🖼️
【WPF】ImageコントロールにBindingしている画像を削除できるようにする
WPFの Image
コントールで、 Source
プロパティに画像ファイルパスをバインドすることで、画像ファイルを画面表示しようとする。
<Image Source="{Binding Image1Path}" />
public class FooViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private string? _image1Path = @"C:\path\to\image.png";
public string? Image1Path
{
get => _image1Path;
set
{
_image1Path = value;
// Raise PropertyChanged
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image1Path)));
}
}
}
Source
プロパティは ImageSource
型だが、stringのまま画像ファイルのパスをBindingしても、勝手にコンバータで変換してくれる。
ところが、このBindingされた状態で画像ファイルを File.Delete()
で削除しようとすると、以下のようなExceptionになる。
System.IO.IOException: 'The process cannot access the file 'C:\path\to\image.png' because it is being used by another process.'
これを防ぐには、画像を表示するときに元のファイルをロックしないように、コンバータを自作する。
[ValueConversion(typeof(string), typeof(ImageSource))]
public class NoLockImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var filePath = value as string;
if (string.IsNullOrEmpty(filePath))
{
return Binding.DoNothing;
}
using (var fs = new FileStream(filePath, FileMode.Open))
{
// OnLoadにする
var decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
var bmp = new WriteableBitmap(decoder.Frames[0]);
bmp.Freeze();
return bmp;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<Grid >
<Grid.Resources>
<!-- 親コンテナなどでリソース定義しておく
(Window で xmlns:local="clr-namespace:FooNamespace" のように名前空間を定義する) -->
<local:NoLockImageConverter x:Key="noLockImageConverter" />
</Grid.Resource>
<Image Source="{Binding Image1Path, Converter={StaticResource noLockImageConverter}}" />
</Grid>
これで表示時にメモリ上に画像をロードするようになるため、元ファイルを削除することもできるようになる。
Discussion