从BackgroundWorker线程更新Image UI属性

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

 Dispatcher.Invoke((Action) (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中更新我上面写的属性。

控件(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线程而不是后台线程上运行。

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

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