WPF/BackgroundWorker and BitmapSource problem
Asked Answered
M

2

5

I am a beginner with WPF and trying a home project to become familiar with the technology. I have a simple form where the user selects an image file, I then display EXIF data along with a thumbnail of the image. This is working fine but when I select a RAW image file (~9 MB) there can be a slight delay while the thumb loads, so I thought I could use the BackgroundWorker to decode the image and the user can view the EXIF data, then when the image has been decoded it is displayed.

The BitmapSource object is declared in the BackgroundWorkers DoWork method:

worker.DoWork += delegate(object s, DoWorkEventArgs args)
{
    string filePath = args.Argument as string;

    BitmapDecoder bmpDecoder = BitmapDecoder.Create(new Uri(filePath), BitmapCreateOptions.None, BitmapCacheOption.None);
    BitmapSource bmpSource = bmpDecoder.Frames[0];
    bmpSource.Freeze(); //As suggested by Paul Betts

    args.Result = bmpSource;
};

the problem that I'm running into is when I try to set the source of my Image control in the RunWorkerCompleted method I receive an error because the object is owned by another thread.

worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
{
    imgThumb.Source = args.Result as BitmapSource;
};

I tried using the imgThumb.Dispatcher.BeginInvoke() method to set the source but this didn't work either, I guess it's because it's the args.Result that is owned by another thread, and not the imgThumb? How can I get round this?

It could be that I was coding my Dispatcher wrong (the following is from memory, I deleted what I had).

imgThumb.Dispatcher.Invoke(new Action<BitmapSource>(
    delegate(BitmapSource src)
    {
        imgThumb.Source = src;
    }
), bmpSource);

Any suggestions or ideas are welcome.

Update

Changed my DoWork method to use BitmapCreateOptions.None rather than .DelayCreation but now I get the following error when loading RAW files (Canon .CR2 files is all I have tested to date), the code works fine for jpg's. Could this be an issue with the Canon Codec I installed to allow me to display the RAW files?

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Marguritemargy answered 24/1, 2010 at 19:34 Comment(0)
M
8

Call Freeze() on the BitmapSource and you won't have this problem (Freezing gets rid of the threading restrictions, but makes the object immutable)

Mum answered 24/1, 2010 at 19:45 Comment(3)
I added the Freeze() call in my DoWork method, just after setting the BitmapSource value. I then add the following line to the RunWorkerCompleted method: BitmapSource xx = args.Result; which gives me the same error as before. Am I missing anything obvious? I've taken out any code using the Dispatcher.Marguritemargy
I was being a dumbass but now have a diff. error, updated question.Marguritemargy
Even after many years. THANK YOU VERY MUCH. been looking for this all over the netPercolator
F
2

I had exactly the sample problem and was lucky to solve it.

Short answer: wrap in WriteableBitmap. That comes at a little price, thou.

Long answer.

Faery answered 14/12, 2011 at 18:43 Comment(1)
For my case, this was the only solution that worked. I needed to feed a BitmapFrame into a TransformedBitmap. Didn't have control over which thread the BitmapFrame was created on as it is provided by a library (and BitmapFrame's Dispatcher property is null). Even querying the CanFreeze property caused an exception. I had two options: major overhaul of the source code of mine and others, or use WriteableBitmap. Guess which one i chose...Hokeypokey

© 2022 - 2024 — McMap. All rights reserved.