C# 从BackgroundWorker线程更新图像UI属性

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

在我正在编写的WPF应用程序中,我有一个TransformedBitmap属性,它绑定到UI上的图像对象。每当我更改此属性时,图像都会更新(因此显示在屏幕上的图像也会更新)。为了防止在检索下一个图像时UI冻结或变得无响应,我尝试使用BackgroundWorker进行快照检索,如下所示:

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