使用WPF图像进行线程处理(System.InvalidOperationException)

时间:2011-05-04 01:12:10

标签: wpf multithreading imagesource

我正在使用线程从网站获取图像并将其拍摄回父图像(WPF)进行显示。我遇到了一个问题,并设法调试它到这个例子:

public void Watch()
{
  while (true)
  {
    Bitmap bmp = new Bitmap(1, 1);
    BitmapImage bmpImg = new BitmapImage();

    this.SetImage(bmp, bmpImg);
  }
}

public delegate void SetImageCallback(Bitmap bmp, BitmapImage bmpImg);

private void SetImage(Bitmap bmp, BitmapImage bmpImg)
{
  if (!this.imgVideo.Dispatcher.CheckAccess())
  {
    SetImageCallback del = new SetImageCallback(SetImage);
    this.Dispatcher.Invoke(del, bmp, bmpImg);
  }
  else
  {
    Bitmap bitmap = bmp;
    BitmapImage bitmapImage = bmpImg;
  }
}

请记住Watch()在自己的线程上运行。如果我使用位图对象(我可以在Window Forms中使用PictureBox)一切都很好。也就是说,当我到达

行时调试这段代码
Bitmap bitmap = bmp;

检查变量bmp,一切都很棒并按预期工作。但是,当我到达下一行时

BitmapImage bitmapImage = bmpImg;

并且在变量bmpImage中,我得到了大量的System.InvalidOperationException。当这在实践中并被分配给WPF Image对象时,它会说“调用线程无法访问此对象,因为另一个线程拥有它”。为什么我在使用WPF BitmapImages(需要设置ImageSource)而不是Windows窗体Bitmap对象(可用于设置PictureBox)时遇到此问题?如何在WPF中修复此问题?

2 个答案:

答案 0 :(得分:3)

WPF中的大多数对象属于这一类:它们不能在不同的线程之间共享。但是,某些低级资源(如画笔和位图)是从名为Freezable的特殊类派生的,如果冻结可以在不同的线程之间共享。当然,一旦对象被冻结,就不能再以任何方式进行修改。要冻结freezable对象,只需调用Freeze,这将阻止跨线程异常。

答案 1 :(得分:1)

而不是

if (!this.imgVideo.Dispatcher.CheckAccess())
  {
    SetImageCallback del = new SetImageCallback(SetImage);
    this.Dispatcher.Invoke(del, bmp, bmpImg);
  }

尝试使用:

if (!App.Current.Dispatcher.CheckAccess())
                App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action<CustomObject>(SetImage),CustomeObjectInstance );

这里Cutom对象将是一个包装类包装

Bitmap bmp, BitmapImage bmpImg

显然,您的SetImage签名将更改为

SetImage(CutomObject custObj)

我没有测试过代码,但这可能会解决问题。 让我们知道这是否有效,以便一些可怜的灵魂可以从这篇文章中受益。 祝一切顺利! SID