BackgroundWorker - Hintergrund-Threads in VS 2005

Einleitung

Zu weilen führt man über Oberflächen länger andauernde Aktionen aus, wie z.B. das Konvertieren von Daten oder ein Download aus dem Web. Eine solche Aktion startet man am besten in einem Hintergrund-Thread, um die Oberfläche während dessen nicht für Rückmeldungen oder weitere Aktionen des Anwenders zu blockieren.

Motivation

Bei der Umsetzung lang andauernder Funktionen stößt man zumeist auf folgendes Schema:

· Es wird eine „Work“-Methode erstellt,

· diese Methode ruft man über einen erstellten Thread auf.

· Aktionen auf der Oberfläche werden über „BeginInvoke“ ausgeführt.

· Es gibt eine Möglichkeit, den Thread zu beenden.

Um dieses Schema nicht in jedem Dialog neu zu Programmieren, stellte Microsoft in VisualStudio 2005 den BackgroundWorker zur Verfügung. Lesen Sie im Folgenden, wie man den BackgroundWorker bei der Anwendungsentwicklung nutzen kann.

BachgroundWorker in VS 2005

Der BackgroundWorker dient der einfachen Erstellung von Hintergrund-Threads und steht in VisualStudio 2005 als Komponente zur Auswahl:



Die Komponente fügt man per Drag & Drop dem Dialog hinzu. Über den Eigenschaftendialog der Events lässt sich die im Hintergrund auszuführende Methode definieren:



Die dem Event „DoWork“ zugewiesene Methode wird später beim asynchronen Aufruf ausgeführt. In dieser Methode werden die Funktionen ausgeführt, die etwas länger dauern und deshalb parallel laufen sollen. Wie z.B. das Konvertieren von Daten, das Laden von Daten aus dem Web, etc. In der Methode darf jedoch auf keinen Fall auf Elemente der Oberfläche zugegriffen werden (s.u., unter Tipps). In der Beispielanwendung finden Sie folgenden einfachen Code in der DoWork-Methode:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)

{

for (int i = 0; i < 100; i++){

backgroundWorker.ReportProgress(i);

System.Threading.Thread.Sleep(100);

if (true == backgroundWorker.CancellationPending){

return;

}

}

}

Die Methode führt keine weiteren Aktionen aus. Die „Arbeit“ wird durch das Warten über die Operation „Sleep(100)“ simuliert. In dem Code sind daneben die relevanten Interaktionen mit der Instanz des BackgroundWorkers zu sehen:

ReportProgress: Über die Methode „backgroundWorker.ReportProgress” können Sie während der Abarbeitung des Hintergrund-Threads auf Dialogelemente zugreifen, um z.B. den Fortschritt der Abarbeitung anzuzeigen. Mit dem Aufruf dieser Methode wird das Event ProgressChanged geworfen und die dem Event zugewiesene Methode dann im Thread der Oberfläche ausgeführt. Doch dazu später.

CancellationPending: Diese Eigenschaft ist „true“, wenn die Ausführung des Hintergrund-Threads von außen abgebrochen wurde.

Um den Fortschritt der Hintergrundaktion auf der Oberfläche zu protokollieren oder auch andere Oberflächeninteraktionen zu tätigen, muss man das Event „ProgressChanged“ verwenden. Auf keinen Fall darf man direkt auf Oberflächenelemente in der „DoWork“-Methode zugreifen! Definiert wird die Methode zu dem Event über die Event-Eigenschaften des Controls, z.B.:



Außer dem „ProgressChanged"-Event wurde auch gleich das Beenden-Event definiert: „RunWorkerCompleted". Diese beiden Events müssen über die Eigenschaften des BackgroundWorker noch explizit aktiviert werden:



Vergisst man die Eigenschaften „WorkerReportsProgress" bzw. WorkerSupportsCancellation" zu aktivieren (auf True zu setzen), führt die Verwendung der entsprechenden Methoden zu einer Ausnahme.

Damit sind die relevanten Methoden für die Abarbeitung eines Hintergrund-Threads definiert:

  • DoWork, die ausführende Methode,
  • ProgressChanged, zur Anzeige des Status auf der Oberfläche und
  • RunWorkerCompleted, um den Status des Dialogs beim Beenden der Aktion umzusetzen.

Als nächstes muss die Aktion gestartet werden, was einfach mit dem Aufruf RunWorkerAsync auf der Instanz des BackgroundWorkers erfolgt. Z.B. in der Event-Handler-Methode des „Do Work"-Buttons:

 

private void buttonDoWork_Click(object sender, EventArgs e)

{

backgroundWorker.RunWorkerAsync();

}

Anbei finden Sie das Beispiel-Projekt zu der Verwendung des BackgroundWorkers.

 

Im Folgenden noch spezielle Hinweise bzw. Tipps zur Umsetzung von Hintergrund-Threads.

 

 

 

Tip

 

Form_FormClosing

 

Definieren Sie das „Closing-Event“ für den Dialog, um das Schließen des Dialoges während der Ausführung des Hintergrund-Thread zu unterbinden. Der Code dazu könnte wie folgt aussehen:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

if (true == backgroundWorker.IsBusy){

e.Cancel = true;

}

}

Zugriff auf Oberflächenelemente

 

Achten Sie darauf, dass in der „DoWork“-Methode auf keine Oberflächenelemente zugegriffen wird. Unter VS 2003 führte das sporadisch zu nicht reproduzierbaren Fehlern. Meine Erfahrungen mit VS 2005 sind, dass solche Fehler sofort mit einer sprechenden Meldung quittiert werden, z.B. mit der Meldung:

 

Illegal cross-thread operation: Control '' accessed from a thread other than the thread it was created on.

Stack trace where the illegal operation occurred was:

at System.Windows.Forms.Control.get_Handle()

Sie können das im Beispiel-Code testen, in dem Sie den Hinweis mit dem folgenden Kommentar befolgen:

 

// include following to test "Illegal cross-thread operation":

Fazit

Mit dem BackgroundWorker aus VisualStudio 2005 erhält man eine einfache und schlanke Komponente zur Erstellung von Threads, die im Hintergrund einer Oberfläche ablaufen sollen. Die Komponente bietet dem Entwickler den nötigen Rahmen, um Hintergrund-Threads zu managen und unter Berücksichtigung der Thread-Grenzen auf der Oberfläche den nötigen Feedback anzuzeigen.

BackgroundThread.zip
Beispielanwendung zum Artikel


  AGB'S   DISCLAIMER   IMPRESSUM