【问题标题】:Call back to main thread from a Task从任务回调主线程
【发布时间】:2013-05-20 20:13:19
【问题描述】:

由于我不太了解线程,所以我有一个问题。 我想在后台做一些事情,在后台方法中我想在某些条件下切换回主线程,否则在后台工作。 我怎样才能实现这个功能?我正在使用从 UI 类(c#)调用 StartSyncThread

async void StartSyncThread()
{
    await DoSyncAsync();
}

Task DoSyncAsync()
{
    return Task.Run(() => DoSync());            
}

在 DoSync 方法中,我想切换回主线程,以便更改 UI。 请给我一个简单的解决方案来做到这一点。提前致谢!

【问题讨论】:

标签: c# windows-phone-8 windows-phone


【解决方案1】:

有几种方法。

首先是将同步方法拆分为不同的部分。如果您的同步方法计算进入 UI 不同部分的不同类型的事物,这是最好的:

async Task DoSyncAsync()
{
  myDataBoundUIProperty1 = await Task.Run(() => DoSync1());
  myDataBoundUIProperty2 = await Task.Run(() => DoSync2());
}

第二个是使用进度报告。如果您的 UI 更新都是同一类型,这是最好的:

Task DoSyncAsync()
{
  Progress<MyProgressType> progress = new Progress<MyProgressType>(progressUpdate =>
  {
    myDataBoundUIProperty = progressUpdate;
  });
  return Task.Run(() => DoSync(progress));
}
void DoSync(IProgress<MyProgressType> progress)
{
  ...
  if (progress != null)
    progress.Report(new MyProgressType(...));
  ...
}

还有最后一种选择,但我强烈推荐以上两种选择之一。上述两种解决方案将带来更好的代码设计(关注点分离)。第三种选择是传入一个TaskFactory,它可用于在 UI 上下文中运行任意代码:

Task DoSyncAsync()
{
  var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
  var factory = new TaskFactory(scheduler);
  return Task.Run(() => DoSync(factory));
}
void DoSync(TaskFactory factory)
{
  ...
  scheduler.StartNew(() => { ... });
  ...
}

同样,我不建议使用最后一种解决方案,因为它会将您的 UI 更新逻辑与您的后台任务逻辑混为一谈。但比直接使用DispatcherControl要好。

【讨论】:

    【解决方案2】:

    首先启动您的异步进程,然后调用 Dispatcher.BeginInvoke 以返回 UI 线程。

    Task.StartNew(() =>
    {
       // Do Something Async
    
       Dispatcher.BeginInvoke(() =>
       {
          // Update Your UI Here 
       });
    });
    

    请注意,Dispatcher 不是静态的 - 这依赖于您的代码是 UI 对象的成员函数的一部分,就像页面对象上的方法一样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多