Click to Rate and Give Feedback
MSDN
MSDN Library
.NET Development
.NET Framework 3.5
Collapse All/Expand All Collapse All
This page is specific to
Microsoft Visual Studio 2008/.NET Framework 3.5

Other versions are also available for the following:
.NET Framework Class Library
BackgroundWorker Class

Executes an operation on a separate thread.

Namespace:  System.ComponentModel
Assembly:  System (in System.dll)
Visual Basic (Declaration)
<HostProtectionAttribute(SecurityAction.LinkDemand, SharedState := True)> _
Public Class BackgroundWorker _
    Inherits Component
Visual Basic (Usage)
Dim instance As BackgroundWorker
C#
[HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true)]
public class BackgroundWorker : Component
Visual C++
[HostProtectionAttribute(SecurityAction::LinkDemand, SharedState = true)]
public ref class BackgroundWorker : public Component
JScript
public class BackgroundWorker extends Component
NoteNote:

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 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.

NoteNote:

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.

Visual Basic
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 

C#
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());
        }
    }
}
Visual C++
#using <System.Drawing.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Collections;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::Windows::Forms;

public ref class FibonacciForm: public System::Windows::Forms::Form
{
private:

   int numberToCompute;
   int highestPercentageReached;

   System::Windows::Forms::NumericUpDown^ numericUpDown1;
   System::Windows::Forms::Button^ startAsyncButton;
   System::Windows::Forms::Button^ cancelAsyncButton;
   System::Windows::Forms::ProgressBar^ progressBar1;
   System::Windows::Forms::Label ^ resultLabel;
   System::ComponentModel::BackgroundWorker^ backgroundWorker1;

public:
   FibonacciForm()
   {
      InitializeComponent();
      numberToCompute = highestPercentageReached = 0;
      InitializeBackgoundWorker();
   }


private:

   // Set up the BackgroundWorker object by 
   // attaching event handlers. 
   void InitializeBackgoundWorker()
   {
      backgroundWorker1->DoWork += gcnew DoWorkEventHandler( this, &FibonacciForm::backgroundWorker1_DoWork );
      backgroundWorker1->RunWorkerCompleted += gcnew RunWorkerCompletedEventHandler( this, &FibonacciForm::backgroundWorker1_RunWorkerCompleted );
      backgroundWorker1->ProgressChanged += gcnew ProgressChangedEventHandler( this, &FibonacciForm::backgroundWorker1_ProgressChanged );
   }

   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 );
   }

   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.
   void backgroundWorker1_DoWork( Object^ sender, DoWorkEventArgs^ e )
   {
      // Get the BackgroundWorker that raised this event.
      BackgroundWorker^ worker = dynamic_cast<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->Result = ComputeFibonacci( safe_cast<Int32>(e->Argument), worker, e );
   }

   // This event handler deals with the results of the
   // background operation.
   void backgroundWorker1_RunWorkerCompleted( Object^ /*sender*/, RunWorkerCompletedEventArgs^ e )
   {
      // First, handle the case where an exception was thrown.
      if ( e->Error != nullptr )
      {
         MessageBox::Show( e->Error->Message );
      }
      else
      if ( e->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->Text = "Cancelled";
      }
      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.
   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 gcnew 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->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;
   }

   void InitializeComponent()
   {
      this->numericUpDown1 = gcnew System::Windows::Forms::NumericUpDown;
      this->startAsyncButton = gcnew System::Windows::Forms::Button;
      this->cancelAsyncButton = gcnew System::Windows::Forms::Button;
      this->resultLabel = gcnew System::Windows::Forms::Label;
      this->progressBar1 = gcnew System::Windows::Forms::ProgressBar;
      this->backgroundWorker1 = gcnew System::ComponentModel::BackgroundWorker;
      (dynamic_cast<System::ComponentModel::ISupportInitialize^>(this->numericUpDown1))->BeginInit();
      this->SuspendLayout();

      // 
      // numericUpDown1
      // 
      this->numericUpDown1->Location = System::Drawing::Point( 16, 16 );
      array<Int32>^temp0 = {91,0,0,0};
      this->numericUpDown1->Maximum = System::Decimal( temp0 );
      array<Int32>^temp1 = {1,0,0,0};
      this->numericUpDown1->Minimum = System::Decimal( temp1 );
      this->numericUpDown1->Name = "numericUpDown1";
      this->numericUpDown1->Size = System::Drawing::Size( 80, 20 );
      this->numericUpDown1->TabIndex = 0;
      array<Int32>^temp2 = {1,0,0,0};
      this->numericUpDown1->Value = System::Decimal( temp2 );

      // 
      // startAsyncButton
      // 
      this->startAsyncButton->Location = System::Drawing::Point( 16, 72 );
      this->startAsyncButton->Name = "startAsyncButton";
      this->startAsyncButton->Size = System::Drawing::Size( 120, 23 );
      this->startAsyncButton->TabIndex = 1;
      this->startAsyncButton->Text = "Start Async";
      this->startAsyncButton->Click += gcnew System::EventHandler( this, &FibonacciForm::startAsyncButton_Click );

      // 
      // cancelAsyncButton
      // 
      this->cancelAsyncButton->Enabled = false;
      this->cancelAsyncButton->Location = System::Drawing::Point( 153, 72 );
      this->cancelAsyncButton->Name = "cancelAsyncButton";
      this->cancelAsyncButton->Size = System::Drawing::Size( 119, 23 );
      this->cancelAsyncButton->TabIndex = 2;
      this->cancelAsyncButton->Text = "Cancel Async";
      this->cancelAsyncButton->Click += gcnew System::EventHandler( this, &FibonacciForm::cancelAsyncButton_Click );

      // 
      // resultLabel
      // 
      this->resultLabel->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
      this->resultLabel->Location = System::Drawing::Point( 112, 16 );
      this->resultLabel->Name = "resultLabel";
      this->resultLabel->Size = 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 = System::Drawing::Point( 18, 48 );
      this->progressBar1->Name = "progressBar1";
      this->progressBar1->Size = 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 = 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";
      (dynamic_cast<System::ComponentModel::ISupportInitialize^>(this->numericUpDown1))->EndInit();
      this->ResumeLayout( false );
   }
};

