[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Use a BackgroundWorker in C#

BackgroundWorker

This example shows how to use a BackgroundWorker component to easily perform a task in the background while the program continues running.

The example Use multiple threads to draw a graph in C# lets you perform an action in the background. Unfortunately using threads directly can be confusing. The BackgroundWorker component provides a slightly easier way to perform a background task.

The key pieces to the BackgroundWorker are:

  • RunWorkerAsync—The UI thread (the main program) calls this method to start the worker.
  • DoWork—The DoWork event is where the worker does its work. It should periodically check its CancellationPending property to see if the UI thread is trying to make it stop. If the worker is stopped, the event handler should set the event's e.Cancel property to true and return.
  • CancelAsync—The UI thread can call this method to tell worker to stop. This sets the worker's CancellationPending to true.
  • ReportProgress—The worker can call this method to pass progress information back to the UI thread.
  • ProgressChanged—This event occurs when the worker calls ReportProgress. The UI thread can update labels, progress bars, and so forth to report progress to the user. (This is a lot easier than using InvokeRequired and Invoke to let a background thread call methods on the UI thread.)
  • RunWorkerCompleted—This event occurs when the worker's DoEvent event handler returns. The UI thread can take action to clean up here. The e.Cancelled property tells whether the worker was stopped (as opposed to finishing its task).

The code for this example is relatively straightforward. The following code starts or stops the BackgroundWorker.

// Use the BackgroundWorker to perform a long task. private void btnGo_Click(object sender, EventArgs e) { if (btnGo.Text == "Go") { // Start the process. lblStatus.Text = "Working..."; btnGo.Text = "Stop"; prgPercentComplete.Value = 0; prgPercentComplete.Visible = true; // Start the BackgroundWorker. bgwLongTask.RunWorkerAsync(); } else { // Stop the process. bgwLongTask.CancelAsync(); } }

When you click the button, the code checks the button's caption to see whether the BackgroundWorker is currently running. If the worker is stopped, the code changes the button's text to Stop, resets the prgPercentComplete progress bar, and calls the worker's RunWorkerAsync method to make it start working.

If the button's caption is Stop, the code calls the worker's CancelAsync method to make it stop.

The following code shows the worker's DoWork event handler.

// Perform the long task. private void bgwLongTask_DoWork(object sender, DoWorkEventArgs e) { // Spend 10 seconds doing nothing. for (int i = 1; i <= 10; i++) { // If we should stop, do so. if (bgwLongTask.CancellationPending) { // Indicate that the task was canceled. e.Cancel = true; break; } // Sleep. System.Threading.Thread.Sleep(1000); // Notify the UI thread of our progress. bgwLongTask.ReportProgress(i * 10); } }

This event handler enters a loop that executes 10 times. Each time through the loop, the code checks the worker's CancellationPending property to see if the UI thread is trying to stop the worker. If CancellationPending is true, the event handler sets e.Cancel to true to indicate that it didn't finish its work and then breaks out of its loop.

If CancellationPending isn't true, the code continues performing the worker's task. In this example, it simply sleeps and then calls the worker's ReportProgress method to report its progress to the UI thread. It passes the ReportProgress method a completion percentage. That makes the following ProgressChanged event handler execute.

// Update the progress bar. private void bgwLongTask_ProgressChanged(object sender, ProgressChangedEventArgs e) { prgPercentComplete.Value = e.ProgressPercentage; }

The ProgressChanged event handler simply updates the program's progress bar by setting its Value property to the completion percentage it receives through its parameters. (And which was set in the call to ReportProgress.)

Finally, when the worker exits its DoWork event handler, the following RunWorkerComplete event handler executes.

// The long task is done. private void bgwLongTask_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (e.Cancelled) { lblStatus.Text = "Canceled"; } else { lblStatus.Text = "Finished"; } btnGo.Text = "Go"; prgPercentComplete.Visible = false; }

This code makes a status label display Canceled or Finished to indicate whether the worker finished its task.

While the worker is doing all of this, the program's Timer executes the following code to display the current time.

// Display the current time. private void tmrClock_Tick(object sender, EventArgs e) { lblClock.Text = DateTime.Now.ToString("T"); }

This may seem fairly complicated, but it's not too bad. The BackgroundWorker uses events to handle calls to the UI thread so you don't have to mess with InvokeRequired and Invoke.

Download the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.