WPF调用线程无法使用eventargs访问

时间:2017-08-22 02:56:51

标签: c# wpf

我已经看到了几个解决方案,但他们似乎没有使用eventargs。因此,在Windows窗体中,一个有效的代码:

private void StartButton_Click(object sender, EventArgs e)
    {
        FinalFrame = new VideoCaptureDevice(CaptureDevice[cboDevices.SelectedIndex].MonikerString);
        FinalFrame.NewFrame += FinalFrame_NewFrame;
        FinalFrame.Start();
    }

        private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        pboLive.Image = (Bitmap)eventArgs.Frame.Clone();
    }

但是在WPF中:

private void StartButton_Click(object sender, RoutedEventArgs e){ int capturedeviceindex = cboDevices.SelectedIndex; FilterInfo cd = CaptureDevice[cboDevices.SelectedIndex]; string cdms = cd.MonikerString; FinalFrame = new VideoCaptureDevice(cdms); FinalFrame.NewFrame += FinalFrame_NewFrame; FinalFrame.Start(); }



private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs){ pboLive.Source = ImageSourceForBitmap((Bitmap)eventArgs.Frame.Clone());}
由于

无法正常工作

  

“调用线程无法访问此对象,因为另一个线程拥有它。”

我几乎100%肯定我不知何故应该使用

    this.Dispatcher.Invoke(() => {
...// your code here.});

但是如何使用eventargs?

好的,所以我标记的当前答案出于某种原因工作一次,然后需要重新启动程序。

是否需要显式销毁一些在WPF窗口关闭后保持活动的线程(而调用程序的Word应用程序仍处于活动状态)?

随后它会进入以下代码:

    private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs) { var imageSource = ImageSourceForBitmap(eventArgs.Frame); imageSource.Freeze(); pboLive.Dispatcher.Invoke(() => pboLive.Source = imageSource); }

到最后一行“Dispatcher.Invoke ...”并且似乎处于无限循环而没有在pboLive上显示任何内容

修改。对不起代码格式。这里似乎不允许换行,不要问我为什么。

3 个答案:

答案 0 :(得分:0)

您的“视频设备”会在工作线程上引发FinalFrame_NewFrame事件......因此您已经发现需要使用Invoke来访问pboLive UI线程上的元素...但你需要传递“位图”。

我相信你只需要这个:

    this.Dispatcher.Invoke(
        new Action<Bitmap>(
            (bitmap) =>
            {
                pboLive.Source = ImageSourceForBitmap(bitmap);
            }
        ),
        (Bitmap)eventArgs.Frame.Clone()
        );

如果您在Clone函数中创建BitmapImage,我认为ImageSourceForBitmap是不必要的。

如果您正在使用CreateBitmapSourceFromHBitmap,那么我可以看到您为什么要使用自己的Bitmap副本(其生命周期归视频设备所有)...但您也可以创建一个BitmapImage或类似的东西。

答案 1 :(得分:0)

我在生产代码中看到的模式,使用CheckAccess来阻止不必要的Invoke次调用;

void DoTheThing()
{
    if(Dispatcher.CheckAccess())
    {
        // Do the thing, ie set up the video capture
    }
    else
    {
        Dispatcher.Invoke(DoTheThing);
    }
}

然而,这只是一种模式,用于阐明您应该如何调用Dispatcher.Invoke,并且我鼓励细读其他答案,因为它们更直接地涉及到手头的问题。

答案 2 :(得分:0)

由于在后台线程上调用NewFrame事件处理程序,因此应冻结从ImageSourceForBitmap返回的ImageSource,以使其可跨线程访问。

然后,您将它分配给Dispatcher Action中的Image的Source属性:

private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    var imageSource = ImageSourceForBitmap(eventArgs.Frame);
    imageSource.Freeze();

    pboLive.Dispatcher.Invoke(() => pboLive.Source = imageSource);
}