1

I'm working on a project where we need to capture and process images in order to control a robot. Those two things are working just fine.

What I can't seem to be able to figure out is how to use WPF to display the pre- and post-processing images.

I have an app that is using this code:

public CamNotification(string label1, string label2, BitmapSource image1, BitmapSource image2)

private bool hwLink_SetInfos(CamNotification info)
{
    try
    {
        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
        {
            lblText1.Content = info.Label1;
            lblText2.Content = info.Label2;

            ImageBox1.Source = info.Image1;
            ImageBox2.Source = info.Image2;
            InvalidateVisual();
        }));
        return true;
    }
    catch (Exception ex)
    {
        Debugger.Break();
        return false;
    }
}

It changes both the labels describing the images and the 'image.source's themselves.

It works ->fine<- when I use a WPF-button to call the code, but when I try it using a WorkerThread from a Threadpool that replaces the two 'image.source's the images are not displayed, even though the labels are.

Moreover, if I have already pressed the button and the pictures were displayed, a call from the ->WorkerThread<- that ends up in the MainThread removes the images and leaves a blank area instead of updating them to the new content.

Using the Dispatcher I have already removed all crossthead-issues, Labels are updated but the "PresentationFramework -> System.Windows.Controls.Image" is cleard and not updated :-(

While looking through stackoverflow I found this question:

WPF imaging problems

It seems to be concerned with a problem similar to mine. However, neither the answers nor the OPs comment about how he solved his problem have helped me.

I would appreciate any help you could give me.

Community
  • 1
  • 1
  • It sounds like an issue with the image not being frozen. Did you try calling info.Image1.Freeze() and info.Image2.Freeze() before setting the source? – Tone Apr 05 '16 at 19:25
  • 1
    @Tone That was it. Thank you very much. For those interested: I put info.image1.Freeze() and info.image2.Freeze() after the try{ but before the Dispatcher. Works like a charm now ^^ – Shane Lyndon Sale Apr 06 '16 at 09:40
  • Good to hear. I've added a full answer for reference. – Tone Apr 06 '16 at 17:03

1 Answers1

0

BitmapImageSource is a freezable object which should be be frozen if you intend to access it across threads

From MSDN

A Freezable provides a Changed event to notify observers of any modifications to the object. Freezing a Freezable can improve its performance, because it no longer needs to spend resources on change notifications. A frozen Freezable can also be shared across threads, while an unfrozen Freezable cannot.

...

A freezable's Freeze method enables you to disable this self-updating ability. You can use this method to make the brush become "frozen," or unmodifiable.

As you're working with the images on another thread, you need to change your code to call Freeze() before it can be used on the UI thread. Some working code below

public CamNotification(string label1, string label2, BitmapSource image1, BitmapSource image2)

private bool hwLink_SetInfos(CamNotification info)
{
    try
    {
        info.Image1.Freeze();
        info.Image2.Freeze();

        Application.Current.Dispatcher.BeginInvoke((Action)(() =>
        {
            lblText1.Content = info.Label1;
            lblText2.Content = info.Label2;

            ImageBox1.Source = info.Image1;
            ImageBox2.Source = info.Image2;
            InvalidateVisual();
        }));
        return true;
    }
    catch (Exception ex)
    {
        Debugger.Break();
        return false;
    }
}

A couple of related articles:

How do you pass a BitmapImage from a background thread to the UI thread in WPF?

In what scenarios does freezing WPF objects benefit performance greatly?

Community
  • 1
  • 1
Tone
  • 1,701
  • 1
  • 17
  • 18