It's a rule that should never be forgotten - don't ever perform work that takes a non-trivial amount of time on the UI thread. Of course you're now wondering, "Where do I perform tasks that take a non-trivial amount of time?". The answer is simple - on a different thread. There are lots of ways to get your work onto another thread, which can include directly creating a Thread or using the ThreadPool. This tutorial, however, will introduce you to .NET's BackgroundWorker class and how it can be used to get the job done.
The other common techniques, such as using Thread or Threadpool, have the downside that you're explicitly required to invoke the Dispatcher whenever you need to update the user interface. The BackgroundWorker class does the invocation for you, which can make things a little nicer.
Below is a Silverlight application that demonstrates the usefulness of performing work on background threads. Remember though, that the code I used here is not specific to Silverlight - it will work on any .NET v2.0 or higher application.
The first thing we're going to take a look at is the function that gets called when you the click the UI thread button.
As you can see, I simply loop through 5 iterations of "work". Each piece takes 1 second to complete. I simulate actual work by using a sleep. If you ran the example, you'll notice that you don't actually get any progress updates whatsoever. This is because the UI thread is completely tied up doing your work and doesn't have any time for itself to redraw the screen. If this were an actual desktop application, the user would experience a frozen program that no longer responds.
Now let's check out the other example:
There's quite a bit more code here, but unlike the previous example, this one does update the user interface as work is being completed. The setup for the BackgroundWorker object should be pretty straight forward. If you want the object to be able to report progress (which we do) you'll need to make sure to set the property, WorkerReportsProgress, to true. If you don't, you'll get an exception when you attempt to report progress.
Most of the logic for a BackgroundWorker class is split among three events: DoWork, ProgressChanged, and RunWorkerCompleted. DoWork is called when the BackgroundWorker is ready to do some work. It's also where you should put all of the code you'd like executed on the background thread. In this example, it does the exact same work as the previous one, except now it invokes ReportProgress when it wants to notify the UI.
The ProgressChanged event gets fired when when ReportProgress is called. This event is automatically dispatched to the UI thread, so there's no need to use invoke to update user interface elements. In my example, I simply update the progress bar's value to the reported progress.
The last event, RunWorkerCompleted, is pretty self-explanatory. When the background thread exits, the event will be fired.
And that's it. Using the BackgroundWorker class is very simple, but has the potential to make your application much more responsive. By not requiring the use of invokes, it is sometimes a better choice that more mainstream background processing techniques. You can download a Visual Studio 2008 solution with all of the source code for my example below.