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.
Pingback: Multithreading in WPF | Andrew Eichacker
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?
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.
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.)
That’s a good point to raise – it is good practice to check if an object that implements Freezable actually can be frozen.
As for why your BitmapImage can’t be frozen, the most common issue that I’ve found through a quick search is that the BitmapImage hasn’t yet finished downloading the bits for the Image. Here’s a post that looked helpful:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/282946ed-09dc-418e-b9bc-99c999344735