views:

695

answers:

4

I am using the MVVM pattern to develop a WPF application.

The app loads a captcha image from the server, and assigns it to an Image on the WPF form when ready. I am using a BackgroundWorker to do the threading for me, as follows:

When the Window is being loaded, the following is called:

BackgroundWorker _bgWorker = new BackgroundWorker();

_bgWorker.DoWork += GetCaptchaImage;
_bgWorker.RunWorkerAsync();

The GetCaptchaImage function is fairly simply, loading an image in another thread:

BitmapSource _tempBitmap = GetCaptchaFromServer();

I need to know how to Invoke the Dispatcher to assign this ImageSource to my Window's image source, Currently I call the dispatcher after loading the _tempBitmap as follows:

Application.Current.Dispatcher.Invoke(
new Action(() => CaptchaBitmap = _tempBitmap));

Where CaptchaBitmap is databound to my image source.

However, when I do this, an InvalidOperationException is thrown, and any reference to _tempBitmap returns an error in the GUI thread. I know its because I am accessing it from the dispatcher GUI thread, when it was created in a BackgroundWorker thread, but how do I get around it?

Help would be greatly appreciated! :)

A: 

I had the same problem http://stackoverflow.com/questions/1182014/wpf-passing-objects-between-ui-thread-and-background-thread Haven't figured out what "correct" solution is. Ended up replacing my BackgroundWorker with a DispatcherTimer that would run just once and that worked.

Klerk
A: 

Just out of curiousity.. Why don't you do all the retrieving and setting the image in the Dispatcher thread instead of the BackgroundWorker class?

Dispatcher.Invoke(DispatcherPriority.Background,
    new Action(() => { CaptchaBitmap = GetCaptchaFromServer(); } )
);
Arcturus
+4  A: 

Just call BitmapSource.Freeze before calling Dispatcher.Invoke

BitmapSource _tempBitmap = GetCaptchaFromServer();
_tempBitmap.Freeze();
Application.Current.Dispatcher.Invoke(
new Action(() => CaptchaBitmap = _tempBitmap));

All WPF objects can only be accessed from the thread that created them, the exceptions are Dispatcher (for obvious reasons) and Freezable after you call teh Freeze method.

After calling Freeze the object can be accessed from any thread (but can't be modified), luckily for you BitmapSource inherits from Freezable.

Nir
I've been tearing my hair out for the last hour over this problem. Thanks heaps!
Jamie Love
A: 

@Arcturus, From my experience if you do that you won't get any UI responsiveness till the download from the server is complete...because you are actually interupting the UI thread and THEN downloading the stuff...i've been making this mistake in a couple of my projs and wondering why the UI doesn't respond....

Yeah thats true.. thats why I usually do the work stuff in the background thread, so that the UI thread gets the most attentions and keeps updating..
Arcturus