我正在使用线程从网站获取图像并将其拍摄回父图像(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中修复此问题?
答案 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