Walkthrough: Running an Operation in the Background
If you have an operation that will take a long time to complete, and you do not want to cause delays in your user interface, you can use the BackgroundWorker class to run the operation on another thread.
For a complete listing of the code used in this example, see How to: Run an Operation in the Background.
Note
The dialog boxes and menu commands you see might differ from those described in Help depending on your active settings or edition. To change your settings, choose Import and Export Settings on the Tools menu. For more information, see Working with Settings.
To run an operation in the background
With your form active in the Windows Forms Designer, drag two Button controls from the Toolbox to the form, and then set the Name and Text properties of the buttons according to the following table.
Button
Name
Text
button1
startBtn
Start
button2
cancelBtn
Cancel
Open the Toolbox, click the Components tab, and then drag the BackgroundWorker component onto your form.
The backgroundWorker1 component appears in the Component Tray.
In the Properties window, set the WorkerSupportsCancellation property to true.
In the Properties window, click on the Events button, and then double-click the DoWork and RunWorkerCompleted events to create event handlers.
Insert your time-consuming code into the DoWork event handler.
Extract any parameters required by the operation from the Argument property of the DoWorkEventArgs parameter.
Assign the result of the computation to the Result property of the DoWorkEventArgs.
This is will be available to the RunWorkerCompleted event handler.
Private Sub backgroundWorker1_DoWork( _ sender As Object, e As DoWorkEventArgs) _ Handles backgroundWorker1.DoWork ' Do not access the form's BackgroundWorker reference directly. ' Instead, use the reference provided by the sender parameter. Dim bw As BackgroundWorker = CType( sender, BackgroundWorker ) ' Extract the argument. Dim arg As Integer = Fix(e.Argument) ' Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg) ' If the operation was canceled by the user, ' set the DoWorkEventArgs.Cancel property to true. If bw.CancellationPending Then e.Cancel = True End If End Sub
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Do not access the form's BackgroundWorker reference directly. // Instead, use the reference provided by the sender parameter. BackgroundWorker bw = sender as BackgroundWorker; // Extract the argument. int arg = (int)e.Argument; // Start the time-consuming operation. e.Result = TimeConsumingOperation(bw, arg); // If the operation was canceled by the user, // set the DoWorkEventArgs.Cancel property to true. if (bw.CancellationPending) { e.Cancel = true; } }
Insert code for retrieving the result of your operation in the RunWorkerCompleted event handler.
' This event handler demonstrates how to interpret ' the outcome of the asynchronous operation implemented ' in the DoWork event handler. Private Sub backgroundWorker1_RunWorkerCompleted( _ sender As Object, e As RunWorkerCompletedEventArgs) _ Handles backgroundWorker1.RunWorkerCompleted If e.Cancelled Then ' The user canceled the operation. MessageBox.Show("Operation was canceled") ElseIf (e.Error IsNot Nothing) Then ' There was an error during the operation. Dim msg As String = String.Format("An error occurred: {0}", e.Error.Message) MessageBox.Show(msg) Else ' The operation completed normally. Dim msg As String = String.Format("Result = {0}", e.Result) MessageBox.Show(msg) End If End Sub
// This event handler demonstrates how to interpret // the outcome of the asynchronous operation implemented // in the DoWork event handler. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { // The user canceled the operation. MessageBox.Show("Operation was canceled"); } else if (e.Error != null) { // There was an error during the operation. string msg = String.Format("An error occurred: {0}", e.Error.Message); MessageBox.Show(msg); } else { // The operation completed normally. string msg = String.Format("Result = {0}", e.Result); MessageBox.Show(msg); } }
Implement the TimeConsumingOperation method.
' This method models an operation that may take a long time ' to run. It can be cancelled, it can raise an exception, ' or it can exit normally and return a result. These outcomes ' are chosen randomly. Private Function TimeConsumingOperation( _ bw As BackgroundWorker, _ sleepPeriod As Integer) As Integer Dim result As Integer = 0 Dim rand As New Random() While Not bw.CancellationPending Dim [exit] As Boolean = False Select Case rand.Next(3) ' Raise an exception. Case 0 Throw New Exception("An error condition occurred.") Exit While ' Sleep for the number of milliseconds ' specified by the sleepPeriod parameter. Case 1 Thread.Sleep(sleepPeriod) Exit While ' Exit and return normally. Case 2 result = 23 [exit] = True Exit While Case Else Exit While End Select If [exit] Then Exit While End If End While Return result End Function
// This method models an operation that may take a long time // to run. It can be cancelled, it can raise an exception, // or it can exit normally and return a result. These outcomes // are chosen randomly. private int TimeConsumingOperation( BackgroundWorker bw, int sleepPeriod ) { int result = 0; Random rand = new Random(); while (!bw.CancellationPending) { bool exit = false; switch (rand.Next(3)) { // Raise an exception. case 0: { throw new Exception("An error condition occurred."); break; } // Sleep for the number of milliseconds // specified by the sleepPeriod parameter. case 1: { Thread.Sleep(sleepPeriod); break; } // Exit and return normally. case 2: { result = 23; exit = true; break; } default: { break; } } if( exit ) { break; } } return result; }
In the Windows Forms Designer, double-click startButton to create the Click event handler.
Call the RunWorkerAsync method in the Click event handler for startButton.
Private Sub startButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles startBtn.Click Me.backgroundWorker1.RunWorkerAsync(2000) End Sub
private void startBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(2000); }
In the Windows Forms Designer, double-click cancelButton to create the Click event handler.
Call the CancelAsync method in the Click event handler for cancelButton.
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cancelBtn.Click Me.backgroundWorker1.CancelAsync() End Sub
private void cancelBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.CancelAsync(); }
At the top of the file, import the System.ComponentModel and System.Threading namespaces.
Imports System Imports System.ComponentModel Imports System.Drawing Imports System.Threading Imports System.Windows.Forms
using System; using System.ComponentModel; using System.Drawing; using System.Threading; using System.Windows.Forms;
Press F6 to build the solution, and then press CTRL-F5 to run the application outside the debugger.
Note
If you press F5 to run the application under the debugger, the exception raised in the TimeConsumingOperation method is caught and displayed by the debugger. When you run the application outside the debugger, the BackgroundWorker handles the exception and caches it in the Error property of the RunWorkerCompletedEventArgs.
Click the Start button to run an asynchronous operation, and then click the Cancel button to stop a running asynchronous operation.
The outcome of each operation is displayed in a MessageBox.
Next Steps
Implement a form that reports progress as an asynchronous operation proceeds. For more information, see How to: Implement a Form That Uses a Background Operation.
Implement a class that supports the Asynchronous Pattern for Components. For more information, see Implementing the Event-based Asynchronous Pattern.
See Also
Tasks
How to: Implement a Form That Uses a Background Operation
How to: Run an Operation in the Background