murmansk
murmansk

Reputation: 845

WPF threading error

I am using EmguCV in WPF and i found this example tp capture image , I want to use bs1 in my some other method Method3(), but i am getting error that object belong to some other thread, anyone has any idea what is the problem ? bs1 is after all a global variable

  BitmapSource bs1;

 private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        capture = new Capture();       ///capture image

        timer = new DispatcherTimer();       // timer object
        timer.Interval = new TimeSpan(500);
        timer.Tick += new EventHandler(timer_Tick);
        timer.Start();

    }
    void timer_Tick(object sender, EventArgs e)
    {
        using (  Image<Bgr, byte> Frame = capture.QueryFrame())
        {
            if (Frame != null)
            {
                bs1 = ToBitmapSource(Frame);
webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource webcam is a picture in mainwindow
                 Frame.Save("fg.jpeg");   //this work but use lot of processing 

            }
        }
    }


public void Method3_click (...)
{
    use_of_bs1(bs1);
}


  private void use_of_bs1()
    {

        data.Text = "waiting...";

        System.Threading.ThreadPool.QueueUserWorkItem(Startwork);
    }


    private void Startwork(object state)
    {

        try
        {
            _work = _worker.bs1_analysis(bs1);      // it is where bs1 giving thread errorbs1_analysis is library function
        }
        catch (Exception ex)
        {
            Dispatcher.BeginInvoke(new ShowworkInformationDelegate(ShowworkInformation));
            MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            return;
        }
        Dispatcher.BeginInvoke(new ShowWorkInformationDelegate(ShowWorkInformation));

    }

/// ToBitmapsource function is

public static BitmapSource ToBitmapSource(Emgu.CV.IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap();
            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ptr, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(ptr);
            return bs;
        }
    }

Upvotes: 0

Views: 758

Answers (4)

user180326
user180326

Reputation:

If you create a wpf resource and want to use it on a different thread, you can call Freeze() on the object before passing it on. That will make it immutable and legal to use on another thread.

Upvotes: 1

GETah
GETah

Reputation: 21449

In WPF, UI elements can only be accessed and used by the same thread that created them (except for freezable elements). In your code, bs1 is created in the main UI thread. The timer being a different thread cannot access that resource. Whenever you want to do something with a UI element that is created on the main UI thread, do the following:

Dispatcher.Invoke(DispatcherPriority.Normal, new Action(()=>DoSomeCodeWithUIElement()));

Use Dispatcher.Invoke if you want the operation to run synchronously or Dispatcher.BeginInvoke if you want the asynchronous call. Where DoSomeCodeWithUIElement is a method in which you access and eventually update UI elements.

Upvotes: 2

dcarneiro
dcarneiro

Reputation: 7180

On the timer event (timer_Tick) you're on a different thread that the one where bs1 belongs

You need to execute the event on the main thread. Something like:

void timer_Tick(object sender, EventArgs e)
{
    Dispatcher.Invoke(DispatcherPriority.Normal,
            new Action(
                delegate {
    using (  Image<Bgr, byte> Frame = capture.QueryFrame())
    {
        if (Frame != null)
        {
            bs1 = ToBitmapSource(Frame);
            webcam.Source = ToBitmapSource(Frame); // ToBitmapSource convert image to bitmapsource
            Frame.Save("fg.jpeg");   //this work but use lot of processing 

        }
    }}));
}

Upvotes: 1

Toan Nguyen
Toan Nguyen

Reputation: 11601

From what you have described, the bs1 was associated with the Window.Dispatcher, so when you accessed it inside Method3(), there was an exception raised. To fix that issue, you could do something like this

public void Method3()
{
    Action<BitmapSource> useBs1 = (source) =>  use_of_bs1(source);
    if(Thread.CurrentThread == this.Dispatcher.Thread)
      {

    useBs1(bs1);
}
else
{
   this.Dispatcher.Invoke(DispatcherPriority.Normal,userBs1, bs1);
}


}

Upvotes: 1

Related Questions