A few days ago I wrote an article describing how to create a worker thread for your Windows Forms. Just recently a friend of mine brought to my attention that the .NET Framework contains a component called BackgroundWorker
which helps you to do what I had explained in that article but in an easier and quicker way. So I decided to read up on the BackgroundWorker
component and now I am going to show you how to use it.
The BackgroundWorker
component can be added to your form from the toolbox within Visual Studio. Once you add the component create an event handler for each of its three events – DoWork
, ProgressChanged
, and RunWorkerCompleted
. After doing this you should end up with the below code.
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { } private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { } private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { }
Now just as we did in the Create a Worker Thread for your Windows Form example, let’s add a textbox which displays the progress of a heavy operation, and two buttons, one to start the operation and one to stop it.
Next we’re going to add the code of our heavy operation in the DoWork
event handler of our BackgroundWorker
.
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { // Example heavy operation for (int i = 0; i <= 999999; i++) { // Sleep for 10ms to simulate work System.Threading.Thread.Sleep(10); // Report the progress now this.backgroundWorker.ReportProgress(i); // Cancel process if it was flagged to be stopped. if (this.backgroundWorker.CancellationPending) { e.Cancel = true; return; } } }
As you can see we are iterating for a million times and sleeping for 10 milliseconds on each iteration. Then we are telling the backgroundWorker
component to report its progress to the UI. When we call the ReportProgress
method the ProgressChanged
event is fired. We will be looking at that event handler soon. Finally we are checking the CancellationPending
property to see if the backgroundWorker
was flagged to stop. If it was we are stopping the process by calling e.Cancel = true;
.
The backgroundWorker_ProgressChanged
event handler runs on the UI thread so it saves us the hassle of creating a delegate to access the UI. This is good news because it keeps your code simpler and easier to maintain since there is less code overall. The event handler looks like this:
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Update UI this.txtProgress.Text += " *"; }
Once the backgroundWorker
completes the heavy operation, or is stopped by an error or a manual cancellation, the RunWorkerCompleted
event will fire. Here we can detect why the backgroundWorker
stopped as can be seen below:
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Error != null) { // An error occurred this.txtProgress.Text += Environment.NewLine + "An error occurred: " + e.Error.Message; } else if (e.Cancelled) { // The process was cancelled this.txtProgress.Text += Environment.NewLine + "Job cancelled."; } else { // The process finished this.txtProgress.Text += Environment.NewLine + "Job finished."; } }
We are almost done. What's missing is a way to start and stop the heavy operation. Subscribe to the Click
event for the start and stop buttons we added in the beginning and call RunWorkerAsync()
or CancelAsync()
accordingly as shown below:
private void btnStart_Click(object sender, EventArgs e) { // Start the process on a seperate thread this.backgroundWorker.RunWorkerAsync(); } private void btnStop_Click(object sender, EventArgs e) { // Flag the process to be stopped. // This will not stop the process. // It will only set the backgroundWorker.CancellationPending property. this.backgroundWorker.CancelAsync(); }
Finally we must tell the backgroundWorker
to expect cancellation requests and to report progress. You can do this in your Form_Load
event handler as shown below:
private void Form1_Load(object sender, EventArgs e) { // Tell backgroundWorker to support cancellations this.backgroundWorker.WorkerSupportsCancellation = true; // Tell backgroundWorker to report progress this.backgroundWorker.WorkerReportsProgress = true; }
And that's it. We have created a worker thread without actually creating one since it is done internally by the BackgroundWorker
component. As you can see this method is by far easier to use and unless you need absolute full control over your thread I recommend you use this method instead of manually creating a worker thread yourself.
I hope you enjoyed this article. See you soon.
Dave
hello dave i have problem wite delegate i thing private delegate void UpdateStatusDelegate();
i hope you can help me
Awesome!
but … how to change diferent controls?
/* Not a completed, but till thanks a lot to David.*/
/* I think “how to create a worker thread for your Windows Forms.” is actually much greater and useful article than this one. */
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork;
this.backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
/*Like delegates, you needs to add above method before RunWorkerAsync()*/
this.backgroundWorker1.RunWorkerAsync();
Great article. thank you