A Developers introduction to BackgroundWorker Component in .NET 2.0
Intended Readers: Persons having basic knowledge of
multithreading, events and delegates
Platform: .NET 2.0
Level: Intermediate
Introduction
During the design of applications we often encounter problems in which
multithreading or background processing is the appropriate solution. Tasks such
as remote method invocation, File transfers, and database transactions are
common examples.
.NET gives us a class called System.Threading.Thread for playing with
background tasks, worker threads etc. Primary thread of application is
responsible for creating the worker thread and controls its execution with
methods such as suspend, resume etc. This approach has some draw backs such as
- Threading logic is tightly coupled with application
logic, results in-efficient design and less maintainability.
- Progress tracking was very difficult and normally
shared variables are used for keeping track of amount of work completed by
the child thread.
- In order to notify the completion of task, worker
thread calls on or more methods of parent class and if parent class method
contain any UI access statement then system will through an exception
because controls of thread cannot be access by other.
Thread
Pooling
You people
might be wondering that isn’t Thread Pooling a proper solution, although it
shields the thread manipulation logic from the application logic but it is
designed specifically for waitable objects and it doesn’t contain the
completion notification or progress tracking mechanism so what’s next? More here
The Mission
Instead of managing threads and delegates, .NET framework 2.0 introduces a
new component System.ComponentModel.BackgroundWorker
which provides high level and event based access to the background tasks and
threads. From developers point of view its only a component which some
properties, methods and events and we are not concerned with thread management,
progress tracking or completion notification since all is automatically managed
by the component with the help of events and methods (hmmmm Sounds cool).
The process of using BackgroundWorker is quite simple i.e.
- Drag the component from toolbox
- Add the event handler for DoWork event, this is
background tasks.
- Call one or more methods to notify the progress of
tasks.
- Add the event handler for RunWorkerCompleted, means
end of tasks.
Isn’t it
Simple and quick?
Before looking at the proper example of BackgroundWorker, let’s discuss some of
the interested members of it.
- DoWork (Event) Occurs when RunWorkerAsync
method is called, handler of this event act as background thread.
- ProgressChanged (Event) Occurs when worker thread
calls ReportProgress method. This event gets chance to the main thread to
determine the progress of tasks.
- RunWorkerCompleted (Event) Occurs when the background
operation has completed, has been canceled, or has raised an exception all
the finishing logic will be included in the handler of this event.
- CancelAsync (Method) Requests cancellation of a
pending background operation after cancellation of tasks
RunWorkerCompleted event will raise. This is normally called by the Parent
thread.
- ReportProgress (Method) Raises the ProgressChanged
event, normally called by the component it self to inform the parent
thread about the progress.
- RunWorkerAsync (Method) Starts execution of a
background operation by raising DoWork event.
BackgroundWorker
Component in Action
The following demonstrate the use of BackgroundWorker
component, here background tasks takes ten seconds, and after every second it
informs the progress to the main thread. In the end main thread display message
box to inform the user.
Create Windows application in Visual Studio 2005 and add
- Button, starts the background task
- TextBox, which display progress of
worker
- BackgroundWorker component
Following is the code for the
application
public partial class Form1 : Form
{
...
private void button1_Click(object
sender, EventArgs e)
{
// by default progress notification
is false
this.backgroundWorker1.WorkerReportsProgress
= true;
// starts the background task
this.backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork_1(object sender, DoWorkEventArgs
e)
{
MessageBox.Show("Work Start");
for
(int a = 1; a <= 10; a++)
{
System.Threading.Thread.Sleep(1000);
// report progress to the main
thread
backgroundWorker1.ReportProgress(a
* 10);
}
}
private void ProgressChanged(object
sender, ProgressChangedEventArgs e)
{
// update UI
textBox1.Text =
e.ProgressPercentage.ToString();
}
private void WorkCompleted(object
sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Work Done...");
}
}
Advantage of BackgroundWorker
Component
- Less effort on behalf of thread management.
- High level, event based multi-threading.
- Simple and efficient code.
- Support of multiple tasks in one
component, since DoWork is an event we can attach multiple handlers for it
and thread will call each and every handler from the context of worker
thread.
- Since event handlers can be attached or detached at
runtime, and background task is actually an event handler, this means we
can dynamic attach or detach the task (isn’t it cool).
- Support of progress notifications, worker thread can
notify the parent about the percentage of task completed, by firing an
event. Progress handlers can be multiple as well.
Conclusion
BackgroundWorker
provides high level and event based support for creating the background tasks
without involving into the threading issues. It also provides progress
notification for the parent thread which was never there before. One instance
of component also supports multiple tasks as well, and can be changed at
runtime all we need to do is attach an event handler for the DoWork event. Use
of BackgroundWorker component simplifies and improves the overall design of the
application and most important very quickly.
Your Comments and
feedbacks are always welcome