从WinRT中的线程更新UI
自从几天前发布了Windows 8消费者预览版以来,我正在使用C#开发新的WinRT(针对Metro应用程序),并且已经将我自己编写的IRC类移植到新的线程和网络中。
问题是:我的类正在运行一个线程,用于从服务器接收消息。 如果发生这种情况,该线程正在进行一些解析,然后触发事件以通知应用程序。 然后,订阅的function“应该”更新UI(文本块)。
这是问题,线程无法更新UI,并且似乎不再可能使用.NET 4.0的调用方法。 是否有更新的解决方法,甚至是更新UI的更好方法? 如果我尝试从事件订阅者更新UI,我将得到此Exception
:
该应用程序调用了一个为不同线程编组的接口(来自HRESULT的exception:0x8001010E(RPC_E_WRONG_THREAD))
在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
,您可以使用与WPF中类似(尽管不同)的方式使用Dispatcher
:
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; }
我认为这是一种更简单的方法!
首先使用以下内容捕获UI SyncronizationContext:
var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();
运行您需要的服务器调用操作或任何其他后台线程操作:
Task serverTask= Task.Run(()=> { /* DoWorkHere(); */} );
然后在您在第一步中捕获的UISyncContext上执行UI操作:
Task uiTask= serverTask.ContinueWith((t)=>{TextBlockName.Text="your value"; }, UISyncContext);
IMO我认为“ThreadPool”是推荐的路线。
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh465290.aspx
public static Task InvokeBackground(Func action) { var tcs = new TaskCompletionSource(); var unused = ThreadPool.RunAsync(async (obj) => { await action(); tcs.TrySetResult(true); }); return tcs.Task; }