1

问题:当我想渲染异步检索的传入数据时,我崩溃了。

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

我总是在委托中遇到崩溃(主要的 XAML 类),这让我相信我不能使用这种方法(纯虚拟类和回调)来更新我的 UI。我想我无意中试图从一个不正确的线程做一些非法的事情,这是异步调用的副产品。

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

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

你认为如果我使用这种方法而不是我自己的回调它就不会崩溃了吗?

让我知道您是否需要更多说明。

这是代码的要点: public interface class ISmileServiceEvents { public: // 所需方法 virtual void UpdateUI(bool isValid) abstract; };

// 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());
}

编辑:顺便说一句,我去更新 UI 时得到的错误是:“一个无效参数被传递给一个认为无效参数致命的函数。” 在这种情况下,我只是想在我的回调中执行

txtBox->Text = data;
4

2 回答 2

0

看来您正在从错误的上下文中更新 UI 线程。您可以使用task_continuation_context::use_arbitrary()来允许您更新 UI。请参阅本文档中的“控制执行线程”示例(封送处理的讨论在底部)。

于 2012-09-25T04:36:45.367 回答
0

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

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

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

现在你已经有了我的答案,如果你看一下原始代码,你会发现它已经包含了 use_current()。这是真的,但为了简单起见,我省略了一个包装函数。这就是我需要添加 use_current() 的地方。

于 2012-09-25T19:50:54.530 回答