Es gibt ein paar Ansätze.
Die erste besteht darin, die synchrone Methode in verschiedene Teile aufzuteilen. Dies ist am besten, wenn Ihre synchrone Methode verschiedene Arten von Dingen berechnet, das in verschiedene Teile der Benutzeroberfläche gehen:
async Task DoSyncAsync()
{
myDataBoundUIProperty1 = await Task.Run(() => DoSync1());
myDataBoundUIProperty2 = await Task.Run(() => DoSync2());
}
Der zweite ist ein Fortschritt Berichterstattung zu verwenden. Dies ist am besten, wenn Sie Ihre UI-Updates alle vom gleichen Typ sind:
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(...));
...
}
Es gibt eine letzte Alternative, aber ich einer der beiden oben sehr empfehlen. Die beiden obigen Lösungen werden zu einem besseren Code-Design (Trennung der Bedenken) führen. Die dritte Alternative ist in einem TaskFactory
passieren, das verwendet werden kann, beliebigen Code auf dem UI-Kontext auszuführen:
Task DoSyncAsync()
{
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
var factory = new TaskFactory(scheduler);
return Task.Run(() => DoSync(factory));
}
void DoSync(TaskFactory factory)
{
...
scheduler.StartNew(() => { ... });
...
}
Auch ich diese letzte Lösung nicht raten, da sie Ihre UI Update-Logik mit dem Hintergrund verschmilzt Aufgabe Logik. Aber es ist besser, als direkt Dispatcher
oder Control
zu verwenden.
Überprüfen Sie 'Control.Invoke (()' oder diesen Thread: http://stackoverflow.com/questions/4331262/task-continuation-on-ui-thread –