2012-03-02 85 views
16

由於幾天前發佈了Windows 8消費者預覽版,我正在使用C#中的新WinRT(用於Metro應用程序),並且我已將自己編寫的IRC類移植到新的線程中,聯網。從WinRT中的線程更新UI

問題是:我的班級正在運行一個線程來接收來自服務器的消息。如果發生這種情況,線程正在進行一些解析,然後發起一個事件來通知應用程序。訂閱功能然後'應該'更新UI(文本塊)。

這是問題,線程無法更新UI,並且與.NET 4.0一起使用的調用方法似乎不再可行。有沒有新的解決方法,甚至更好的方式來更新用戶界面?如果我嘗試更新從事件用戶的UI我會得到這個Exception

應用程序調用的是被編組爲 不同的線程的接口(從HRESULT異常:0x8001010E (RPC_E_WRONG_THREAD))

+0

這是由設計。線程消耗電池電量。異步IO的新風格是通過指定延續。 http://channel9.msdn.com上有關於此的一些報道(教程視頻)。 – 2012-03-02 21:03:01

+0

關於第二個想法,可能是BackgroundWorker仍然有效,它更像是一個線程,它也有編組(可以將進度更新發送到UI線程)。 – 2012-03-02 21:04:48

回答

27

處理這種在WinRT中(和C#5在普通)的優選方法是使用async - await

private async void Button_Click(object sender, RoutedEventArgs e) 
{ 
    string text = await Task.Run(() => Compute()); 
    this.TextBlock.Text = text; 
} 

在這裏,Compute()方法將在後臺線程上運行,並且完成後,該方法的其餘部分將在UI線程上執行。與此同時,UI線程可以自由地執行任何需要的操作(如處理其他事件)。

但是,如果你不想或者不能使用async,您可以使用Dispatcher,類似的(儘管不同)的方式在WPF:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Run(() => Compute()); 
} 

private void Compute() 
{ 
    // perform computation here 

    Dispatcher.Invoke(CoreDispatcherPriority.Normal, ShowText, this, resultString); 
} 

private void ShowText(object sender, InvokedHandlerArgs e) 
{ 
    this.TextBlock.Text = (string)e.Context; 
} 
+0

非常感謝你,你的第二個想法已經解決了我的問題,而不用重寫我的全班:),只是用代碼片段替換一些 – Suchiman 2012-03-02 22:14:38

+0

對於第二個示例,我強烈建議使用lambda而不是ShowText方法 - 它允許你要避免「e.Context」。所以調度員。Invoke(CoreDispatcherPriority.Normal,(s,e)=> {this.TextBlock.Text = resultString},this,null); – 2012-03-04 02:44:24

+0

如果代碼不在頁面中怎麼辦?我們如何從BG線程獲得調度員? – Grigory 2012-06-12 14:40:15

8

這裏做一個簡單的方法我想!

首先捕捉你的UI SyncronizationContext下列要求:

var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext(); 

運行服務器調用操作或任何其他後臺線程操作,你需要:

Task serverTask= Task.Run(()=> { /* DoWorkHere(); */}); 

然後做的UISyncContext您的UI操作在第一步中捕獲:

Task uiTask= serverTask.ContinueWith((t)=>{TextBlockName.Text="your value"; }, UISyncContext); 
+1

因此,WINRT的答案是否是「我如何從一些隨機後臺線程獲取UI上下文?」似乎沒有一個簡單的答案,而不是修改所有的接口來傳遞一個UI上下文?如果您的後臺線程對象是從UI線程創建的(因此您可以在構造函數中捕獲UISyncContext),Deeb的上述答案似乎可行。但是如果它不是在UI線程上創建的呢?我錯過了什麼,爲什麼沒有一種腦死的方法來可靠地從任意隨機後臺線程獲取UI上下文? – 2013-02-23 23:08:20

+1

不適用於我。我得到一個InvalidOp異常:'當前的SynchronizationContext不能用作TaskScheduler.'我正在爲Win SDK 8上的MS Surface開發 – Howie 2013-08-21 11:57:28