Exemplarische Vorgehensweise: Multithreading mit der BackgroundWorker-Komponente (C#)Walkthrough: Multithreading with the BackgroundWorker Component (C#)

In dieser exemplarischen Vorgehensweise wird veranschaulicht, wie man eine Windows Forms-Multithreadanwendung erstellt, die in einer Textdatei nach dem Vorkommen eines Worts sucht.This walkthrough demonstrates how to create a multithreaded Windows Forms application that searches a text file for occurrences of a word. Folgendes wird veranschaulicht:It demonstrates:

So erstellen Sie die BenutzeroberflächeTo create the user interface

  1. Öffnen Sie ein neues Anwendungsprojekt von C# Windows Forms, und erstellen Sie ein Formular mit dem Namen Form1.Open a new C# Windows Forms Application project, and create a form named Form1.

  2. Fügen Sie zwei Schaltflächen und vier Textfelder zu Form1 hinzu.Add two buttons and four text boxes to Form1.

  3. Benennen Sie die Objekte wie in der folgenden Tabelle gezeigt.Name the objects as shown in the following table.

    ObjektObject EigenschaftProperty EinstellungSetting
    Erste SchaltflächeFirst button Name, TextName, Text Start, StartStart, Start
    Zweite SchaltflächeSecond button Name, TextName, Text Abbrechen, AbbrechenCancel, Cancel
    Erstes TextfeldFirst text box Name, TextName, Text SourceFile, ""SourceFile, ""
    Zweites TextfeldSecond text box Name, TextName, Text CompareString, „“CompareString, ""
    Drittes TextfeldThird text box Name, TextName, Text WordsCounted, „0“WordsCounted, "0"
    Viertes TextfeldFourth text box Name, TextName, Text LinesCounted, "0"LinesCounted, "0"
  4. Fügen Sie neben jedem Textfeld eine Bezeichnung hinzu.Add a label next to each text box. Legen Sie die Eigenschaft Text für jede Bezeichnung fest wie in der folgenden Tabelle gezeigt.Set the Text property for each label as shown in the following table.

    ObjektObject EigenschaftProperty EinstellungSetting
    Erste BezeichnungFirst label Text QuelldateiSource File
    Zweite BezeichnungSecond label Text Zeichenfolge vergleichenCompare String
    Dritte BezeichnungThird label Text Abgleich von WörternMatching Words
    Vierte BezeichnungFourth label Text Gezählte ZeilenLines Counted

So erstellen Sie eine BackgroundWorker-Komponente und abonnieren deren EreignisseTo create a BackgroundWorker component and subscribe to its events

  1. Fügen Sie dem Formular über den Abschnitt Komponenten im Werkzeugkasten eine BackgroundWorker-Komponente hinzu.Add a BackgroundWorker component from the Components section of the ToolBox to the form. Sie wird in der Komponentenleiste des Formulars angezeigt.It will appear in the form's component tray.

  2. Legen Sie die folgenden Eigenschaften für das Objekt „backgroundWorker1“ fest.Set the following properties for the backgroundWorker1 object.

    EigenschaftProperty EinstellungSetting
    WorkerReportsProgress TrueTrue
    WorkerSupportsCancellation TrueTrue
  3. Abonnieren Sie die Ereignisse des Objekts „backgroundWorker1“.Subscribe to the events of the backgroundWorker1 object. Klicken Sie oben im Fenster Eigenschaften auf das Symbol Ereignisse.At the top of the Properties window, click the Events icon. Doppelklicken Sie auf das Ereignis RunWorkerCompleted, um eine Ereignishandlermethode zu erstellen.Double-click the RunWorkerCompleted event to create an event handler method. Führen Sie das gleiche für die Ereignisse ProgressChanged und DoWork durch.Do the same for the ProgressChanged and DoWork events.

So definieren Sie die Methode, die in einem separaten Thread ausgeführt wirdTo define the method that will run on a separate thread

  1. Wählen Sie im Menü Projekt Klasse hinzufügen aus, um eine Klasse zum Projekt hinzuzufügen.From the Project menu, choose Add Class to add a class to the project. Das Dialogfeld Neues Element hinzufügen wird angezeigt.The Add New Item dialog box is displayed.

  2. Wählen Sie Klasse aus dem Fenster „Vorlagen“ aus, und geben Sie Words.cs in das Namensfeld ein.Select Class from the templates window and enter Words.cs in the name field.

  3. Klicken Sie auf Hinzufügen.Click Add. Die Words-Klasse wird angezeigt.The Words class is displayed.

  4. Fügen Sie der Words -Klasse folgenden Code hinzu:Add the following code to the Words class:

    public class Words  
    {  
        // Object to store the current state, for passing to the caller.  
        public class CurrentState  
        {  
            public int LinesCounted;  
            public int WordsMatched;  
        }  
    
        public string SourceFile;  
        public string CompareString;  
        private int WordCount;  
        private int LinesCounted;  
    
        public void CountWords(  
            System.ComponentModel.BackgroundWorker worker,  
            System.ComponentModel.DoWorkEventArgs e)  
        {  
            // Initialize the variables.  
            CurrentState state = new CurrentState();  
            string line = "";  
            int elapsedTime = 20;  
            DateTime lastReportDateTime = DateTime.Now;  
    
            if (CompareString == null ||  
                CompareString == System.String.Empty)  
            {  
                throw new Exception("CompareString not specified.");  
            }  
    
            // Open a new stream.  
            using (System.IO.StreamReader myStream = new System.IO.StreamReader(SourceFile))  
            {  
                // Process lines while there are lines remaining in the file.  
                while (!myStream.EndOfStream)  
                {  
                    if (worker.CancellationPending)  
                    {  
                        e.Cancel = true;  
                        break;  
                    }  
                    else  
                    {  
                        line = myStream.ReadLine();  
                        WordCount += CountInString(line, CompareString);  
                        LinesCounted += 1;  
    
                        // Raise an event so the form can monitor progress.  
                        int compare = DateTime.Compare(  
                            DateTime.Now, lastReportDateTime.AddMilliseconds(elapsedTime));  
                        if (compare > 0)  
                        {  
                            state.LinesCounted = LinesCounted;  
                            state.WordsMatched = WordCount;  
                            worker.ReportProgress(0, state);  
                            lastReportDateTime = DateTime.Now;  
                        }  
                    }  
                    // Uncomment for testing.  
                    //System.Threading.Thread.Sleep(5);  
                }  
    
                // Report the final count values.  
                state.LinesCounted = LinesCounted;  
                state.WordsMatched = WordCount;  
                worker.ReportProgress(0, state);  
            }  
        }  
    
        private int CountInString(  
            string SourceString,  
            string CompareString)  
        {  
            // This function counts the number of times  
            // a word is found in a line.  
            if (SourceString == null)  
            {  
                return 0;  
            }  
    
            string EscapedCompareString =  
                System.Text.RegularExpressions.Regex.Escape(CompareString);  
    
            System.Text.RegularExpressions.Regex regex;  
            regex = new System.Text.RegularExpressions.Regex(   
                // To count all occurrences of the string, even within words, remove  
                // both instances of @"\b" from the following line.  
                @"\b" + EscapedCompareString + @"\b",  
                System.Text.RegularExpressions.RegexOptions.IgnoreCase);  
    
            System.Text.RegularExpressions.MatchCollection matches;  
            matches = regex.Matches(SourceString);  
            return matches.Count;  
        }  
    
    }  
    

So behandeln Sie Ereignisse aus dem ThreadTo handle events from the thread

  • Fügen Sie dem Hauptformular die folgenden Ereignishandler hinzu:Add the following event handlers to your main form:

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
    {  
    // This event handler is called when the background thread finishes.  
    // This method runs on the main thread.  
    if (e.Error != null)  
        MessageBox.Show("Error: " + e.Error.Message);  
    else if (e.Cancelled)  
        MessageBox.Show("Word counting canceled.");  
    else  
        MessageBox.Show("Finished counting words.");  
    }  
    
    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)  
    {  
        // This method runs on the main thread.  
        Words.CurrentState state =  
            (Words.CurrentState)e.UserState;  
        this.LinesCounted.Text = state.LinesCounted.ToString();  
        this.WordsCounted.Text = state.WordsMatched.ToString();  
    }  
    

