如何在WPF中释放Image Source的图像

18

我正在像下面这样加载图片

XAML

<Image Stretch="None" Grid.Row="16" Height="70" HorizontalAlignment="Left" Name="imgThumbnail" VerticalAlignment="Top" Width="70" Grid.RowSpan="3" Margin="133,1,0,0" Grid.Column="2" Grid.ColumnSpan="2" />

CodeBehind

if (Path.GetFileNameWithoutExtension(filePath).ToLower().Contains(slugName.ToLower() + "_70x70"))
{
    imgThumbnail.BeginInit();
    imgThumbnail.Stretch = Stretch.UniformToFill;
    imgThumbnail.Source = new BitmapImage(new Uri(filePath));
    imgThumbnail.EndInit();
    count = count + 1;
}

以上代码运行正常,现在我有一个删除按钮放在我的缩略图旁边,如果调用删除按钮,我应该从源位置删除所有图像。

以下是删除图像文件的代码

internal int Remove(string slugName, DirectoryInfo outputFolder)
{
    Helper.MetadataView.imgThumbnail.Source = null;

    foreach (string filePath_ToBeDeleted in filePathList_ToBeDeleted)
    {
        if (File.Exists(filePath_ToBeDeleted))
        {
            Helper.MetadataView.imgThumbnail.IsEnabled = false;
            File.Delete(filePath_ToBeDeleted);
            count += 1;
            }
        }
        return count;
    }
    return 0; // slugName == null
}

我试图将来源设为null并删除,但是会抛出以下异常:

由于另一个进程正在使用,因此无法访问文件'\serv1\Dev\Images\730_Test4_0406_70x70.jpg'。

我不确定如何处理,请有经验的人指导一下。


imgThumbnail 是什么类型? - Gjeltema
@Gjeltema,imgThumbnail是一张图片。我已经用XAML更新了我的问题。谢谢。 - Usher
2个回答

48

如果您想要删除或移动该Image,则不应直接在您的应用程序中使用它。

imgThumbnail.Source = new BitmapImage(new Uri(filePath));

相反,做这个:

BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(filePath);
image.EndInit();
imgThumbnail.Source = image;

欲了解更多,请阅读此文


1
这是一个不错的解决方案。我使用了 ImageSource 而不是创建新的 Image。赋值方式就像 ImageSource SomeImageSource = image,在 XAML 中进行绑定 <Image Source"={Binding SomeImageSource}" />。同时,我将这段代码封装在一个方法中。 - Mr. Blond
1
我已经完成了所有工作,但没有设置CacheOption属性为OnLoad。默认值是OnDemand,它会保持源流处于打开状态。似乎应该将OnLoad设置为默认值以便按预期行事。有关此问题的完整文档,请参见:https://msdn.microsoft.com/zh-cn/library/system.windows.media.imaging.bitmapimage.cacheoption(v=vs.110).aspx?f=255&MSPPError=-2147217396 - Dan Randolph
如果我使用这段代码,应用程序的内存会增加吗? - Ankur Tripathi
@Ankur Tripathi 它会保留内存直到不再需要为止。 - Chris Bordeman
@ChrisBordeman 如果我使用这段代码并加载1000张图片,会增加高级内存吗?还是内存=图像大小X1000? - Ankur Tripathi
显示剩余5条评论

5
为了实现良好的代码重用,可以使用绑定转换器:
namespace Controls
{
    [ValueConversion(typeof(String), typeof(ImageSource))]
    public class StringToImageSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is string valueString))
            {
                return null;
            }
            try
            {
                ImageSource image = BitmapFrame.Create(new Uri(valueString), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad);
                return image;
            }
            catch { return null; }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

有一个绑定的字符串,例如:

public string MyImageString { get; set; } = @"C:\test.jpg"

在UI中使用转换器,例如在我的情况下从名为“Controls”的库中。
<Window x:Class="MainFrame"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:controls="clr-namespace:Controls;assembly=Controls">
    <Window.Resources>
        <controls:StringToImageSourceConverter x:Key="StringToImageSourceConverter" />
    </Window.Resources>
    <Grid>
        <Image Source="{Binding MyImageString, Converter={StaticResource StringToImageSourceConverter}}" />
    </Grid>
</Window>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接