我已经看到了几个解决方案,但他们似乎没有使用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上显示任何内容
修改。对不起代码格式。这里似乎不允许换行,不要问我为什么。
答案 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);
}