由于我对线程不太了解,所以我有一个问题。 我想在后台做一些事情,在后台方法中我想在某些条件下切换回主线程,否则在后台工作。 我怎样才能实现这个功能?我正在使用从 UI 类 (c#) 调用 StartSyncThread
async void StartSyncThread()
{
await DoSyncAsync();
}
Task DoSyncAsync()
{
return Task.Run(() => DoSync());
}
在 DoSync 方法中,我想切换回主线程,以便可以更改 UI。 请给我一个简单的解决方案来做到这一点。预先感谢!
首先启动异步进程,然后调用 Dispatcher.BeginInvoke 返回 UI 线程。
Task.StartNew(() =>
{
// Do Something Async
Dispatcher.BeginInvoke(() =>
{
// Update Your UI Here
});
});
请注意,Dispatcher 不是静态的 - 这依赖于您的代码是 UI 对象的成员函数的一部分,就像页面对象上的方法一样。
有几种方法。
首先是将同步方法分成不同的部分。如果您的同步方法计算进入 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(...));
...
}
还有最后一个选择,但我强烈推荐上述两个之一。上述两种解决方案将带来更好的代码设计(关注点分离)。第三种选择是传入一个可用于在 UI 上下文上运行任意代码的
TaskFactory
:
Task DoSyncAsync()
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
var factory = new TaskFactory(scheduler);
return Task.Run(() => DoSync(factory));
}
void DoSync(TaskFactory factory)
{
...
factory.StartNew(() => { ... });
...
}
再次强调,我不建议最后一个解决方案,因为它将您的 UI 更新逻辑与后台任务逻辑混为一谈。但比直接使用
Dispatcher
或 Control
更好。