So starten und rufen Sie einen neuen Thread auf, der die WordCount-Methode ausführtTo start and call a new thread that runs the WordCount method

  1. Fügen Sie dem Programm die folgenden Verfahren hinzu:Add the following procedures to your program:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)  
    {  
        // This event handler is where the actual work is done.  
        // This method runs on the background thread.  
    
        // Get the BackgroundWorker object that raised this event.  
        System.ComponentModel.BackgroundWorker worker;  
        worker = (System.ComponentModel.BackgroundWorker)sender;  
    
        // Get the Words object and call the main method.  
        Words WC = (Words)e.Argument;  
        WC.CountWords(worker, e);  
    }  
    
    private void StartThread()  
    {  
        // This method runs on the main thread.  
        this.WordsCounted.Text = "0";  
    
        // Initialize the object that the background worker calls.  
        Words WC = new Words();  
        WC.CompareString = this.CompareString.Text;  
        WC.SourceFile = this.SourceFile.Text;  
    
        // Start the asynchronous operation.  
        backgroundWorker1.RunWorkerAsync(WC);  
    }  
    
  2. Rufen Sie die StartThread-Methode über die Start-Schaltfläche im Formular auf:Call the StartThread method from the Start button on your form:

    private void Start_Click(object sender, EventArgs e)  
    {  
        StartThread();  
    }  
    
    So implementieren Sie eine Schaltfläche „Abbrechen“, die den Thread beendetTo implement a Cancel button that stops the thread
    • Rufen Sie die Prozedur StopThread aus dem Ereignishandler Click für die Schaltfläche Cancel auf.Call the StopThread procedure from the Click event handler for the Cancel button.

      private void Cancel_Click(object sender, EventArgs e)  
      {  
          // Cancel the asynchronous operation.  
          this.backgroundWorker1.CancelAsync();  
      }  
      

