异常:BitmapFrameDecode 必须将 IsFrozen 设置为 false 才能修改

Exception: BitmapFrameDecode must have IsFrozen set to false to modify

我有一个用 C# WPF 编写的程序可以自动打印文档。它具有的功能之一是它可以检测图像下载失败,因此不会打印包含空图像的文档。

这是检测 'sender logo' 图片下载失败的代码的一部分:

_senderLogoFrame = BitmapFrame.Create(new Uri(_invoice.Sender.Logo));
_senderLogoFrame.DownloadFailed += BitmapFrameDownloadFailed;
SenderLogo.Source = _senderLogoFrame;

当调用 _senderLogoFrame.DownloadFailed 中的事件处理程序 BitmapFrameDownloadFailed 时,发生此异常:

shippingLabelForm.CreateDocument Exception: Specified value of type 'System.Windows.Media.Imaging.BitmapFrameDecode' must have IsFrozen set to false to modify. Stack Trace: at System.Windows.Freezable.WritePreamble() at System.Windows.Media.Imaging.BitmapSource.add_DownloadFailed(EventHandler`1 value) at InvoicePrintingClient.Form.ShippingLabelForm.SetDataToElements() at InvoicePrintingClient.Form.ShippingLabelForm.d__18.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at InvoicePrintingClient.Main.PrintClientMainWindow.<>c__DisplayClass101_1.<b__4>d.MoveNext()

IsFrozen 设置为 false 是什么意思?它与 BitmapSource.DownloadFailure 事件处理程序有什么关系吗?我必须怎么做才能解决这个问题?

当您使用 Stream 或本地文件 Uri 作为参数调用 BitmapFrame.Create 时(因此它可以立即解码位图),方法 returns 一个冻结的 BitmapFrame。

来自MSDN

Any BitmapFrame returned from a decoder is always frozen. If you require a modifiable copy, you must first create a copy of the BitmapFrame by using the Clone method.

因此您无法修改 BitmapFrame,例如通过为 DownloadFailed 事件附加处理程序。

在附加事件处理程序之前,只需检查 IsFrozenIsDownloading 属性。如果 IsDownloading 为 false.

,附加 DownloadFailed 事件处理程序毫无意义
_senderLogoFrame = BitmapFrame.Create(new Uri(_invoice.Sender.Logo));

if (!_senderLogoFrame.IsFrozen && _senderLogoFrame.IsDownloading)
{
    _senderLogoFrame.DownloadFailed += BitmapFrameDownloadFailed;
}

SenderLogo.Source = _senderLogoFrame;

要检查本地文件 Uri 是否指向可能无效或不存在的图像文件,请将 BitmapFrame.Create 调用放在 try/catch 块中,