There are already a lot of articles, out there in the cloud, about how to use delegates because Windows Forms’ thread safety prevents a worker thread from updating it’s interface, yada, yada, yada.
Then .NET 2.0 introduced the BackgroundWorker component that addresses the issue quite elegantly.
Although there are a few articles about this also, I realize no-one talks about passing “real” data and not just “percent done” through the Progress Updates, so I will attempt to cover that in this post.

Let’s start with a quick summary…
Problem: Perform a time-consuming operation without killing the responsiveness of a Windows Form.
During the operation, display operational data, not just progress percentage, to the user.

Solution: Drop a BackgroundWorker component (found in the components area in the Toolbox) onto the Windows Form.

Double-clicking the component will take you into a DoWork event. This event is raised when you call the RunWorkerAsync method. Note, you can pass in a parameter (which could be a business object of yours) into this method.

For e.g. backgroundWorker1.RunWorkerAsync(person);

This parameter can be retrieved in the event handler as the Arguments property of the DoWorkEventArgs parameter.

private void backgroundWorker1_DoWork(object sender,  DoWorkEventArgs e)
{
    Person person = (Person) e.Argument;
}

If you’d like to report progress during the operation, set the WorkerReportsProgress property of the component to True (in the designer). And, set the WorkerSupportsCancellation property if you’d like to support termination while in operation.

In some Initialization area, usually the Form constructor, chain-in corresponding event handlers, like so:

backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);

The moment you start typing, notice the VS2008 RAD environment at work…it’s just amazing…auto-completion/generation kicks in and you can pretty much put in an event handler and generate a stub for the event with 2 Tab hits.

To report progress in operation, simply call the ReportProgress method and pass in the required parameters.
This is where we can supply operational data to the application. If you notice, there is an overloaded method that also accepts a UserState object along with the progress percentage value.
You can set the Result propertry of DoEventArgs to any object you like, like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  …
  e.Result = person;

}

… and this can be retrieved downstream in the ProgressChanged event, like so:

private void backgroundWorker1_ProgressChanged(object sender,
    ProgressChangedEventArgs e)
{

    DoWorkEventArgs dw = (DoWorkEventArgs) e.UserState;
    Person p = (Person) dw.Result ;
…}

So, knowing what to type casting is the tricky bit and also note that dw.Arguments can also be used to retrieve the input objects for starting the operation. I hope that clears up the parameter passing bit.

I’d like to end with Cancellation of the Operation in progress. To do that:
– Ensure that the set the WorkerSupportsCancellation property = True
– Then simply set the CancelAsync property of the BackgroundWorker to True
– Check this action flag in your DoWork event via the CancellationPending property of the BackgroundWorker.
– Set the Cancel property of the DoWorkEventArgs to further propagate this cancellation sequence in the ProgressChanged event.

As you can see, this is much cleaner and simpler than the AsyncDelegates one had to use in .NET 1.1. Hope this article helped…

Advertisements