Reputation:
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! :)
Upvotes: 0
Views: 2618
Reputation:
@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....
Upvotes: 0
Reputation: 29594
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.
Upvotes: 5
Reputation: 27055
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(); } )
);
Upvotes: 0
Reputation: 2018
I had the same problem 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.
Upvotes: 0