Невозможно удалить файл, используемый другим процессом

Я показываю какое-то изображение в своем приложении wpf, используя следующий код:

 <Image Source="{Binding Path=TemplateImagePath, Mode=TwoWay}"  Grid.Row="3" Grid.Column="2"  Width="400" Height="200"/>

и установить его свойство привязки внутри кода конструктора, перемещаясь по некоторому каталогу, ниже приведен код:

DirectoryInfo Dir = new DirectoryInfo(@"D:/Template");
            if (Dir.Exists)
            {
                if (Dir.GetFiles().Count() > 0)
                {
                    foreach (FileInfo item in Dir.GetFiles())
                    {
                        TemplateImagePath = item.FullName;
                    }
                }
            }

но если пользователь загрузит какое-то другое изображение, мне нужно удалить это старое изображение, которое я делаю следующим образом и устанавливаю привязку изображения к нулю:

DirectoryInfo Dir = new DirectoryInfo(@"D:/Template");
                if (Dir.Exists)
                {
                    if (Dir.GetFiles().Count() > 0)
                    {
                        foreach (FileInfo item in Dir.GetFiles())
                        {
                            TemplateImagePath= null;
                            File.Delete(item.FullName);
                        }
                    }
                }

Но я получаю исключение, которое не может удалить файл, используемый каким-либо другим процессом. Как я могу удалить его?


person SST    schedule 09.10.2012    source источник
comment
Вы пробовали не использовать двустороннюю привязку? Другое решение, которое может сработать, состоит в том, чтобы не задавать путь напрямую, а создавать BitmapImage из пути и привязывать его к этому растровому изображению.   -  person Akku    schedule 09.10.2012
comment
как это сделать. Я новичок в примере кода WPF.any   -  person SST    schedule 09.10.2012
comment
Извините, нет времени, используйте Google, пожалуйста.   -  person Akku    schedule 09.10.2012


Ответы (2)


Чтобы иметь возможность удалить изображение во время его отображения в ImageControl, необходимо создать новый BitmapImage или объект BitmapFrame с < набор href="http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapcacheoption.aspx" rel="noreferrer">BitmapCacheOption.OnLoad. Затем растровое изображение будет загружено из файла немедленно, и после этого файл не будет заблокирован.

Измените свое свойство с string TemplateImagePath на ImageSource TemplateImage и выполните привязку следующим образом:

<Image Source="{Binding TemplateImage}"/>

Установите свойство TemplateImage следующим образом:

BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(item.FullName);
image.EndInit();
TemplateImage = image;

или это:

TemplateImage = BitmapFrame.Create(
    new Uri(item.FullName),
    BitmapCreateOptions.None,
    BitmapCacheOption.OnLoad);

Если вы хотите сохранить привязку к своему свойству TemplateImagePath, вы можете вместо этого использовать преобразователь привязки, который преобразует строку в ImageSource, как показано выше.

person Clemens    schedule 09.10.2012
comment
Также мне нужно добавить 'System.GC.Collect(); System.GC.WaitForPendingFinalizers();' перед удалением того файла, который находится перед этой строкой: File.Delete(item.FullName) - person SST; 10.10.2012
comment
Потратил на это целую вечность, но добавил 'GC.Collect();' и 'GC.WaitForPendingFinalizers();' перед удалением решил мою проблему. Спасибо @SST - person Sandwich; 11.08.2016
comment
@Jon Вы также можете взглянуть на это: stackoverflow.com/q/13262548/1136211. Хотя запуск сборщика мусора может сработать, правильным (т. е. задокументированным) решением будет установка свойства StreamSource вместо свойства UriSource. - person Clemens; 11.08.2016
comment
@Clemens Спасибо, посмотрю - person Sandwich; 12.08.2016
comment
Как вы это делаете с видео? - person Altiano Gerung; 24.09.2018

Согласно предложению Клеменса, вот конвертер привязки, чтобы иметь хорошее повторное использование кода:

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"

А в пользовательском интерфейсе используется конвертер, в моем случае из Библиотеки под названием "Элементы управления"

<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>
person Apfelkuacha    schedule 19.06.2018