问题描述
当WPF的应用程序(.net6),打开图像时,图像会被锁定,这会导致其他程序无法修改(比如重命名,删除,覆盖等),提示如下:
无法重命名:
无法覆盖旧图像:
问题分析和解决
这里是动态加载图像到Image组件的代码:
public void ReloadImage(string imagePath)
{
this._ResetImageTransform();
ImagePath = imagePath;
if (ImagePath != string.Empty && File.Exists(ImagePath))
{
var imgUrl = new Uri(ImagePath, UriKind.Absolute);
PreviewImg.Source = new BitmapImage(imgUrl);
ImageOriginWidth = PreviewImg.Source.Width;
ImageOriginHeight = PreviewImg.Source.Height;
}
else
{
PreviewImg.Source = null;
ImageOriginWidth = -1;
ImageOriginHeight = -1;
}
}
直接从文件加载BitmapImage
时,文件会被锁定,直到图像被释放(即使是加载了图像的子窗口关闭了也不会释放;或者是把PreviewImg.Source设置为null,也是无法释放;必须等到主窗口关闭才能释放)。
为了避免这种情况,最简单的方法是从流加载映像,并将CacheOption
设置为OnLoad
。比如
using (var stream = File.OpenRead(filename))
{
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = stream;
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
this.BarcodeImage.Source = bmp;
}
或者直接把图像加载到内存,然后断开内存中的图像和外部的真实图像之间的联系:
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.UriSource = new Uri(ImagePath, UriKind.Absolute);;
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.EndInit();
this.BarcodeImage.Source = bmp;
下面是修改后的代码:
public void ReloadImage(string imagePath)
{
this._ResetImageTransform();
ImagePath = imagePath;
if (ImagePath != string.Empty && File.Exists(ImagePath))
{
var imgUrl = new Uri(ImagePath, UriKind.Absolute);
var source = new BitmapImage();
source.BeginInit();
source.UriSource = imgUrl;
source.CacheOption = BitmapCacheOption.OnLoad;
source.EndInit(); // Required for full initialization to complete at this time
PreviewImg.Source = source;
ImageOriginWidth = PreviewImg.Source.Width;
ImageOriginHeight = PreviewImg.Source.Height;
}
else
{
PreviewImg.Source = null;
ImageOriginWidth = -1;
ImageOriginHeight = -1;
}
}
问题解决。
扩展
System.Windows.Media.Imaging.BitmapCacheOption
是C# WPF框架中的一个枚举类型,用于指定位图缓存选项。它提供了不同的缓存策略,以便在加载和显示位图时进行优化。
BitmapCacheOption Enum (System.Windows.Media.Imaging) | Microsoft Learn