WPF:使用ValueConverter为ImageSource创建BitmapImage的内存含义
我在使用图像时遇到问题,并提供了一个右键单击上下文菜单来删除图像。
最初我绑定了绝对文件路径:
其中ImageFileName
类似于C:\myapp\images\001.png
。
我收到错误, The process cannot access the file 'X' because it is being used by another process
。 经过大量的研究,我发现了必要的代码更改。
我使用了Stackoverflow的答案: 删除另一个进程正在使用的文件 ,并将代码放入ValueConverter
。
XAML:
价值转换器:
public class PathToImageConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { try { String fileName = value as String; if (fileName != null) { BitmapImage image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; image.UriSource = new Uri(fileName); image.EndInit(); return image; } return new BitmapImage(); } catch { return new BitmapImage(); } } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
-
我关心的是内存使用情况。 当我向我的容器添加图像时,我看到内存增加。 但是,当我删除图像,并删除基础文件时,我没有看到任何内存被释放。
-
我也一直认为Bitmaps是一种非常低效的文件格式,因为它们是未压缩的,并且与JPEG或PNG文件相比往往是巨大的。
System.Windows.Media.Imaging.BitmapSource
类是否真的从我的PNG中创建了一个未压缩的图像?
首先十分感谢!
菲利普
从URI加载图像时,WPF最多可缓存300个 ImageSource
对象(使用弱引用)。 要避免这种情况,请设置BitmapCreateOptions.IgnoreImageCache
选项或使用FileStream
来加载图像。
请注意,这可能会对应用程序的性能产生负面影响,尤其是在您在虚拟化ListBox
滚动和加载图像的情况下。 但是如果你要加载非常大的图像,你可能想要避免它。
在转换器中使用以下代码( image.Freeze
请注意添加的image.Freeze
调用,它通过使对象成为只读和与线程无关来提高性能):
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { BitmapImage image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; image.StreamSource = fs; image.EndInit(); image.Freeze(); return image; }
另一种可能的性能优化是将DecodePixelWidth
设置为缩小图像。
关于您对格式的关注 – 位图是基于像素的图像的通用名称(与基于矢量的图像相反)。 您提到的文件格式(PNG,JPEG)也是位图,它们只是编码 (可能有一些压缩)。 BitmapImage
类使用WIC对它们进行解码,以便可以在屏幕上呈现它们。
试试这个..
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return Convert(new[] { value }, targetType, parameter, culture); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { try { string imageUri = String.Format((parameter ?? "{0}").ToString(), values); return new BitmapImage(new Uri(imageUri, UriKind.RelativeOrAbsolute)); } catch { return null; } } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); }