从BackgroundWorker线程更新Image UI属性

时间:2010-09-13 19:15:52

标签: c# wpf multithreading image backgroundworker

在我写的WPF应用程序中,我有一个TransformedBitmap属性,它绑定到UI上的Image对象。每当我更改此属性时,图像都会更新(从而更新显示在屏幕上的图像)。为了防止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属性时用于告诉Image对象更新的NotifyPropertyChanged方法;我遇到了一个跨线程的错误。

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。至少从我能说的来看。任何有关这方面的帮助将不胜感激!谢谢!

3 个答案:

答案 0 :(得分:2)

控件(Image)只能在创建它的Thread上更改。基本上发生的事情是你的后台线程改变你对象的属性,然后它会触发PropertyChanged事件,然后由WPF使用,然后WPF尝试修改Image控件(记住我们仍然在整个链中的BackgroundThread上)事件)。

幸运的是,修复非常简单:

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  myWindow.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(delegate() 
     {
        this.CurrentImage = (TransformedBitmap)e.Result;
        ....
     });
}

您需要对Window或Control的引用才能生效,但这实际上将委托排队,以便在UI线程而不是后台线程上运行。

答案 1 :(得分:2)

Dispatcher.Invoke((Action<TransformedBitmap>) (obj => this.CurrentImage = obj), e.Result as TransformedBitmap);

这应该有用......

<强>更新

在您的情况下,您使用的是freezable对象,并且您在创建的位图中的问题需要在UI线程中发送之前冻结。所以DoWork将如下:

void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var bmp = snapshotHelper.GetSnapshot(ImageFormat.Bmp);
            bmp.Freeze();
            e.Result = bmp;            
        }

然后在RunWorkerCompleted中更新我上面写的属性。

答案 2 :(得分:0)

只允许调度程序与UI进行交互。看看这里:

http://www.jeff.wilcox.name/2010/04/propertychangedbase-crossthread/