65.9K
CodeProject 正在变化。 阅读更多。
Home

如何摆脱 Dispatcher.Invoke

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (7投票s)

2013年12月6日

CPOL
viewsIcon

24724

downloadIcon

201

使用 Task 切换上下文

引言

在使用 Dispatcher 在线程之间切换上下文时遇到困难后,我很高兴能够通过使用 Task 来传达以下解决方案。  

使用代码

我将任务包装在一个接受 Action 的执行方法中。  

//
// private method to switch context.
//
private void Execute(Action action)
{
  try
  {
    // Invoke action on UI thread
    var task = Task.Factory.StartNew(() =>
               {
                 if (action != null)
                    action();
               }, CancellationToken.None, TaskCreationOptions.None, taskScheduler);
    if (task.IsFaulted)
      throw new AggregateException(task.Exception);
  }
  catch (Exception e)
  {
    if (Debugger.IsAttached) Debugger.Break();
    // Handle exception here.
  }
} 

要使用该方法,需要在 UI 线程内设置任务调度器,并且必须设置 SynchronizationContext。 

// Must be set on the UI thread
taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();  
// Example 
// Invoke event LogonStatusChanged on the UI thread.
private void InvokeLoginStatusChanged(Object sender, EventArgs e)
{
  if (LogonStatusChanged == null) return;
  Execute(() => LogonStatusChanged(this, e));
}  

关注点

当涉及到单元测试时,使用 Task 在线程之间切换上下文会很棘手。 在这些情况下,您可以使用以下代码创建自己的同步上下文。

// Creating you own Synchronization context
[TestInitialize]
private void TestSetup()
{
  SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
}  


请注意,同步上下文在应用程序启动时不会立即创建。
如果在 App.cs 构造函数中引用 TaskScheduler.FromCurrentSynchronizationContext(),它将始终为 null。 

相反,将任何初始化移动到 OnStartup。 

protected override void OnStartup(StartupEventArgs e)
{
  // Initialize here
  base.OnStartup(e);
}  

历史 

2013-12-6:初始版本。  
2013-12-8:添加了一个示例。



© . All rights reserved.