Aktualisierung von hintergrund-Arbeiter async-await
So ist dies, wie ich derzeit mit hintergrund-Arbeiter zu retten, eine Menge Zeug, um die Datei während der Präsentation der user mit einer Fortschrittsanzeige und verhindert jegliche änderungen an der Benutzeroberfläche beim speichern ist in Arbeit. Ich denke, ich habe erobert die wesentlichen Merkmale. Der modal ProgressWindow
zeigt einen Fortschrittsbalken und sonst nicht viel. Wie würde ich mich über eine änderung dieses zu async-await
Muster, wenn ich musste?
private ProgressForm ProgressWindow { get; set; }
///<summary>On clicking save button, save stuff to file</summary>
void SaveButtonClick(object sender, EventArgs e)
{
if (SaveFileDialog.ShowDialog() == DialogResult.OK)
{
if (!BackgroundWorker.IsBusy)
{
BackgroundWorker.RunWorkerAsync(SaveFileDialog.FileName);
ProgressWindow= new ProgressForm();
ProgressWindow.SetPercentageDone(0);
ProgressWindow.ShowDialog(this);
}
}
}
///<summary>Background worker task to save stuff to file</summary>
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
string path= e.Argument as string;
//open file
for (int i=0; i < 100; i++)
{
//get some stuff from UI
//save stuff to file
BackgroundWorker.ReportProgress(i);
}
//close file
}
///<summary>On background worker progress, report progress</summary>
void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
ProgressWindow.SetPercentageDone(e.ProgressPercentage);
}
///<summary>On background worker finished, close progress form</summary>
void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ProgressWindow.Close();
}
- Gut, beginnen Sie mit der Entfernung Ihres backgroundworker, dann prüfen Sie diese Seite. Await-Async
- Fortschritt melden mit async verwenden Sie
IProgress<T>
. Siehe hier für mehr info. - Mein problem ist, dass es scheint nicht, um irgendetwas für mich zu
await
- Wenn Sie
File
Klasse statische Methoden, es gibt nichts zu erwarten. Aber beachten Sie, dass alle Datei-stream-Verwandte Methoden haben Ihre asynchronen Versionen, die kannst du natürlich erwarten. Müssen nur die Art und Weise ändern Sie die Programm-Operationen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich habe eine blog-Serie, deckt diese im detail.
Kurz
BackgroundWorker
wird ersetzt durchTask.Run
, undReportProgress
(und Freunde) wird ersetzt durchIProgress<T>
.So, eine direkte übersetzung würde wie folgt Aussehen:
Hinweise für Verbesserungen:
//get some stuff from UI
). Es würde wahrscheinlich besser funktionieren, wenn könnten Sie sammeln alle Informationen aus dem UI - vor aufrufenTask.Run
und übergeben Sie es in dieSave
Methode.ProgressWindow.ShowDialog(this);
wird nicht geben Ihnen eine chance zuawait task
und das Dialogfeld zu schließen.SaveAndClose
richtig handles schließenProgressWindow
innerhalbProgressWindow.ShowDialog
(Mann, ich hasse verschachtelte message-loops!). Ich bin immer noch skeptisch über das Lesen der UI-Werte aus einem hintergrund-thread; vor allem, da I/O ist im Allgemeinen viel, viel langsamer als in-memory-Operationen.Task.Factory.StartNew
undInvoke
Zeug zu bekommen, die von der Benutzeroberfläche aus. Die hintergrund-worker-pattern noch spielt es für mich aber. Vielleicht ist es genau das, was ich gewohnt bin!Ich denke, der Grund, warum Sie zulassen, dass ein anderer thread tun, das zeitraubende Zeug ist, weil Sie wollen, dass das user interface reagiert. Ihre Methode wird diese Anforderung erfüllt.
Den Vorteil der Verwendung von async-await, dass der code Aussehen wird mehr synchron, während das user-interface scheint zu reagieren. Sie don ' T haben, mit zu arbeiten Ereignisse und Funktionen wie die Kontrolle.IsInvokeRequired, denn es ist der Haupt-thread, der die Arbeit machen.
Den Nachteil, async-await, dass, solange der Haupt-thread ist wirklich etwas tun (= nicht warten auf eine Aufgabe zu beenden), die Benutzeroberfläche ist nicht ansprechbar.
Gesagt haben, dass, was eine Funktion async ist einfach:
So machen Sie Ihre Funktion async:
Den async-SaveFile-Funktion ist einfach:
Den SaveButtonClick async ist auch einfach. Weil alle mein Kommentar scheint es eine Menge code, aber in der Tat ist es eine kleine Funktion.
Beachten Sie, dass die Funktion einen Ereignis-handler: void zurück anstelle von Task
Dem der Vorgang ausgeführt, sobald ein thread im thread-pool ist für Sie kostenfrei.
Inzwischen ist der Haupt-thread hat Zeit für andere Dinge, wie zeigen, und aktualisieren Sie das Fenster.
Nun wiederholt, warten Sie eine Sekunde und stellen Fortschritte. Stoppen Sie, sobald das saveFileTask Aufgabe abgeschlossen ist.
Können wir nicht einfach lassen Sie der main-thread warten, bis die Aufgabe fertig zu stellen, denn das würde aufhören, UI, flexibel, neben der Haupt-thread sollte immer wieder aktualisieren der progressbar.
Lösung: verwenden Sie nicht die Aufgabe.Funktion warten, aber die Aufgabe.Wenn Funktionen. Der Unterschied ist, dass Aufgabe.Wenn Funktionen zurück erwartbaren Aufgaben, und so können Sie erwarten, für die Aufgabe zu beenden, so daß die UI reagiert.
Aufgabe.Wenn funcitons nicht eine version. HIERFÜR starten wir eine Aufgabe.Verzögerung
Aufgabe.WhenAny Stoppt, sobald die fileSaveTask abgeschlossen ist, oder wenn die Verzögerung Aufgabe abgeschlossen ist.
Dinge zu tun: reagieren auf Fehler, wenn fileSave trifft auf Probleme. Sollten Sie Rückgabe einem Task < TResult > anstelle von Task.
oder werfen eine Ausnahme. Das Hauptfenster thread fängt diese als eine AggregateException. Die InnerExceptions (plural) enthalten die Ausnahmen von der Aufgaben.
Wenn Sie brauchen, um in der Lage zu stoppen den Prozess des Speicherns, die Sie brauchen, um passieren eine CacellationToken zu jeder Funktion und lassen Sie die SaveFile
WriteAsync
scheint nicht nützlich für mich.Stephen Cleary Antwort im Grunde deckt den Fall ab. Aber es ist eine Komplikation, die durch die Sperrung
ShowDialog
nennen, die verhindert, dass die normaleasync/await
fließen.Also zusätzlich zu seiner Antwort, die ich würde vorschlagen, dass Sie die folgenden Allgemeinen Hilfsfunktion
Dann entfernen Sie die
ProgressWindow
form Mitglied und nutzen Sie die folgendenBeachten Sie, dass ich ' ve markiert die eigentliche worker-Methode
static
, um zu verhindern, dass der Zugriff auf das Formular (und alle UI-Elemente) innen und arbeiten nur mit den übergebenen Argumenten.