[STAThread]
int main()
{
   Application::Run( gcnew FibonacciForm );
}
System..::.Object
  System..::.MarshalByRefObject
    System.ComponentModel..::.Component
      System.ComponentModel..::.BackgroundWorker
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

Windows 7, Windows Vista, Windows XP SP2, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP Starter Edition, Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, Windows Server 2000 SP4, Windows Millennium Edition, Windows 98

The .NET Framework and .NET Compact Framework do not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

.NET Framework

Supported in: 3.5, 3.0, 2.0
Community Content   What is Community Content?
Add new content RSS  Annotations
Horrible example      Tuxbear ... Thomas Lee   |   Edit   |   Show History
The while loop is horrible. A subscription to RunWorkerCompleted is the way to go. Please revise this example.
A second example of BackgroundWorker.      David M Morton   |   Edit   |   Show History

I wrote this example as an online example in the MSDN forums, but I thought it would be better posted here. I've included several comments on where to put what, etc.

using System.Windows.Forms;   
using System;
using System.Drawing;
using System.Timers;
using System.IO;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
  
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
BackgroundWorker worker;

public Form1()
{

InitializeComponent();
// instantiate the backgroundworker.
worker = new BackgroundWorker();

// These hook up the event handlers to the events on the BackgroundWorker.
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

// This line ensures that we can report progress from the BackgroundWorker. By default
// progress reporting is disabled, and it'll throw an error if you don't enable it, and you try to
// report progress.
worker.WorkerReportsProgress = true;


}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
// put the code or the method call you want to run in here.
// when you want to report progress to the UI, call:
worker.ReportProgress(50, DateTime.Now);
// where 50 represents the percentage of the task completed, and
// the DateTime.Now would be replaced with an object that represents
// more intricate data you want to display on the UI. This information
// gets passed into the ProgressChanged event handler, which in this scenario
// is the "worker_ProgressChanged" method. See that method for more information.


// Lets sleep for a little bit here:
Thread.Sleep(5000);

// you can pass a result back to the RunWorkerCompleted event handler,
// by setting the e.Result to a value when you're completed.
e.Result = "I'm all finished";
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// e.Result is the object that was set to e.Result in the DoWork event handler above.
// In this situation, you'll see a messagebox that says "I'm all finished".
MessageBox.Show(e.Result.ToString());
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// This is the progresschanged event. This gets called whenever you call "worker.ReportProgress"
// from your DoWork event handler. The first value you pass to "ReportProgress" comes
// in as e.ProgressPercentage. You can use it in this method:

MessageBox.Show("The progress completed is: " + e.ProgressPercentage.ToString());

// The second parameter you pass into ReportProgress is the "UserState".
// this is your more intricate data you passed to ReportProgress from your
// DoWork event handler:
MessageBox.Show("The current user state, and the second parameter passed to ReportProgress is: " +
e.UserState.ToString());

}

private void button1_Click(object sender, EventArgs e)
{
// this is the method to call to start running your background process.
// first we're going to ensure the worker is not busy, by checking the IsBusy property.
// This will let us know whether or not the backgroundWorker is currently performing
// some operation in the background. We don't want to start it if it is.
if (!worker.IsBusy)
worker.RunWorkerAsync();
else
MessageBox.Show("The worker is busy right now... please wait.");
}
}
}
BackgroundWorker and CPU architecture affinity      Vitaliy Liptchinsky ... Thomas Lee   |   Edit   |   Show History
Hi,

