关于.net:Image UriSource和数据绑定

关于.net:Image UriSource和数据绑定

Image UriSource and Data Binding

我正在尝试将自定义对象列表绑定到WPF图像,如下所示:

1
2
3
4
5
<Image>
    <Image.Source>
        <BitmapImage UriSource="{Binding Path=ImagePath}" />
    </Image.Source>
</Image>

但是它不起作用。这是我得到的错误:

"必须设置属性\\'UriSource \\'或属性\\'StreamSource \\'。"

我想念什么?


WPF具有某些类型的内置转换器。如果将Image的Source属性绑定到stringUri值,则WPF在幕后将使用ImageSourceConverter将值转换为ImageSource

所以

1
<Image Source="{Binding ImageSource}"/>

如果ImageSource属性是图像的有效URI的字符串表示形式,则可以使用。

您当然可以滚动自己的Binding转换器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ImageConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new BitmapImage(new Uri(value.ToString()));
    }

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

并像这样使用它:

1
<Image Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}"/>

Atul Gupta的这篇文章的示例代码涵盖了几种场景:

  • 常规资源图像绑定到XAML中的Source属性
  • 绑定资源映像,但来自代码后面
  • 通过使用Application.GetResourceStream在代码后绑定资源映像
  • 通过内存流从文件路径加载图像(从数据库加载博客图像数据时同样适用)
  • 从文件路径加载图像,但是通过使用绑定到文件路径
  • 通过依赖属性将图像数据绑定到内部具有图像控件的用户控件
  • 与第5点相同,但还要确保文件不会被锁定在硬盘上

  • 您也可以简单地设置Source属性,而不使用子元素。为此,您的类需要将图像作为位图图像返回。这是我完成该操作的一种方式的示例

    1
    2
    3
    <Image Width="90" Height="90"
           Source="{Binding Path=ImageSource}"
           Margin="0,0,0,5" />

    class属性就是这个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public object ImageSource {
        get {
            BitmapImage image = new BitmapImage();

            try {
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
                image.UriSource = new Uri( FullPath, UriKind.Absolute );
                image.EndInit();
            }
            catch{
                return DependencyProperty.UnsetValue;
            }

            return image;
        }
    }

    我想它可能比值转换器要多一些工作,但这是另一种选择。


    您需要实现IValueConverter接口,该接口将uri转换为图像。您的IValueConverter的Convert实现将如下所示:

    1
    2
    3
    4
    5
    6
    BitmapImage image = new BitmapImage();
    image.BeginInit();
    image.UriSource = new Uri(value as string);
    image.EndInit();

    return image;

    然后,您将需要在绑定中使用转换器:

    1
    2
    3
    4
    5
    <Image>
        <Image.Source>
            <BitmapImage UriSource="{Binding Path=ImagePath, Converter=...}" />
        </Image.Source>
    </Image>

    此处选择答案的问题是,在来回导航时,每次显示页面时都会触发转换器。

    这将导致连续创建新的文件句柄,并且将阻止任何删除该文件的尝试,因为该文件仍在使用中。可以使用Process Explorer来验证。

    如果图像文件可能在某个时候被删除,则可以使用如下所示的转换器:
    使用XAML将System.Drawing.Image绑定到System.Windows.Image控件中

    此内存流方法的缺点在于,每次都会对图像进行加载和解码,并且无法进行缓存:
    "为了防止图像被多次解码,请从Uri分配Image.Source属性,而不要使用内存流"
    来源:"使用XAML的Windows Store应用程序的性能提示"

    为解决性能问题,存储库模式可用于提供缓存层。缓存可能发生在内存中,这可能会导致内存问题,也可能是缩略图文件驻留在temp文件夹中,可以在应用程序退出时清除。


    您可以使用

    ImageSourceConverter class

    得到想要的东西

    1
        img1.Source = (ImageSource)new ImageSourceConverter().ConvertFromString("/Assets/check.webp");

    推荐阅读