使用 XAML 获取图像资源后如何 release/caching
How to release/caching image resources after get them using XAML
目前我在一个使用 prism 6 的 WPF 项目中工作,尽可能避免代码隐藏。我在 ViewModel 中有一个变量,其中包含存储相关图像的本地路径。在视图中,我将图像控件的源 属性 绑定到 ViewModel 的变量,我可以显示图像。
当图像仍在视图中显示时我需要从磁盘中删除图像时出现问题。然后,如果我这样做,我会得到典型的“Image is in use”。我在论坛上阅读了有关图像缓存的内容,我想知道我是否可以在这种情况下应用它来避免这种行为,如果可能的话只使用 XAML。
我正在使用这种方法:
<Border Grid.Column="0" BorderThickness="2" BorderBrush="#808080" Height="300"
Width="300" Background="#FCFCFC">
<Image Height="350" Width="350" HorizontalAlignment="Center"
VerticalAlignment="Center" Source="{Binding ImageUri}"/>
</Border>
只要您的 ImageSource 指向本地磁盘上的文件,您就无法删除它。我想到了以下两种方法:
既然你有实际图像的路径 - 为什么不将它复制到 TEMP 文件夹并绑定到这个路径。这样你就永远不会引用现在可以删除的实际图像。
Use/Build 图像文件(如)imgur(Whosebug 也使用)的 http 主机 (CMS)。总是 save/host 个文件。这样 ImageSource 就是一个 http uri.
如果您可以在调用(MainWindow 或 UserControl 的)InitializeComponent 之前分配 DataContext,则可以在 XAML 中显式创建一个 BitmapImage 并将其 CacheOption
设置为 OnLoad
。然后框架将立即加载文件而不是保持打开状态。
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageUri}" CacheOption="OnLoad"/>
</Image.Source>
</Image>
如果 DataContext 或 ImageUri 属性 必须在 InitializeComponent 之后设置,您可以添加类型 ImageSource
的 属性
public ImageSource Image
{
get { return BitmapFrame.Create(
ImageUri, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); }
}
或byte[]
:
public byte[] Image
{
get { return File.ReadAllBytes(ImageUri.LocalPath); }
}
并像这样绑定它:
<Image Source="{Binding Image}"/>
或异步提高 UI 的响应能力:
<Image Source="{Binding Image, IsAsync=True}"/>
您不需要在 ViewModel
中创建 ImageSource
对象。相反,只需创建类型为 byte[]
的 属性,您可以使用标准 IO 函数从文件中设置它。然后,您可以将 Image
控件的 Source
属性 绑定到此字节数组 - 控件将自动处理到可显示图像的转换。
请参阅我对 的回答以了解以异步方式处理此问题的方法。
读取文件后,您可以根据需要删除它。如果图像来自某些外部来源,例如一个网络下载,你可以直接使用数据,甚至根本不需要将它保存到磁盘。
您可以为此编写一个转换器,将文件名转换为字节
public class FilenameToBytesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
var path = (string)value;
if (!File.Exists(path))
{
return null;
}
return File.ReadAllBytes(path);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
并在视图中使用它
<Window ...
xmlns:Converters="clr-namespace:YourNamespacePath.Converters"/>
<Window.Resources>
<Converters:FilenameToBytesConverter x:Key="FilenameToBytesConverter"/>
</Window.Resources>
<Image Source="{Binding ImageUri, Converter={StaticResource FilenameToBytesConverter}}"/>
目前我在一个使用 prism 6 的 WPF 项目中工作,尽可能避免代码隐藏。我在 ViewModel 中有一个变量,其中包含存储相关图像的本地路径。在视图中,我将图像控件的源 属性 绑定到 ViewModel 的变量,我可以显示图像。
当图像仍在视图中显示时我需要从磁盘中删除图像时出现问题。然后,如果我这样做,我会得到典型的“Image is in use”。我在论坛上阅读了有关图像缓存的内容,我想知道我是否可以在这种情况下应用它来避免这种行为,如果可能的话只使用 XAML。
我正在使用这种方法:
<Border Grid.Column="0" BorderThickness="2" BorderBrush="#808080" Height="300"
Width="300" Background="#FCFCFC">
<Image Height="350" Width="350" HorizontalAlignment="Center"
VerticalAlignment="Center" Source="{Binding ImageUri}"/>
</Border>
只要您的 ImageSource 指向本地磁盘上的文件,您就无法删除它。我想到了以下两种方法:
既然你有实际图像的路径 - 为什么不将它复制到 TEMP 文件夹并绑定到这个路径。这样你就永远不会引用现在可以删除的实际图像。
Use/Build 图像文件(如)imgur(Whosebug 也使用)的 http 主机 (CMS)。总是 save/host 个文件。这样 ImageSource 就是一个 http uri.
如果您可以在调用(MainWindow 或 UserControl 的)InitializeComponent 之前分配 DataContext,则可以在 XAML 中显式创建一个 BitmapImage 并将其 CacheOption
设置为 OnLoad
。然后框架将立即加载文件而不是保持打开状态。
<Image>
<Image.Source>
<BitmapImage UriSource="{Binding ImageUri}" CacheOption="OnLoad"/>
</Image.Source>
</Image>
如果 DataContext 或 ImageUri 属性 必须在 InitializeComponent 之后设置,您可以添加类型 ImageSource
public ImageSource Image
{
get { return BitmapFrame.Create(
ImageUri, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); }
}
或byte[]
:
public byte[] Image
{
get { return File.ReadAllBytes(ImageUri.LocalPath); }
}
并像这样绑定它:
<Image Source="{Binding Image}"/>
或异步提高 UI 的响应能力:
<Image Source="{Binding Image, IsAsync=True}"/>
您不需要在 ViewModel
中创建 ImageSource
对象。相反,只需创建类型为 byte[]
的 属性,您可以使用标准 IO 函数从文件中设置它。然后,您可以将 Image
控件的 Source
属性 绑定到此字节数组 - 控件将自动处理到可显示图像的转换。
请参阅我对
读取文件后,您可以根据需要删除它。如果图像来自某些外部来源,例如一个网络下载,你可以直接使用数据,甚至根本不需要将它保存到磁盘。
您可以为此编写一个转换器,将文件名转换为字节
public class FilenameToBytesConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
var path = (string)value;
if (!File.Exists(path))
{
return null;
}
return File.ReadAllBytes(path);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
并在视图中使用它
<Window ...
xmlns:Converters="clr-namespace:YourNamespacePath.Converters"/>
<Window.Resources>
<Converters:FilenameToBytesConverter x:Key="FilenameToBytesConverter"/>
</Window.Resources>
<Image Source="{Binding ImageUri, Converter={StaticResource FilenameToBytesConverter}}"/>