BackgroundWorker Class
Assembly: System (in system.dll)
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.
To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished. You can create the BackgroundWorker programmatically or you can drag it onto your form from the Components tab of the Toolbox. If you create the BackgroundWorker in the Windows Forms Designer, it will appear in the Component Tray, and its properties will be displayed in the Properties window.
To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.
Note: |
|---|
| You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events. BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain. |
If your background operation requires a parameter, call RunWorkerAsync with your parameter. Inside the DoWork event handler, you can extract the parameter from the DoWorkEventArgs.Argument property.
For more information about BackgroundWorker, see How to: Run an Operation in the Background.
The following code example demonstrates the use of the BackgroundWorker class for executing a time-consuming operation asynchronously. The operation computes the selected Fibonacci number, reports progress updates as the calculation proceeds, and permits a pending calculation to be canceled.
Imports System Imports System.Collections Imports System.ComponentModel Imports System.Drawing Imports System.Threading Imports System.Windows.Forms Public Class FibonacciForm Inherits System.Windows.Forms.Form Private numberToCompute As Integer = 0 Private highestPercentageReached As Integer = 0 Private numericUpDown1 As System.Windows.Forms.NumericUpDown Private WithEvents startAsyncButton As System.Windows.Forms.Button Private WithEvents cancelAsyncButton As System.Windows.Forms.Button Private progressBar1 As System.Windows.Forms.ProgressBar Private resultLabel As System.Windows.Forms.Label Private WithEvents backgroundWorker1 As System.ComponentModel.BackgroundWorker Public Sub New() InitializeComponent() End Sub 'New Private Sub startAsyncButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles startAsyncButton.Click ' Reset the text in the result label. resultLabel.Text = [String].Empty ' Disable the UpDown control until ' the asynchronous operation is done. Me.numericUpDown1.Enabled = False ' Disable the Start button until ' the asynchronous operation is done. Me.startAsyncButton.Enabled = False ' Enable the Cancel button while ' the asynchronous operation runs. Me.cancelAsyncButton.Enabled = True ' Get the value from the UpDown control. numberToCompute = CInt(numericUpDown1.Value) ' Reset the variable for percentage tracking. highestPercentageReached = 0 ' Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(numberToCompute) End Sub Private Sub cancelAsyncButton_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cancelAsyncButton.Click ' Cancel the asynchronous operation. Me.backgroundWorker1.CancelAsync() ' Disable the Cancel button. cancelAsyncButton.Enabled = False End Sub 'cancelAsyncButton_Click ' This event handler is where the actual work is done. Private Sub backgroundWorker1_DoWork( _ ByVal sender As Object, _ ByVal e As DoWorkEventArgs) _ Handles backgroundWorker1.DoWork ' Get the BackgroundWorker object that raised this event. Dim worker As BackgroundWorker = _ CType(sender, BackgroundWorker) ' Assign the result of the computation ' to the Result property of the DoWorkEventArgs ' object. This is will be available to the ' RunWorkerCompleted eventhandler. e.Result = ComputeFibonacci(e.Argument, worker, e) End Sub 'backgroundWorker1_DoWork ' This event handler deals with the results of the ' background operation. Private Sub backgroundWorker1_RunWorkerCompleted( _ ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) _ Handles backgroundWorker1.RunWorkerCompleted ' First, handle the case where an exception was thrown. If (e.Error IsNot Nothing) Then MessageBox.Show(e.Error.Message) ElseIf e.Cancelled Then ' Next, handle the case where the user canceled the ' operation. ' Note that due to a race condition in ' the DoWork event handler, the Cancelled ' flag may not have been set, even though ' CancelAsync was called. resultLabel.Text = "Canceled" Else ' Finally, handle the case where the operation succeeded. resultLabel.Text = e.Result.ToString() End If ' Enable the UpDown control. Me.numericUpDown1.Enabled = True ' Enable the Start button. startAsyncButton.Enabled = True ' Disable the Cancel button. cancelAsyncButton.Enabled = False End Sub 'backgroundWorker1_RunWorkerCompleted ' This event handler updates the progress bar. Private Sub backgroundWorker1_ProgressChanged( _ ByVal sender As Object, ByVal e As ProgressChangedEventArgs) _ Handles backgroundWorker1.ProgressChanged Me.progressBar1.Value = e.ProgressPercentage End Sub ' This is the method that does the actual work. For this ' example, it computes a Fibonacci number and ' reports progress as it does its work. Function ComputeFibonacci( _ ByVal n As Integer, _ ByVal worker As BackgroundWorker, _ ByVal e As DoWorkEventArgs) As Long ' The parameter n must be >= 0 and <= 91. ' Fib(n), with n > 91, overflows a long. If n < 0 OrElse n > 91 Then Throw New ArgumentException( _ "value must be >= 0 and <= 91", "n") End If Dim result As Long = 0 ' Abort the operation if the user has canceled. ' Note that a call to CancelAsync may have set ' CancellationPending to true just after the ' last invocation of this method exits, so this ' code will not have the opportunity to set the ' DoWorkEventArgs.Cancel flag to true. This means ' that RunWorkerCompletedEventArgs.Cancelled will ' not be set to true in your RunWorkerCompleted ' event handler. This is a race condition. If worker.CancellationPending Then e.Cancel = True Else If n < 2 Then result = 1 Else result = ComputeFibonacci(n - 1, worker, e) + _ ComputeFibonacci(n - 2, worker, e) End If ' Report progress as a percentage of the total task. Dim percentComplete As Integer = _ CSng(n) / CSng(numberToCompute) * 100 If percentComplete > highestPercentageReached Then highestPercentageReached = percentComplete worker.ReportProgress(percentComplete) End If End If Return result End Function Private Sub InitializeComponent() Me.numericUpDown1 = New System.Windows.Forms.NumericUpDown Me.startAsyncButton = New System.Windows.Forms.Button Me.cancelAsyncButton = New System.Windows.Forms.Button Me.resultLabel = New System.Windows.Forms.Label Me.progressBar1 = New System.Windows.Forms.ProgressBar Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker CType(Me.numericUpDown1, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' 'numericUpDown1 ' Me.numericUpDown1.Location = New System.Drawing.Point(16, 16) Me.numericUpDown1.Maximum = New Decimal(New Integer() {91, 0, 0, 0}) Me.numericUpDown1.Minimum = New Decimal(New Integer() {1, 0, 0, 0}) Me.numericUpDown1.Name = "numericUpDown1" Me.numericUpDown1.Size = New System.Drawing.Size(80, 20) Me.numericUpDown1.TabIndex = 0 Me.numericUpDown1.Value = New Decimal(New Integer() {1, 0, 0, 0}) ' 'startAsyncButton ' Me.startAsyncButton.Location = New System.Drawing.Point(16, 72) Me.startAsyncButton.Name = "startAsyncButton" Me.startAsyncButton.Size = New System.Drawing.Size(120, 23) Me.startAsyncButton.TabIndex = 1 Me.startAsyncButton.Text = "Start Async" ' 'cancelAsyncButton ' Me.cancelAsyncButton.Enabled = False Me.cancelAsyncButton.Location = New System.Drawing.Point(153, 72) Me.cancelAsyncButton.Name = "cancelAsyncButton" Me.cancelAsyncButton.Size = New System.Drawing.Size(119, 23) Me.cancelAsyncButton.TabIndex = 2 Me.cancelAsyncButton.Text = "Cancel Async" ' 'resultLabel ' Me.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D Me.resultLabel.Location = New System.Drawing.Point(112, 16) Me.resultLabel.Name = "resultLabel" Me.resultLabel.Size = New System.Drawing.Size(160, 23) Me.resultLabel.TabIndex = 3 Me.resultLabel.Text = "(no result)" Me.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter ' 'progressBar1 ' Me.progressBar1.Location = New System.Drawing.Point(18, 48) Me.progressBar1.Name = "progressBar1" Me.progressBar1.Size = New System.Drawing.Size(256, 8) Me.progressBar1.TabIndex = 4 ' 'backgroundWorker1 ' Me.backgroundWorker1.WorkerReportsProgress = True Me.backgroundWorker1.WorkerSupportsCancellation = True ' 'FibonacciForm ' Me.ClientSize = New System.Drawing.Size(292, 118) Me.Controls.Add(Me.progressBar1) Me.Controls.Add(Me.resultLabel) Me.Controls.Add(Me.cancelAsyncButton) Me.Controls.Add(Me.startAsyncButton) Me.Controls.Add(Me.numericUpDown1) Me.Name = "FibonacciForm" Me.Text = "Fibonacci Calculator" CType(Me.numericUpDown1, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub 'InitializeComponent <STAThread()> _ Shared Sub Main() Application.Run(New FibonacciForm) End Sub 'Main End Class 'FibonacciForm
import System.* ;
import System.Collections.* ;
import System.ComponentModel.* ;
import System.Drawing.* ;
import System.Threading.* ;
import System.Windows.Forms.* ;
public class FibonacciForm extends System.Windows.Forms.Form
{
private int numberToCompute = 0;
private int highestPercentageReached = 0;
private System.Windows.Forms.NumericUpDown numericUpDown1;
private System.Windows.Forms.Button startAsyncButton;
private System.Windows.Forms.Button cancelAsyncButton;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label resultLabel;
private System.ComponentModel.BackgroundWorker backgroundWorker1;
public FibonacciForm()
{
InitializeComponent();
InitializeBackgoundWorker();
} //FibonacciForm
// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgoundWorker()
{
backgroundWorker1.add_DoWork(new DoWorkEventHandler(
backgroundWorker1_DoWork));
backgroundWorker1.add_RunWorkerCompleted(
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted));
backgroundWorker1.add_ProgressChanged(
new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged));
} //InitializeBackgoundWorker
private void startAsyncButton_Click(Object sender, EventArgs e)
{
// Reset the text in the result label.
resultLabel.set_Text(String.Empty);
// Disable the UpDown control until
// the asynchronous operation is done.
this.numericUpDown1.set_Enabled(false);
// Disable the Start button until
// the asynchronous operation is done.
this.startAsyncButton.set_Enabled(false);
// Enable the Cancel button while
// the asynchronous operation runs.
this.cancelAsyncButton.set_Enabled(true);
// Get the value from the UpDown control.
numberToCompute = System.Convert.ToInt32((numericUpDown1.get_Value()));
// Reset the variable for percentage tracking.
highestPercentageReached = 0;
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(System.Convert.ToString
(numberToCompute));
}
private void cancelAsyncButton_Click(Object sender, System.EventArgs e)
{
// Cancel the asynchronous operation.
this.backgroundWorker1.CancelAsync();
// Disable the Cancel button.
cancelAsyncButton.set_Enabled(false);
}
// This event handler is where the actual,
// potentially time-consuming work is done.
private void backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = (BackgroundWorker)sender;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.set_Result(new Long(ComputeFibonacci(System.Convert.ToInt32
(e.get_Argument()), worker, e)));
//e.Result = ComputeFibonacci((int)e.Argument, worker, e);
} //backgroundWorker1_DoWork
// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(Object sender,
RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.get_Error() != null) {
MessageBox.Show(e.get_Error().get_Message());
}
else {
if (e.get_Cancelled()) {
// Next, handle the case where the user cancelled
// the operation.
// Note that due to a race condition in
// the DoWork event handler, the Cancelled
// flag may not have been set, even though
// CancelAsync was called.
resultLabel.set_Text("Cancelled");
}
else {
// Finally, handle the case where the operation
// succeeded.
resultLabel.set_Text(e.get_Result().ToString());
}
}
// Enable the UpDown control.
this.numericUpDown1.set_Enabled(true);
// Enable the Start button.
startAsyncButton.set_Enabled(true);
// Disable the Cancel button.
cancelAsyncButton.set_Enabled(false);
} //backgroundWorker1_RunWorkerCompleted
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(Object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.set_Value(e.get_ProgressPercentage());
} //backgroundWorker1_ProgressChanged
// This is the method that does the actual work. For this
// example, it computes a Fibonacci number and
// reports progress as it does its work.
long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)
{
// The parameter n must be >= 0 and <= 91.
// Fib(n), with n > 91, overflows a long.
if (n < 0 || n > 91) {
throw new ArgumentException("value must be >= 0 and <= 91", "n");
}
long result = 0;
// Abort the operation if the user has cancelled.
// Note that a call to CancelAsync may have set
// CancellationPending to true just after the
// last invocation of this method exits, so this
// code will not have the opportunity to set the
// DoWorkEventArgs.Cancel flag to true. This means
// that RunWorkerCompletedEventArgs.Cancelled will
// not be set to true in your RunWorkerCompleted
// event handler. This is a race condition.
if (worker.get_CancellationPending()) {
e.set_Cancel(true);
}
else {
if (n < 2) {
result = 1;
}
else {
result = ComputeFibonacci(n - 1, worker, e)
+ ComputeFibonacci(n - 2, worker, e);
}
// Report progress as a percentage of the total task.
int percentComplete=(int)((float)(n)/(float)(numberToCompute)* 100);
if (percentComplete > highestPercentageReached) {
highestPercentageReached = percentComplete;
worker.ReportProgress(percentComplete);
}
}
return result;
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.startAsyncButton = new System.Windows.Forms.Button();
this.cancelAsyncButton = new System.Windows.Forms.Button();
this.resultLabel = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).
BeginInit();
this.SuspendLayout();
//
// numericUpDown1
//
this.numericUpDown1.set_Location(new System.Drawing.Point(16, 16));
this.numericUpDown1.set_Maximum(new System.Decimal(
new int[] { 91, 0, 0, 0 }));
this.numericUpDown1.set_Minimum(new System.Decimal(
new int[] { 1, 0, 0, 0 }));
this.numericUpDown1.set_Name("numericUpDown1");
this.numericUpDown1.set_Size(new System.Drawing.Size(80, 20));
this.numericUpDown1.set_TabIndex(0);
this.numericUpDown1.set_Value(new System.Decimal(
new int[] { 1, 0, 0, 0 }));
//
// startAsyncButton
//
this.startAsyncButton.set_Location(new System.Drawing.Point(16, 72));
this.startAsyncButton.set_Name("startAsyncButton");
this.startAsyncButton.set_Size(new System.Drawing.Size(120, 23));
this.startAsyncButton.set_TabIndex(1);
this.startAsyncButton.set_Text("Start Async");
this.startAsyncButton.add_Click(
new System.EventHandler(this.startAsyncButton_Click));
//
// cancelAsyncButton
//
this.cancelAsyncButton.set_Enabled(false);
this.cancelAsyncButton.set_Location(new System.Drawing.Point(153, 72));
this.cancelAsyncButton.set_Name("cancelAsyncButton");
this.cancelAsyncButton.set_Size(new System.Drawing.Size(119, 23));
this.cancelAsyncButton.set_TabIndex(2);
this.cancelAsyncButton.set_Text("Cancel Async");
this.cancelAsyncButton.add_Click(
new System.EventHandler(this.cancelAsyncButton_Click));
//
// resultLabel
//
this.resultLabel.set_BorderStyle(System.Windows.Forms.BorderStyle.Fixed3D);
this.resultLabel.set_Location(new System.Drawing.Point(112, 16));
this.resultLabel.set_Name("resultLabel");
this.resultLabel.set_Size(new System.Drawing.Size(160, 23));
this.resultLabel.set_TabIndex(3);
this.resultLabel.set_Text("(no result)");
this.resultLabel.set_TextAlign(System.Drawing.ContentAlignment.MiddleCenter);
//
// progressBar1
//
this.progressBar1.set_Location(new System.Drawing.Point(18, 48));
this.progressBar1.set_Name("progressBar1");
this.progressBar1.set_Size(new System.Drawing.Size(256, 8));
this.progressBar1.set_Step(2);
this.progressBar1.set_TabIndex(4);
//
// backgroundWorker1
//
this.backgroundWorker1.set_WorkerReportsProgress(true);
this.backgroundWorker1.set_WorkerSupportsCancellation(true);
//
// FibonacciForm
//
this.set_ClientSize(new System.Drawing.Size(292, 118));
this.get_Controls().Add(this.progressBar1);
this.get_Controls().Add(this.resultLabel);
this.get_Controls().Add(this.cancelAsyncButton);
this.get_Controls().Add(this.startAsyncButton);
this.get_Controls().Add(this.numericUpDown1);
this.set_Name("FibonacciForm");
this.set_Text("Fibonacci Calculator");
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).
EndInit();
this.ResumeLayout(false);
} //InitializeComponent
#endregion
/** @attribute STAThread()
*/
public static void main(String[] args)
{
Application.Run(new FibonacciForm());
} //main
} //FibonacciForm
System.MarshalByRefObject
System.ComponentModel.Component
System.ComponentModel.BackgroundWorker
Windows 98, Windows Server 2000 SP4, Windows Millennium Edition, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition
The Microsoft .NET Framework 3.0 is supported on Windows Vista, Microsoft Windows XP SP2, and Windows Server 2003 SP1.
Note: