Multithreading in WPF

If you’re unfamiliar with multithreading, be sure to check out my previous entries on the topic.

In WPF, creating a thread is as easy as it is with C#. You can find an example on that here.  Alternatively, you could use the BackgroundWorker, which basically will create a thread and will give you a generalized, simplified interface in which to interact with it for a common threading task: doing an extra task in the background (such as downloading or progress bar updating).

In an earlier post, I used a mysterious method to enable responsiveness in the UI while loading a bunch of content (in that case, images).

This mystical object is called The Dispatcher.

THE DISPATCHER

No, this isn’t an edge-of-your-seat thrill ride movie that smacks explosions, swords, and alien guts into your M&M-filled mouth. It is an object used to manage the work for threads within WPF.  It maintains a queue of work items that are requested of any given thread, based on their order and priority.  This is the object you want to get to know if you’re going to be playing with your UI on a separate thread.

As mentioned previously, UI objects can’t be accessed outside of the threads that created them.  You can, however, use a separate thread to determine what changes you’ll be making and to what objects you will make them, then use their thread to actually apply that change.  In order to do this, use the object’s dispatcher to schedule the work on their queue.

For example, take a look at the code for loading images mentioned above:

private void LoadImage(string fname)
{
	// instantiate and initialize the image source
	BitmapImage bmi = new BitmapImage();
	bmi.BeginInit();
	bmi.UriSource = new Uri(fname, UriKind.Relative);
	bmi.EndInit();
 
	bmi.Freeze();		// freeze the image source, used to move it across the thread
 
	// this method tells the separate thread to run the following method to run on the UI thread
	// the (ThreadStart)delegate(){ } notation is a shorthand for creating a method and a delegate for that method
	TheImage.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (ThreadStart)delegate ()
	{
		TheImage.Source = bmi;
	});
}

This method creates the BitmampImage object on a separate thread, leaving the main thread free for user input, and freezes it so that it can be used on another thread.  It then uses TheImage’s Dispatcher to modify TheImage on its own thread by calling its dispatcher’s BeginInvoke method.

There are two ways to invoke using the dispatcher: BeginInvoke() and Invoke().  BeginInvoke() will queue the work for the dispatcher and continue the separate thread’s execution.  It puts in the request for the UI thread to execute the delegate, then continues on it merry way for its own execution.  This is useful when your separate thread does not rely on what it is requesting the UI thread to do.

The Invoke() method will wait until the delegate is executed and returns.  If you are modifying anything that you need or if the modification must be done before continuing in the separate thread, you should go with this one.

The Dispatcher is something you’ll get pretty cozy with if you plan on changing your UI elements from a separate thread.  If you’re just doing a progress bar or something else that is rather predictable, you can skip it by using the BackgroundWorker’s ReportProgress method and ProgressChanged event.  Just be sure to give it some time if you are calling the dispatcher often.

In case you didn’t notice all of my linking to previous posts, you may want to check out the rest of my posts on multithreading.