[英]Call back to main thread from a Task
由於我不了解線程,所以我有一個問題。 我想在背景和背景方法中做一些事情我想在某些條件下切換回主線程,否則在后台工作。 我該如何實現這一功能? 我正在使用UI類中的StartSyncThread調用(c#)
async void StartSyncThread()
{
await DoSyncAsync();
}
Task DoSyncAsync()
{
return Task.Run(() => DoSync());
}
在DoSync方法中,我想切換回主線程,以便我可以更改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(...));
...
}
有一個最后的選擇,但我強烈推薦上述兩個中的一個。 上述兩種解決方案將帶來更好的代碼設計(關注點分離)。 第三種方法是傳入一個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
更好。
首先啟動異步過程,然后調用Dispatcher.BeginInvoke以返回UI線程。
Task.StartNew(() =>
{
// Do Something Async
Dispatcher.BeginInvoke(() =>
{
// Update Your UI Here
});
});
請注意,Dispatcher不是靜態的 - 這依賴於您的代碼是UI對象的成員函數的一部分,就像頁面對象上的方法一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.