2

我正在使用线程从网站获取图像并将其拍摄回父表单 (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() 在它自己的线程上运行。如果我使用位图对象(我可以在窗口窗体中使用 PictureBox),一切都会很好。也就是说,调试这段代码,当我到达该行时

Bitmap bitmap = bmp;

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

BitmapImage bitmapImage = bmpImg;

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

4

2 回答 2

4

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

于 2011-05-04T02:25:30.067 回答
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)

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

于 2011-05-04T11:31:48.777 回答