Tuesday, May 15, 2012

BackgroundWorker Component - "I'm Not Dead, Yet!"

The BackgroundWorker component is one of those things that I wish someone had told me about earlier.  One thing that surprises me is that the a blog article I wrote 2-1/2 years ago still gets regular hits (Introduction to the BackgroundWorker Component in .NET), and the corresponding walkthrough and code samples are some of the most-viewed items on my website.

The BackgroundWorker has been around since .NET 2.0, and some people argue that it's an archaic component that needs to be deprecated.  But in reality, the BackgroundWorker fills a very specific niche and does it very well.

What's Good About the BackgroundWorker
The BackgroundWorker is all about keeping your UI responsive during a long-running process.  There is no reason for a UI to "lock up" in an application.  If you find that there times when the UI is non-responsive, it is time to take a look at the BackgroundWorker.

Single Purpose
The BackgroundWorker is simply about moving a long-running process off of your UI thread so that your UI remains responsive.  If that's what you're trying to do, then it works great.

The BackgroundWorker consists of 3 methods, 4 properties, and 3 events.  That's it.  This makes it very easy to learn the ins and outs of the component.  There just isn't that much there to learn.

Event Driven
The BackgroundWorker is event-driven.  Specific events fire on the background thread, and other events fire on the UI thread.  Event-handling is a straight-forward process that practically all .NET developers understand.

The BackgroundWorker is a component (from System.ComponentModel).  Because of this, you can add the BackgroundWorker as a non-visual component to a WinForms application or as a resource in a XAML application.  This gives you the ability to use the Properties Window to hook up the events and set the properties.

Concealed Threading
The BackgroundWorker handles all of the threading for you.  It creates the background thread and starts the appropriate process on it.  It handles the marshaling between the background thread and the UI thread.  As a programmer, you never actually see these threads, nor do you need to keep track of them.

Full Featured
The BackgroundWorker has ways to handle showing progress (through a progress bar or other UI element), to get data from the background thread back to the UI thread, to handle cancellation of the background process, and to expose exceptions that happen on the background thread to the UI.

Multiple Platforms

The BackgroundWorker is supported in the full .NET framework, the .NET 4.0 Client Profile, Silverlight, and Windows Phone 7.  This means that you can use it with any of your smart-client technologies.

What the BackgroundWorker is Not
As mentioned above, the BackgroundWorker is great for keeping the UI responsive.  But it is not a replacement for the other threading options that are out there.  It is not a replacement for the Task Parallel Library (TPL).  TPL is really about running multiple processes in parallel; the BackgroundWorker is about moving one process off of the UI thread.

At the same time, it is not a replacement for the "await" keyword that we get with .NET 4.5.  Again, "await" can be used in a variety of circumstances (such as running an asynchronous process on a server).  If the process doesn't involve a smart-client UI (WinForms or XAML), then the BackgroundWorker is probably not the best choice.

It is not a replacement for more complex thread-management.  If you need to control thread-lifetime, manage the re-use of threads, or have complex resource management, then spinning up your own threads is probably the better choice.  The BackgroundWorker hides these things (to make things simple).  As always, we need to take a look at our problem and pick the right tool for the job.

How I Used It
As I mentioned, the BackgroundWorker is one of those things that I wish I had known about before.  I'm still surprised at how many people are not familiar with this useful little tool.  I was able to make good use of it in a reporting application.  I had an application that needed to run a variety of Crystal Reports that were backed by SQL Stored Procedures running against live data.  The unfortunate thing is that the reports took a long time to run (from 5 to 15 minutes depending on the parameters).  I could not have the UI "lock up" during that time; the users would just kill the non-responsive application.  Instead, I was able to use the BackgroundWorker to run the report in the background.  The UI remained responsive, and I even provided a counter so that the user could see that the application was still "ticking".

BackgroundWorker and MVVM
A while back, I was asked whether the BackgroundWorker component could be used with the MVVM design pattern (BackgroundWorker Session Questions).  After thinking about this for a bit, the answer I came to was "yes", the BackgroundWorker could be used with the MVVM pattern.

Remember that even though the View, ViewModel, and Model are all separate parts when using the MVVM pattern, they will all run on the same thread (unless you code things specifically to do otherwise).  This means that if you have a long-running process in the ViewModel or the Model, you can easily lock-up your UI.

I did some more noodling-around on this today.  I took the sample code from my BackgroundWorker session (available here: Keep Your UI Responsive with the BackgroundWorker Component) and re-organized the application using the MVVM pattern.  I found that the BackgroundWorker still works just as well.  I placed the BackgroundWorker in the ViewModel, ran a long-running process from the Model, and updated ViewModel properties that were databound to the UI (such as the progress bar and output text box).

You can see that this application looks and operates just the same as the original sample.  I'll describe how this code differs from the original application in the next article.  Until then...

Happy Coding!

No comments:

Post a Comment