WPF线程错误

本文关键字:错误 线程 WPF | 更新日期: 2023-09-27 18:26:46

我在WPF中使用EmguCV,我发现了这个例子来捕捉图像,我想在我的其他方法Method3()中使用bs1,但我得到了一个错误,即对象属于其他线程,有人知道问题出在哪里吗?bs1毕竟是一个全局变量

  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函数是

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;
        }
    }

WPF线程错误

在WPF中,UI元素只能由创建它们的同一线程访问和使用(可冻结元素除外)。在您的代码中,bs1是在主UI线程中创建的。作为其他线程的计时器无法访问该资源。每当您想对在主UI线程上创建的UI元素执行某些操作时,请执行以下操作:

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

如果希望操作同步运行,请使用Dispatcher.Invoke;如果希望异步调用,则使用Dispatcher.BeginInvoke。其中DoSomeCodeWithUIElement是一种访问并最终更新UI元素的方法。

如果您创建了一个wpf资源,并希望在不同的线程上使用它,那么在传递它之前,您可以在对象上调用Freeze()。这将使它不可变,并且在另一个线程上使用是合法的。

根据您所描述的,bs1与Window.Dispatcher相关联,因此当您在Method3()中访问它时,会引发异常。为了解决这个问题,你可以做一些类似的事情

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);
}

}

在计时器事件(timer_Tick)上,您所在的线程与bs1属于的线程不同

您需要在主线程上执行事件。类似于:

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 
        }
    }}));
}