2012-09-24 31 views
1

问题:当我想呈现异步检索的传入数据时,我崩溃了。Metro C++异步编程和UI更新。我的技术?

该应用程序启动并使用XAML显示一些对话框。一旦用户填写了他们的数据并点击了登录按钮,XAML类就拥有了一个为我执行HTTP内容的工作类实例(异步使用IXMLHTTPRequest2)。当应用程序成功登录到Web服务器时,我的.then()块会触发,并且会对我的主要xaml类进行回调以执行资源渲染。

尽管(主XAML类)我总是在代理中发生崩溃,这导致我相信我不能使用这种方法(纯虚类和回调函数)来更新我的UI。我认为我无意中尝试从异步调用的副产品不正确的线程中进行非法操作。

有没有更好或不同的方式,我应该通知主XAML类,它是时候更新它的UI了?我来自iOS世界,我可以使用NotificationCenter。

现在,我看到了微软的东西在这里它自己的委托类型:http://msdn.microsoft.com/en-us/library/windows/apps/hh755798.aspx

你想,如果我用这种方法不是我自己的回调,这将不再崩溃?

让我知道你是否需要更多的澄清或不。

这里是代码的JIST: 公共接口类ISmileServiceEvents { 公共://所需的方法 虚拟无效UpdateUI(布尔的isValid)抽象; };

// In main XAML.cpp which inherits from an ISmileServiceEvents 
void buttonClick(...){ 
    _myUser->LoginAndGetAssets(txtEmail->Text, txtPass->Password); 
} 
void UpdateUI(String^ data) // implements ISmileServiceEvents 
{ 
    // This is where I would render my assets if I could. 
    // Cannot legally do much here. Always crashes. 
    // Follow the rest of the code to get here. 
} 

// In MyUser.cpp 
void LoginAndGetAssets(String^ email, String^ password){ 
    Uri^ uri = ref new URI(MY_SERVER + "login.json"); 
    String^ inJSON = "some json input data here"; // serialized email and password with other data 

    // make the HTTP request to login, then notify XAML that it has data to render. 
    _myService->HTTPPostAsync(uri, json).then([](String^ outputJson){ 
     String^ assets = MyParser::Parse(outputJSON); 
     // The Login has returned and we have our json output data 
     if(_delegate) 
     { 
     _delegate->UpdateUI(assets); 
     } 
    }); 
} 

// In MyService.cpp 
task<String^> MyService::HTTPPostAsync(Uri^ uri, String^ json) 
{ 
    return _httpRequest.PostAsync(uri, 
     json->Data(), 
     _cancellationTokenSource.get_token()).then([this](task<std::wstring> response) 
    { 
     try 
     { 
      if(_httpRequest.GetStatusCode() != 200) SM_LOG_WARNING("Status code=", _httpRequest.GetStatusCode()); 
       String^ j = ref new String(response.get().c_str()); 
       return j; 
     } 
     catch (Exception^ ex) .......; 
    return ref new String(L""); 
    }, task_continuation_context::use_current()); 
} 

编辑:BTW,当我去更新UI我得到的错误是: “一个无效参数传递给确认为无效参数致命的函数” 在这种情况下,我只是想在我的回调执行是

txtBox->Text = data; 

回答

0

看样子你是从错误的上下文更新UI线程。您可以使用task_continuation_context::use_arbitrary()来允许您更新UI。请参阅this document中的“控制执行线程”示例(关于编组的讨论位于底部)。

+0

感谢您的链接。我读完了,说什么与你的建议相矛盾。从文章: “ 使用并发:: task_continuation_context :: use_arbitrary指定延续在后台线程运行 使用并发:: task_continuation_context :: use_current指定延续调用任务的线程上运行: :然后 “ – VaporwareWolf

+0

无论哪种方式,我试图改变任意()和删除use_current()。两人都没有帮助解决问题。 – VaporwareWolf

0

所以,事实证明,当你有一个延续时,如果你没有在lambda函数后面指定一个上下文,那么它默认使用use_arbitrary()。这与我在MS视频中学到的内容相矛盾。

但是,通过将use_currrent()添加到与GUI有任何关系的所有.then块中,我的错误消失了,所有内容都能正确呈现。

我的GUI调用一个服务,该服务生成一些任务,然后调用一个不同步的HTTP类。回到HTTP类我使用use_arbitrary(),以便它可以在辅助线程上运行。这工作正常。只要确保在任何与GUI有关的事情上使用use_current()。

既然你有我的答案,如果你看看原来的代码,你会看到它已经包含use_current()。这是真的,但为了简化示例,我省略了包装功能。这是我需要添加use_current()的地方。

+0

在哪个视频中说延续会被编组回到原始线程? –

+0

这是视频。实际上这很不错。 http://channel9.msdn.com/Events/Windows-Camp/Developing-Windows-8-Metro-style-apps-in-Cpp/Async-made-simple-with-Cpp-PPL – VaporwareWolf