有几种方法。
首先是将同步方法拆分为不同的部分。如果您的同步方法计算进入 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 更新逻辑与您的后台任务逻辑混为一谈。但它比使用Dispatcher
或Control
直接更好。