C# 从BackgroundWorker线程更新图像UI属性
在我正在编写的WPF应用程序中,我有一个TransformedBitmap属性,它绑定到UI上的图像对象。每当我更改此属性时,图像都会更新(因此显示在屏幕上的图像也会更新)。为了防止在检索下一个图像时UI冻结或变得无响应,我尝试使用BackgroundWorker进行快照检索,如下所示:C# 从BackgroundWorker线程更新图像UI属性,c#,wpf,multithreading,image,backgroundworker,C#,Wpf,Multithreading,Image,Backgroundworker,在我正在编写的WPF应用程序中,我有一个TransformedBitmap属性,它绑定到UI上的图像对象。每当我更改此属性时,图像都会更新(因此显示在屏幕上的图像也会更新)。为了防止在检索下一个图像时UI冻结或变得无响应,我尝试使用BackgroundWorker进行快照检索,如下所示: private void bw_DoWork(object sender, DoWorkEventArgs e) { e.Result = this.snapshotHelper.GetSnapshot(I
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = this.snapshotHelper.GetSnapshot(ImageFormat.Bmp);
}
然后,在我的RunWorkerCompleted方法中,我有以下内容:
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.CurrentImage = (TransformedBitmap)e.Result;
....
}
在我更新CurrentImage属性时,NotifyPropertyChanged方法用于告诉Image对象要更新之前,这似乎可以正常工作;我得到一个跨线程错误
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
//The following causes a "the calling thread cannot access this object because a different thread owns it" error!
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
我真的不知道如何改变周围的事物,或者如何做不同的事情来避免这个错误。在过去的几个小时里,我一直在阅读有关BackgroundWorkers的文章,在我看来,我应该能够在RunWorkerCompleted方法中设置CurrentImage;至少从我能说的来看。在此方面的任何帮助都将不胜感激!谢谢 仅允许dispatcher与UI交互。请看这里: 控件(图像)只能在创建它的线程上更改。因此,基本上,您的后台线程会更改对象上的属性,从而触发PropertyChanged事件,然后WPF会使用该事件,然后WPF会尝试修改图像控件(请记住,在整个事件链中,我们仍然在后台线程上) 幸运的是,修复非常简单:
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
myWindow.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate()
{
this.CurrentImage = (TransformedBitmap)e.Result;
....
});
}
您需要一个对窗口或控件的引用才能工作,但这实际上是将委托排队,以便在UI线程而不是后台线程上运行
Dispatcher.Invoke((Action<TransformedBitmap>) (obj => this.CurrentImage = obj), e.Result as TransformedBitmap);
然后在RunWorkerCompleted中,您更新了我上面所写的属性。这实际上导致了“异常已由调用的目标引发”错误……这可能是因为它被WPF包装在某个地方,但我猜InnerException将包含跨线程冲突异常。我刚刚找到它;你是对的,确实如此……那么这个修复对这个案子根本不起作用?使用Dispatcher.Invoke()执行上面提到的操作会导致“异常已由调用的目标引发”,并且它的InnerException是同一个跨线程错误。所以我真的不知道现在该怎么办;我只是遗漏了一些基本的东西吗?我想你可能遗漏了一些东西,如果你想给我发电子邮件(标记在warpool.org),我很乐意查看你的代码,看看我是否能进一步提供帮助。这也导致了“异常已由调用的目标引发”这反过来仍然包含相同的跨线程错误。请参阅更新我的答案。我已经处理了这个问题,它是有效的。
void worker_DoWork(object sender, DoWorkEventArgs e)
{
var bmp = snapshotHelper.GetSnapshot(ImageFormat.Bmp);
bmp.Freeze();
e.Result = bmp;
}