TestTesting

Sie können die Anwendung jetzt testen, um die korrekte Ausführung sicherzustellen.You can now test the application to make sure it works correctly.

So testen Sie die AnwendungTo test the application

  1. Drücken Sie F5, um die Anwendung auszuführen.Press F5 to run the application.

  2. Wenn das Formular angezeigt wird, geben Sie den Dateipfad für die Datei ein, die Sie im Feld sourceFile testen möchten.When the form is displayed, enter the file path for the file you want to test in the sourceFile box. Nehmen wir z.B. an, dass Ihre Testdatei den Namen „Test.txt“ hat; geben Sie „C:\Test.txt“ ein.For example, assuming your test file is named Test.txt, enter C:\Test.txt.

  3. Geben Sie im zweiten Textfeld ein Wort oder einen Satz für die Anwendung ein, nach der Sie im Textfeld suchen möchten.In the second text box, enter a word or phrase for the application to search for in the text file.

  4. Klicken Sie auf die Schaltfläche Start.Click the Start button. Die Schaltfläche LinesCounted sollte sofort mit dem Inkrementieren beginnen.The LinesCounted button should begin incrementing immediately. Die Anwendung zeigt die Benachrichtigung „Finished Counting“ (Berechnung abgeschlossen) an, wenn der Vorgang abgeschlossen ist.The application displays the message "Finished Counting" when it is done.

So testen Sie die Schaltfläche „Abbrechen“To test the Cancel button

  1. Drücken Sie F5, um die Anwendung zu starten, und geben Sie den Dateinamen und das Suchwort ein, wie in der vorherigen Prozedur beschrieben.Press F5 to start the application, and enter the file name and search word as described in the previous procedure. Stellen Sie sicher, dass die von Ihnen ausgewählte Datei groß genug ist, um sicherzustellen, dass Sie Zeit haben, den Vorgang abzubrechen, bevor er abgeschlossen ist.Make sure that the file you choose is large enough to ensure you will have time to cancel the procedure before it is finished.

  2. Klicken Sie auf die Schaltfläche Start, um die Anwendung zu starten.Click the Start button to start the application.

  3. Klicken Sie auf die Schaltfläche Cancel.Click the Cancel button. Die Anwendung sollte den Zählvorgang sofort beenden.The application should stop counting immediately.

Nächste SchritteNext Steps

Diese Anwendung enthält eine grundlegende Fehlerbehandlung.This application contains some basic error handling. Sie erkennt leere Suchbegriffe.It detects blank search strings. Sie können dieses Programm stabiler machen, indem Sie andere Fehler behandeln, z.B. das Überschreiten der maximalen Anzahl von Wörtern oder Linien, die gezählt werden können.You can make this program more robust by handling other errors, such as exceeding the maximum number of words or lines that can be counted.

Siehe auchSee Also

Threading (C#)Threading (C#)
Gewusst wie: Abonnieren von Ereignissen und Kündigen von EreignisabonnementsHow to: Subscribe to and Unsubscribe from Events