WPF, binding to an image without file access exceptions
You can run into
file access errors when using images in WPF. By default, the .Net
Framework locks the image until it's not used and the garbage collector
decides to release the reference. For example, the following
snippet displays an image but a file access error occurs if the
application, or the user, tries to modify or delete the image file from
the file system.
<Image Source="d:\vertigo.png" />
You can change how the
framework manages the reference to the image with the BitmapImage.CacheOption
property. The following snippet specifies that the image is loaded and
the reference is released, so the image on the file system can be
modified or deleted.
<Image>
<Image.Source>
<BitmapImage UriSource="d:\vertigo.png" CacheOption="OnLoad"></BitmapImage>
</Image.Source>
</Image>
But the UriSource
property does not support binding, so you cannot do something simple
like the following:
<Image>
<Image.Source>
<!--
this does not work -->
<BitmapImage UriSource="{Binding Path=ImagePath}" CacheOption="OnLoad"></BitmapImage>
</Image.Source>
</Image>
Instead, you can
do your own UriSource binding by creating a converter that takes in a
path to the image and returns a BitmapImage
object. For example, the following XAML binds the Source
property to ImagePath (which is the path to the image), along
with a converter that returns a BitmapImage object.
<local:ImagePathConverter x:Key="ImagePathConverter"/>
<Image Source="{Binding Path=ImagePath, Converter={StaticResource ImagePathConverter}}" />
The converter is
pretty straightforward: creates a BitmapImage object, sets the
CacheOption property, and returns the object. So now you can data bind
to an image and still modify or delete the image from the file system
without file access errors.
public class ImagePathConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
// value contains the full path to the image
string path = (string)value;
// load the image, specify CacheOption so the file is not locked
BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = new Uri(path);
image.EndInit();
return image;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("The method or operation is not implemented.");
}
}