WPF线程错误

时间:2012-03-06 11:56:08

标签: c# wpf multithreading thread-safety

我在WPF中使用EmguCV并且我发现这个示例tp捕获图像,我想在我的其他方法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;
        }
    }

4 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:1)

根据您的描述,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);
}


}

答案 2 :(得分:1)

在计时器事件(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 

        }
    }}));
}

答案 3 :(得分:1)

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