2012-09-24 43 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