billy_flow
billy_flow

Reputation: 81

Display WPF Image in backgroundworker

I am using WPF 3.5.

I have while loop in a backgroundworker_DoWork event, which will continuously stream images from a DSLR.

Initially, the streamed image will be displayed in a PictureBox

<Grid>
    <WindowsFormsHost VerticalAlignment="Top" Background="Transparent" Height="500">
        <wf:PictureBox x:Name="picLiveView" />
    </WindowsFormsHost>
</Grid>

Here is the code behind:

        while (!liveViewExit)
        {
            try
            {
                if (picImage != null)
                    lock (mylock)
                    {
                        this.picLiveView.Image = (Image)picImage.Clone();
                    }
            }
            catch
            {

            }
        }

This works fine.

However, when I try to change the PictureBox to WPF Image control, I have this error when I assigned the BitmapImage to the WPF image control:

{"The calling thread cannot access this object because a different thread owns it."}

        MemoryStream ms = new MemoryStream();
        bmp.Save(ms, ImageFormat.Png);
        ms.Position = 0;
        BitmapImage bi = new BitmapImage();
        bi.BeginInit();
        bi.StreamSource = ms;
        bi.EndInit();

        try
        {
            if (bi != null)
            {
                this.imageBox.Source = bi;
            }
        }
        catch
        {

        }

Why the .NET 2 PictureBox control works while .NET 3.5 WPF Image control doesn't?

I tried this code:

BackgroundWorker bg = new BackgroundWorker();
Dispatcher disp = Dispatcher.CurrentDispatcher;
bg.DoWork += (sender, e) =>
{
    // load your data
    disp.Invoke(new Action(/* a method or lambda that do the assignment */));
}
bg.RunWorkerCompleted += anotherMethodOrLambda; // optional
bg.RunWorkerAsync(/*an argument object that will be visible in e.Argument*/);

It doesn't have any error, but the image doesn't refresh. The while loop make the application not responding.

Upvotes: 0

Views: 3415

Answers (1)

BertuPG
BertuPG

Reputation: 653

you need to instantiate a Dispatcher object in main thread, and use it in the background worker, calling it's Invoke method.

Here's a sample of code:

BackgroundWorker bg = new BackgroundWorker();
Dispatcher disp = Dispatcher.CurrentDispatcher;
bg.DoWork += (sender, e) =>
{
    // load your data
    disp.Invoke(new Action(/* a method or lambda that do the assignment */));
}
bg.RunWorkerCompleted += anotherMethodOrLambda; // optional
bg.RunWorkerAsync(/*an argument object that will be visible in e.Argument*/);

Upvotes: 2

Related Questions