I've noticed that internal field called cancellationPending which is encapsulated by property CancellationPending is not covered by any thread synchronization and neither is not marked as volatile.

CancellationPending is used in different threads: main UI and background thread.

This can cause problems on CPU architectures with weak memory models such as Itanium.

I believe it should be stated in documentation as a warning


--- I would imagine this is a CLR issue, along with all other similar hardware sensitive optimizations.
Updating the UI or Manipulating Databound ViewModel Properties      LukeSkywalker   |   Edit   |   Show History
A technique for writing changes to the UI or to a ViewModel object is to package it up in a delegate inside the ProgressChangedEventArgs instance which means that you can code much more complex UI updates as anonymous methods from within the code that's doing the work.

See my article here:

http://lukepuplett.blogspot.com/2009/05/updating-ui-from-asynchronous-ops.html
BGW Nuances including Sample with ProgressBar      Rudedog2   |   Edit   |   Show History
At the suggestion of David Morton, I am adding this content and sample. David assisted me with the sample on a question I had posed on the forums. First a few comments about the sample.

There are two types of threads. I used what is known as the BackgroundWorker class. You can look it up in the MSDN library for detailed explanations. I will describe some the nuances they do not discuss or emphasize enough.

1. The BGW is a "turnkey" class that is ready made to perform tasks---execute a method---on another thread. The method that is invoked is the the DoWork event handler. The last method in my sample is where the BGW does its' work.

2. Note, that the BGW can cause exceptions if it attempts to access or modify class level variables. All data must be passed to it by delegates and events. In my sample I do not pass any arguments or data to it. I use the parameterless overload of RunWorkerAsync() to start the BGW. The parameter would get passed into the BGW as the Argument property of the DoWorkEventArgs.

3. You return data from the BGW once again through the use of delegates and events. I do this in my sample by calling the ReportProgress() method, which fires the ProgressChanged event. The parameter in ReportProgress is returned to the main thread as a Property in the EventsArgs class. Set a breakpoint in my sample and verify this for yourself. In my sample I do pass an argument back to the calling thread by calling the overload of ReportProgress. The parameter would get passed back to the calling thread as the UserState property of the ProgressChangedEventArgs object.

4. NEVER. NEVER. Never try to reference variables not declared inside of DoWork. It may seem to work at times, but in reality you are just getting lucky.

5. ALWAYS. ALWAYS. Check the RunWorkerCompletedEventArgs.Error property in the Completed event handler. I understand that it is the most reliable way to catch BGW exceptions and that it is crucial to do so.

Note that I used the PerformStep() method in the ProgressBar to change the "Value" of it. You must first set the "Step" property prior to calling that method. Why do that when the Value can be set directly? The PB has Min and Max properties that set limits on the Value property, in other words they set the scaling behavior of the display.

Some folks claim that Min and Max do not work. If you write a Value that is outside of the Min/Max limits an exception is thrown. One must check the value prior to writing to the PB.Value property to avoid the exception. Doing so actually bypasses the built-in checks afforded my the Min/Max properties. That is why I set the Step property, and then call PerformStep().

Here's the sample ...


class ProgressForm2 : Form
{
public ProgressForm2()
{
InitializeComponent();
}
public void ShowProgress()
{
this.button1_Click(this, new EventArgs());
}
        private Button button1;
private ProgressBar progressBar1;
        /// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
            base.Dispose(disposing);
        }
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(92, 99);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Process";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(30, 47);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(223, 23);
this.progressBar1.TabIndex = 1;
//
// ProgressForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.button1);
this.Name = "ProgressForm";
this.Text = "ProgressForm";
this.Load += new System.EventHandler(this.ProgressForm_Load);
this.ResumeLayout(false);
}
  
#endregion
        private BackgroundWorker worker = new BackgroundWorker();
        private void ProgressForm_Load(object sender, EventArgs e)
{
this.progressBar1.Style = ProgressBarStyle.Continuous;
this.progressBar1.Step = 1;
this.button1_Click(this, new EventArgs());
}

public delegate void Action();
        private void PerformStep()
{
if (this.InvokeRequired)
{
this.Invoke(new Action(PerformStep));
}
else
{
this.progressBar1.PerformStep();
}
}
        private void button1_Click(object sender, EventArgs e)
{
this.progressBar1.Minimum = 0;
this.progressBar1.Maximum = 1000;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.WorkerReportsProgress = true;
worker.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged +=
new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerAsync();
}
        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.progressBar1.PerformStep();
