【问题标题】:WPF: Memory implications of using ValueConverter to create BitmapImage for ImageSourceWPF:使用 ValueConverter 为 ImageSource 创建 BitmapImage 的内存影响
【发布时间】:2014-05-18 20:39:30
【问题描述】:

我在使用图像时遇到了问题,我提供了一个右键单击上下文菜单来删除图像。

原来我是绑定绝对文件路径的:

<Image Source="{Binding Path=ImageFileName} .../>

其中ImageFileName 类似于C:\myapp\images\001.png

我遇到了一个错误,The process cannot access the file 'X' because it is being used by another process。经过大量研究,我想出了必要的代码更改。

我使用了这个 Stackoverflow 答案:Delete a file being used by another process 并将代码放入 ValueConverter

XAML:

<Image Source="{Binding Path=ImageFileName, 
    Converter={StaticResource pathToImageConverter}}" ...>

值转换器:

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();
    }
}
  1. 我担心的是内存使用情况。当我将图像添加到我的 容器,我看到内存增加了。但是,当我删除图像时, 并且底层文件被删除,我没有看到任何内存 释放。

  2. 我也一直认为位图是一个非常低效的文件 格式,因为它们是未压缩的,并且与 JPEG 或 PNG 文件。是个 System.Windows.Media.Imaging.BitmapSource 类实际创建 我的 PNG 中的未压缩图像?

提前非常感谢!

菲利普

【问题讨论】:

  • 删除图像并不能保证内存会被释放。只要垃圾收集器认为合适,就会收集内存。通过手动调用 GC.Collect() 进行交叉检查并查看内存是否释放。
  • 您是否考虑过在图像上使用 VirtualizingStackPanel 并指定 DecodePixel* 属性?
  • @Aybe 不,我没有,但我会调查这些。老实说,直到现在才听说过 VirtualizingStackPanel。
  • @Aybe 此处需要绑定转换器,以便能够在将图像文件加载到 BitmapImage 后立即删除它。这不适用于内置的(字符串到 ImageSource)类型转换器。
  • 嗯,这很简单。下载并安装JetBrains dotPeek,加载 PresentationCore.dll,然后检查命名空间 System.Windows.Media 中 ImageSourceConverter 类中的 ConvertFrom 方法。

标签: c# wpf xaml bitmap


【解决方案1】:

当您从 URI 加载图像时,WPF 最多缓存 300 ImageSource 对象(使用弱引用)。为避免这种情况,请设置BitmapCreateOptions.IgnoreImageCache 选项使用FileStream 来代替加载图像。

请注意,这可能会对您的应用性能产生不利影响,尤其是在您在虚拟化ListBox 中滚动和加载图像的情况下。但是,如果您要加载非常大的图像,则可能需要避免它。

在您的转换器中使用以下代码(另请注意添加的 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 对它们进行解码,以便它们可以在屏幕上呈现。

【讨论】:

  • 这很有帮助,感谢您的回答。当我今晚回家时,我将尝试使用 image.Freeze()。也感谢有关位图的信息......这很有意义。
猜你喜欢
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多