BackgroundWorker
This makes threads easy to implement in Windows Forms. Intensive tasks need to be done on another thread so the UI does not freeze.
With BackgroundWorker
, it is necessary to post messages and update the user interface when the task is done. There is some complexity to this—but it makes sense with an example.
DoWork
Here we must look at the C# view of your file, where we will see the DoWork
method. The backgroundWorker1_DoWork
event is generated when you double-click on DoWork
.
BackgroundWorker
. Look at the gray bar near the bottom of your window. A BackgroundWorker
will appear there.backgroundWorker1
. Click on the backgroundWorker1
item in the gray bar on the bottom. Now, look at the Properties panel.DoWork
.Thread.Sleep
method will pause the execution of the BackgroundWorker
. It will show us threading is functioning.using System; using System.ComponentModel; using System.Windows.Forms; using System.Threading; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Thread.Sleep(1000); // One second. } } }
I want to emphasize the Argument, Result
, and the RunWorkerAsync
methods. These are the properties of BackgroundWorker
required to accomplish anything.
DoWorkEventArgs e Contains e.Argument and e.Result. It is used to access those properties. e.Argument Used to get the parameter reference received by RunWorkerAsync. e.Result Check to see what the BackgroundWorker processing did. backgroundWorker1.RunWorkerAsync Called to start a process on the worker thread.
RunWorkerAsync
We can add arguments and return values to BackgroundWorker
. We need to add arguments, invoke the BackgroundWorker
, and then receive the results of the thread.
public partial class Form1 : Form { public Form1() { InitializeComponent(); // // Example argument object // TestObject test = new TestObject { OneValue = 5, TwoValue = 4 }; // // Send argument to our worker thread // backgroundWorker1.RunWorkerAsync(test); } } /// <summary> /// The test class for our example. /// </summary> class TestObject { public int OneValue { get; set; } public int TwoValue { get; set; } }
DoWork
2Place some code in DoWork
. Then, use the DoWorkEventArgs
in its body and as its result. We hook up the arguments and results from the RunWorkerAsync
call.
TestObject
was passed to RunWorkerAsync
, and that is received as e.Argument
. We also have to cast./// <summary> /// Where we do the work in the program (the expensive slow stuff). /// </summary> private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // // e.Argument contains whatever was sent to the background worker in RunWorkerAsync. // We can cast it to its original type. // TestObject argumentTest = e.Argument as TestObject; // // Boring.... // Thread.Sleep(10000); argumentTest.OneValue = 6; argumentTest.TwoValue = 3; // // Now, return the values we generated in this method. // ... Use e.Result. // e.Result = argumentTest; }
RunWorkerCompleted
You can use the RunWorkerCompleted
event handler by clicking on the backgroundWorker1
icon in the tray. Now double-click in RunWorkerCompleted
.
/// <summary> /// This is on the main thread, so we can update a TextBox or anything. /// </summary> private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // // Receive the result from DoWork, and display it. // TestObject test = e.Result as TestObject; this.Text = test.OneValue.ToString() + " " + test.TwoValue.ToString(); // // Will display "6 3" in title Text (in this example) // }
Call RunWorkerAsync
with an argument. You can pass any argument to this method on BackgroundWorker
, including null
. It simply must inherit from object, which everything does.
DoWork
method. Insert
pause here as your program works.RunWorkerCompleted
is called. In this method, you receive the result.ProgressBar
A ProgressBar
visually displays progress. And the ProgressBar
control in Windows Forms can be used with a BackgroundWorker
.
We implemented the code for a BackgroundWorker
control. We generally instead prefer ThreadPool
when we need many threads. And threads are not always useful.