【问题标题】:Deleting an Image that has been used by a WPF control删除已被 WPF 控件使用的图像
【发布时间】:2010-03-11 08:53:15
【问题描述】:

我想将 Image 绑定到某种控件,然后再将其删除。

path = @"c:\somePath\somePic.jpg"
FileInfo fi = new FileInfo(path);
Uri uri = new Uri(fi.FullName, UriKind.Absolute);
var img = new System.Windows.Controls.Image();
img.Source = new BitmapImage(uri);

现在我想在这段代码之后删除文件:

fi.Delete();

但我不能这样做,因为现在正在使用该图像。 在代码片段 1 和 2 之间我可以做些什么来释放它?

【问题讨论】:

    标签: c# wpf file-locking


    【解决方案1】:

    您可以使用MemoryStream,但这实际上会浪费内存,因为位图数据的两个单独副本保存在 RAM 中:当您加载 MemoryStream 时,您会制作一个副本,而当位图被解码时,则会制作另一个副本.以这种方式使用MemoryStream 的另一个问题是您绕过了缓存。

    最好的方法是使用 BitmapCacheOptions.OnLoad 直接从文件中读取:

    path = @"c:\somePath\somePic.jpg"
    
    var source = new BitmapImage();
    source.BeginInit();
    source.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
    source.CacheOption = BitmapCacheOption.OnLoad;
    source.EndInit();  // Required for full initialization to complete at this time
    
    var img = new System.Windows.Controls.Image { Source = source };
    

    这个解决方案也很高效和简单。

    注意:如果您确实想绕过缓存,例如因为图像可能在磁盘上发生变化,您还应该设置CreateOption = BitmapCreateOption.IgnoreImageCache。但即使在这种情况下,该解决方案也优于 MemoryStream 解决方案,因为它不会在 RAM 中保留两个图像数据副本。

    【讨论】:

    • 听起来不错,但我得到一个:不能多次设置初始化状态。source.BeginInit();跨度>
    • 抱歉:我没有使用特定的构造函数重载测试代码。它似乎在内部调用BeginInit()EndInit()。我已更改代码以使用常规构造函数,这应该可以解决该问题。
    • 更多问题: 1. 我不认为 Source 是 BitmapImage 类的属性 2. 如果我用 UriSource 替换它,我仍然知道它没有被初始化......虽然它可以工作我这样使用它: var source = new BitmapImage(); source.BeginInit(); source.UriSource = new Uri(path, UriKind.Absolute); source.CacheOption = BitmapCacheOption.OnLoad; source.EndInit(); 不过为了正确的想法 +1,谢谢。
    【解决方案2】:

    在提供给 imagesource 之前将图像复制到 MemoryStream 它应该是这样的

    BitmapImage bi = new BitmapImage();
    bi.BeginInit();
    bi.DecodePixelWidth = 30;
    bi.StreamSource = byteStream;
    bi.EndInit();
    

    其中 byteStream 是 MemoryStream 中文件的副本

    this 也很有用

    【讨论】:

    • Tx,它有效。对于以后的读者:我已将其复制到这样的内存流中: MemoryStream byteStream = new MemoryStream(File.ReadAllBytes(path));
    • 是的,它可以工作,但效率低下,因为:1. 图像数据的两个副本被永久保留,2. 缓存被绕过,因此图像被加载即使它已经在 RAM 中。链接的文章解释了 #1 的解决方法,但它需要大量额外的代码,但仍然无法解决 #2。一个更好的解决方案是BitmapCacheOption.OnLoad 结合BeginInit/EndInit
    • 你不能在EndInit之后关闭内存流吗?为什么需要同时保留两者?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 2022-01-24
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多