Just a Bit: Loading Images Asynchronously in WPF

Multithreading using WPF is a little tricky at first (I’m planning a more thorough post on that later), but the basic thing you need to know is that you can’t access WPF elements outside of the UI thread, because they aren’t thread safe.  There are some things you can do to speed loading up, however.  Here’s a method for loading images on a separate thread:

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;
	});
}

The meat of the method is the BitmapImage.Freeze method – this is specifically useful for loading images.  The Dispatcher.BeginInvoke is also important, but I’ll leave more explanation on that for the threading post.

5 thoughts on “Just a Bit: Loading Images Asynchronously in WPF

  1. Pingback: Multithreading in WPF | Andrew Eichacker

  2. I need to load multiple large images and I’m using your method (Thanks!). Each call to bmi.Freeze() takes about 10 seconds on my computer. When I try to have two or three BackgroundWorkers call LoadImage at the same time, it seems that I get no performance improvement over having one BackgroundWorker calling LoadImage multiple times successively. It doesn’t seem that this process is CPU bound as far as I can tell by looking at Task Manager. I don’t think it is disk bound either because the files themselves would take less that 2 seconds to read in memory. I’m wondering if Windows is only able to handle one bmi.Freeze at a time. Any ideas?

  3. Wow…10s is very long. Here are a few questions that might help me address your question:

    How large are these images?
    Are there any other tasks being executed while the loading is going on?
    About how many images are being loaded?

    If these images are very large or there are a great deal of them, you might look into image caching to improve the initial load time. Also take a look at BitmapImage.DecodePixelWidth.

  4. I get an exception on the Freeze method saying “This Freezable cannot be frozen.” BitmapImage.CanFreeze is false.

    (Just coming across your blog via Google, good stuff here, subscribed.)

Comments are closed.