I am trying to load an image in the background and then update the UI. I have been playing with this all day and I don’t know what I am missing. I keep getting the following error:
‘The calling thread cannot access this object because a different thread owns it.’
I’ve hunted around following example after example, but I cannot seem to find an answer. I also wrapped the code that is touching the UI in another BeginInvoke.
Update 3: The moral of the story. ImageSource is not thread safe for access.
Update 2: This has got to be a simple solution :). I tried the cloning, but that didn’t result in success, but I did get a different error: ‘Exception has been thrown by the target of an invocation.’
Update 1: I tried the BackgroundWorker, but I am still getting the same error, but it is occurring on the brush.ImageSource.Height. Am I signaling the UI correctly? Any suggestions?
Here is my XAML:
<Window x:Class='Slideshow.Show' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'> <DockPanel> <Canvas Background='Black' Name='canvas'> <Viewbox Name='background' Stretch='Uniform'> <Rectangle name='background' /> </Viewbox> </Canvas> </DockPanel> </Window>
Here is some of the code behind:
namespace Slideshow { public class Show { public Show() { BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted); bw.RunWorkerAsync(); } void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { BitmapSource bitmap = e.Result as BitmapSource; if (bitmap != null) { this.Dispatcher.BeginInvoke(DispatcherPriority.Normal (ThreadStart)delegate() { Image image = new Image(); image.Source = bitmap; background.Child = image; }); } } void bw_DoWork(object sender, DoWorkEventArgs e) { BitmapSource bitmapSource = CreateBrush(GetRandomFile()); e.Result = bitmapSource; } } }
What I tend to use the
ThreadPool.QueueUserWorkItemto load the image, then when the operation completes I call back to the UI thread using the thread-safeDispatcherobject. The image source is not thread safe, you will have to use something like theJpegBitmapDecoder, there is also aPngBitmapDecoder.For Example: