BackgroundWorker Class
Updated: September 2010
Executes an operation on a separate thread.
System.MarshalByRefObject
System.ComponentModel.Component
System.ComponentModel.BackgroundWorker
Assembly: System (in System.dll)
The BackgroundWorker type exposes the following members.
Name | Description | |
---|---|---|
CancellationPending | Gets a value indicating whether the application has requested cancellation of a background operation. | |
CanRaiseEvents | Gets a value indicating whether the component can raise an event.(Inherited from Component.) | |
Container | Gets the IContainer that contains the Component. (Inherited fromComponent.) | |
DesignMode | Gets a value that indicates whether the Component is currently in design mode. (Inherited from Component.) | |
Events | Gets the list of event handlers that are attached to this Component.(Inherited from Component.) | |
IsBusy | Gets a value indicating whether the BackgroundWorker is running an asynchronous operation. | |
Site | Gets or sets the ISite of the Component. (Inherited fromComponent.) | |
WorkerReportsProgress | Gets or sets a value indicating whether the BackgroundWorkercan report progress updates. | |
WorkerSupportsCancellation | Gets or sets a value indicating whether the BackgroundWorkersupports asynchronous cancellation. |
Name | Description | |
---|---|---|
CancelAsync | Requests cancellation of a pending background operation. | |
CreateObjRef | Creates an object that contains all the relevant information required to generate a proxy used to communicate with a remote object.(Inherited from MarshalByRefObject.) | |
Dispose() | Releases all resources used by the Component. (Inherited fromComponent.) | |
Dispose(Boolean) | Releases the unmanaged resources used by the Component and optionally releases the managed resources. (Inherited fromComponent.) | |
Equals(Object) | Determines whether the specified Object is equal to the currentObject. (Inherited from Object.) | |
Finalize | Releases unmanaged resources and performs other cleanup operations before the Component is reclaimed by garbage collection.(Inherited from Component.) | |
GetHashCode | Serves as a hash function for a particular type. (Inherited fromObject.) | |
GetLifetimeService | Retrieves the current lifetime service object that controls the lifetime policy for this instance. (Inherited fromMarshalByRefObject.) | |
GetService | Returns an object that represents a service provided by theComponent or by its Container. (Inherited from Component.) | |
GetType | Gets the Type of the current instance. (Inherited from Object.) | |
InitializeLifetimeService | Obtains a lifetime service object to control the lifetime policy for this instance. (Inherited from MarshalByRefObject.) | |
MemberwiseClone() | Creates a shallow copy of the current Object. (Inherited fromObject.) | |
MemberwiseClone(Boolean) | Creates a shallow copy of the current MarshalByRefObject object.(Inherited from MarshalByRefObject.) | |
OnDoWork | Raises the DoWork event. | |
OnProgressChanged | Raises the ProgressChanged event. | |
OnRunWorkerCompleted | Raises the RunWorkerCompleted event. | |
ReportProgress(Int32) | Raises the ProgressChanged event. | |
ReportProgress(Int32, Object) | Raises the ProgressChanged event. | |
RunWorkerAsync() | Starts execution of a background operation. | |
RunWorkerAsync(Object) | Starts execution of a background operation. | |
ToString | Returns a String containing the name of the Component, if any. This method should not be overridden. (Inherited from Component.) |
Name | Description | |
---|---|---|
Disposed | Occurs when the component is disposed by a call to the Dispose method.(Inherited from Component.) | |
DoWork | Occurs when RunWorkerAsync is called. | |
ProgressChanged | Occurs when ReportProgress is called. | |
RunWorkerCompleted | Occurs when the background operation has completed, has been canceled, or has raised an exception. |
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 theBackgroundWorker programmatically or you can drag it onto your form from the Components tab of theToolbox. 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 aBackgroundWorker component to perform multithreaded operations in more than one AppDomain. |
If your background operation requires a parameter, call RunWorkerAsync with your parameter. Inside theDoWork 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.
Note |
---|
The HostProtectionAttribute attribute applied to this type or member has the following Resources property value: SharedState. The HostProtectionAttribute does not affect desktop applications (which are typically started by double-clicking an icon, typing a command, or entering a URL in a browser). For more information, see the HostProtectionAttribute class or SQL Server Programming and Host Protection Attributes. |
The following code example demonstrates the basics of the BackgroundWorker class for executing a time-consuming operation asynchronously. The following illustration shows an example of the output.
To try this code, create a Windows Forms application. Add a Label control named resultLabel and add twoButton controls named startAsyncButton and cancelAsyncButton. Create Click event handlers for both buttons. From the Components tab of the Toolbox, add a BackgroundWorker component namedbackgroundWorker1. Create DoWork, ProgressChanged, and RunWorkerCompleted event handlers for theBackgroundWorker. In the code for the form, replace the existing code with the following code.
using System; using System.ComponentModel; using System.Windows.Forms; namespace BackgroundWorkerSimple { public partial class Form1 : Form { public Form1() { InitializeComponent(); backgroundWorker1.WorkerReportsProgress = true; backgroundWorker1.WorkerSupportsCancellation = true; } private void startAsyncButton_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy != true) { // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(); } } private void cancelAsyncButton_Click(object sender, EventArgs e) { if (backgroundWorker1.WorkerSupportsCancellation == true) { // Cancel the asynchronous operation. backgroundWorker1.CancelAsync(); } } // This event handler is where the time-consuming work is done. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; for (int i = 1; i <= 10; i++) { if (worker.CancellationPending == true) { e.Cancel = true; break; } else { // Perform a time consuming operation and report progress. System.Threading.Thread.Sleep(500); worker.ReportProgress(i * 10); } } } // This event handler updates the progress. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { resultLabel.Text = (e.ProgressPercentage.ToString() + "%"); } // This event handler deals with the results of the background operation. private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled == true) { resultLabel.Text = "Canceled!"; } else if (e.Error != null) { resultLabel.Text = "Error: " + e.Error.Message; } else { resultLabel.Text = "Done!"; } } } }
The following code example demonstrates the use of the BackgroundWorker class for executing a time-consuming operation asynchronously. The following illustration shows an example of the output.
The operation computes the selected Fibonacci number, reports progress updates as the calculation proceeds, and permits a pending calculation to be canceled.
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Threading; using System.Windows.Forms; namespace BackgroundWorkerExample { public class FibonacciForm : 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(); InitializeBackgroundWorker(); } // Set up the BackgroundWorker object by // attaching event handlers. private void InitializeBackgroundWorker() { backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler( backgroundWorker1_RunWorkerCompleted); backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler( backgroundWorker1_ProgressChanged); } private void startAsyncButton_Click(System.Object sender, System.EventArgs e) { // Reset the text in the result label. resultLabel.Text = String.Empty; // Disable the UpDown control until // the asynchronous operation is done. this.numericUpDown1.Enabled = false; // Disable the Start button until // the asynchronous operation is done. this.startAsyncButton.Enabled = false; // Enable the Cancel button while // the asynchronous operation runs. this.cancelAsyncButton.Enabled = true; // Get the value from the UpDown control. numberToCompute = (int)numericUpDown1.Value; // Reset the variable for percentage tracking. highestPercentageReached = 0; // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(numberToCompute); } private void cancelAsyncButton_Click(System.Object sender, System.EventArgs e) { // Cancel the asynchronous operation. this.backgroundWorker1.CancelAsync(); // Disable the Cancel button. cancelAsyncButton.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 = sender as 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((int)e.Argument, worker, e); } // 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.Error != null) { MessageBox.Show(e.Error.Message); } else if (e.Cancelled) { // 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(); } // Enable the UpDown control. this.numericUpDown1.Enabled = true; // Enable the Start button. startAsyncButton.Enabled = true; // Disable the Cancel button. cancelAsyncButton.Enabled = false; } // This event handler updates the progress bar. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage; } // 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 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) { e.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.Location = new System.Drawing.Point(16, 16); this.numericUpDown1.Maximum = new System.Decimal(new int[] { 91, 0, 0, 0}); this.numericUpDown1.Minimum = new System.Decimal(new int[] { 1, 0, 0, 0}); this.numericUpDown1.Name = "numericUpDown1"; this.numericUpDown1.Size = new System.Drawing.Size(80, 20); this.numericUpDown1.TabIndex = 0; this.numericUpDown1.Value = new System.Decimal(new int[] { 1, 0, 0, 0}); // // startAsyncButton // this.startAsyncButton.Location = new System.Drawing.Point(16, 72); this.startAsyncButton.Name = "startAsyncButton"; this.startAsyncButton.Size = new System.Drawing.Size(120, 23); this.startAsyncButton.TabIndex = 1; this.startAsyncButton.Text = "Start Async"; this.startAsyncButton.Click += new System.EventHandler(this.startAsyncButton_Click); // // cancelAsyncButton // this.cancelAsyncButton.Enabled = false; this.cancelAsyncButton.Location = new System.Drawing.Point(153, 72); this.cancelAsyncButton.Name = "cancelAsyncButton"; this.cancelAsyncButton.Size = new System.Drawing.Size(119, 23); this.cancelAsyncButton.TabIndex = 2; this.cancelAsyncButton.Text = "Cancel Async"; this.cancelAsyncButton.Click += new System.EventHandler(this.cancelAsyncButton_Click); // // resultLabel // this.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; this.resultLabel.Location = new System.Drawing.Point(112, 16); this.resultLabel.Name = "resultLabel"; this.resultLabel.Size = new System.Drawing.Size(160, 23); this.resultLabel.TabIndex = 3; this.resultLabel.Text = "(no result)"; this.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // progressBar1 // this.progressBar1.Location = new System.Drawing.Point(18, 48); this.progressBar1.Name = "progressBar1"; this.progressBar1.Size = new System.Drawing.Size(256, 8); this.progressBar1.Step = 2; this.progressBar1.TabIndex = 4; // // backgroundWorker1 // this.backgroundWorker1.WorkerReportsProgress = true; this.backgroundWorker1.WorkerSupportsCancellation = true; // // FibonacciForm // this.ClientSize = new System.Drawing.Size(292, 118); this.Controls.Add(this.progressBar1); this.Controls.Add(this.resultLabel); this.Controls.Add(this.cancelAsyncButton); this.Controls.Add(this.startAsyncButton); this.Controls.Add(this.numericUpDown1); this.Name = "FibonacciForm"; this.Text = "Fibonacci Calculator"; ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); this.ResumeLayout(false); } #endregion [STAThread] static void Main() { Application.Run(new FibonacciForm()); } } }