2013-05-25 2 views
9

Da ich nicht über Threads weiß, habe ich eine Frage. Ich möchte etwas im Hintergrund und im Hintergrund Methode Ich möchte zurück auf den Haupt-Thread auf bestimmten Bedingungen ändern, ansonsten im Hintergrund arbeiten. Wie kann ich diese Funktionalität erreichen? Ich einen Anruf zu StartSyncThread aus UI-Klasse (C#)Rückruf zum Hauptthread von einer Aufgabe

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

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

in DoSync Methode I zur Haupt-Thread wechseln möchte, so dass i UI ändern kann. Bitte geben Sie mir eine einfache Lösung, dies zu tun. Danke im Voraus!

+0

Überprüfen Sie 'Control.Invoke (()' oder diesen Thread: http://stackoverflow.com/questions/4331262/task-continuation-on-ui-thread –

Antwort

6

Starten Sie zunächst Ihren Async-Prozess und rufen Sie dann Dispatcher.BeginInvoke auf, um den UI-Thread wiederherzustellen.

Task.StartNew(() => 
{ 
    // Do Something Async 

    Dispatcher.BeginInvoke(() => 
    { 
     // Update Your UI Here 
    }); 
}); 

Beachten Sie, dass Dispatcher nicht statisch ist - dies auf Ihren Code verlässt sich für ein UI-Objekt ein Teil einer Elementfunktion sein, wie ein Verfahren auf der Seite Objekt.

8

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.