return;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message, "File Transfer Failed", MessageBoxIcon.Error);
}
else
{
MessageBox.Show("File Transfer Completed", "File Transfer Completed", MessageBoxButtons.OK);
}
this.Close();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
int ordersCount = 1000;
for (int i = 0; i < ordersCount; i++)
{
//this.PerformStep(); // either statement works
worker.ReportProgress(i); either statement works
Thread.Sleep(5);
}
}
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
return base.ProcessCmdKey(ref msg, keyData);
}
}



VB Sample with ProgressBar      Rudedog2   |   Edit   |   Show History
Imports System.ComponentModel
Imports System.Threading
  
Imports System.ComponentModel
Imports System.Threading
 
Friend Class ProgressForm2
Inherits Form
' Methods
Public Sub New()
Me.InitializeComponent()
End Sub
    Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
Me.progressBar1.Minimum = 0
Me.progressBar1.Maximum = &H3E8
AddHandler Me.worker.DoWork, New DoWorkEventHandler(AddressOf Me.worker_DoWork)
Me.worker.WorkerReportsProgress = True
AddHandler Me.worker.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf Me.worker_RunWorkerCompleted)
AddHandler Me.worker.ProgressChanged, New ProgressChangedEventHandler(AddressOf Me.worker_ProgressChanged)
Me.worker.RunWorkerAsync()
End Sub
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If (disposing AndAlso (Not Me.components Is Nothing)) Then
Me.components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
    Private Sub InitializeComponent()
Me.button1 = New Button
Me.progressBar1 = New ProgressBar
MyBase.SuspendLayout()
Me.button1.Location = New Point(&H5C, &H63)
Me.button1.Name = "button1"
Me.button1.Size = New Size(&H4B, &H17)
Me.button1.TabIndex = 0
Me.button1.Text = "Process"
Me.button1.UseVisualStyleBackColor = True
AddHandler Me.button1.Click, New EventHandler(AddressOf Me.button1_Click)
Me.progressBar1.Location = New Point(30, &H2F)
Me.progressBar1.Name = "progressBar1"
Me.progressBar1.Size = New Size(&HDF, &H17)
Me.progressBar1.TabIndex = 1
MyBase.AutoScaleDimensions = New SizeF(6.0!, 13.0!)
MyBase.AutoScaleMode = AutoScaleMode.Font
MyBase.ClientSize = New Size(&H124, &H111)
MyBase.Controls.Add(Me.progressBar1)
MyBase.Controls.Add(Me.button1)
MyBase.Name = "ProgressForm"
Me.Text = "ProgressForm"
AddHandler MyBase.Load, New EventHandler(AddressOf Me.ProgressForm_Load)
MyBase.ResumeLayout(False)
End Sub
    Private Sub PerformStep()
If MyBase.InvokeRequired Then
MyBase.Invoke(New Action(AddressOf Me.PerformStep))
Else
Me.progressBar1.PerformStep()
End If
End Sub
    Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
Return MyBase.ProcessCmdKey((msg), keyData)
End Function
    Private Sub ProgressForm_Load(ByVal sender As Object, ByVal e As EventArgs)
Me.progressBar1.Style = ProgressBarStyle.Continuous
Me.progressBar1.Step = 1
Me.button1_Click(Me, New EventArgs)
End Sub
    Public Sub ShowProgress()
Me.button1_Click(Me, New EventArgs)
End Sub
    Private Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
Dim ordersCount As Integer = &H3E8 ' decimal 10000
Dim i As Integer
For i = 0 To ordersCount - 1
Me.worker.ReportProgress(i) ' update the UI for the user.
'PerformStep() ' alternate means to update UI that uses Control.InvokeRequired
Thread.Sleep(5) ' simulate a time consuming task.
Next i
e.Result = "File Transfer Completed"
End Sub
    Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
Me.progressBar1.PerformStep()
End Sub
    Private Sub worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
If (Not e.Error Is Nothing) Then
MessageBox.Show(e.Error.Message, "File Transfer Failed", MessageBoxButtons.RetryCancel)
Else
Dim s As String = CType(e.Result, String)
MessageBox.Show(s, "File Transfer Completed", MessageBoxButtons.OK)
End If
MyBase.Close()
End Sub
  
' Fields
Private button1 As Button
Private components As IContainer
Private progressBar1 As ProgressBar
Private worker As BackgroundWorker = New BackgroundWorker
    ' Nested Types
Public Delegate Sub Action()
End Class
 
 
 
  
Tags What's this?: Add a tag
Flag as ContentBug
Error in sample computing Fibonacci Number      MrPerphekt   |   Edit   |   Show History
In case anyone is interested in the Fibonacci calculation portion of this code be aware that the code in the article will result in an incorrect answer. In the ComputeFibonacci method where it says

if ( n < 2 )
result = 1;

Should be

if ( n <= 2 )
result = 1;
Tags What's this?: Add a tag
Flag as ContentBug
Processing
© 2010 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement
Page view tracker