2012-03-02 187 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