【问题标题】:using XAML to bind to a System.Drawing.Image into a System.Windows.Image control使用 XAML 将 System.Drawing.Image 绑定到 System.Windows.Image 控件中
【发布时间】:2010-08-06 19:22:30
【问题描述】:

我将 ListView 绑定到对象列表,就像这样;

<ListView 
    ItemsSource="{ Binding Path=. }"
    ItemTemplate="{DynamicResource EventTemplate}">   

我正在绑定一个声明两个属性的对象;

string DisplayName { get; }
System.Drawing.Image Image { get; set; }

我想填充DataTemplate,但我不知道怎么做;如果我在我的模板中这样做;

<StackPanel Orientation="Horizontal">
    <Image Source="{ Binding Path=Image }" />
    <TextBlock Text="{ Binding Path=DisplayName }" />
</StackPanel>      

文字出现,但图像不出现。我究竟做错了什么?调试输出显示

System.Windows.Data Error: 1 : Cannot create default converter
to perform 'one-way' conversions between types
'System.Drawing.Image' and 'System.Windows.Media.ImageSource'.
Consider using Converter property of Binding.
BindingExpression:Path=Image; DataItem='RealElement'
(HashCode=54308798); target element is 'Image' (Name='');
target property is 'Source' (type 'ImageSource')

【问题讨论】:

    标签: c# wpf image xaml binding


    【解决方案1】:

    找到了令我满意的方法。我使用Reed Copsey's pointerthis tutorial 将代码包装为IValueConverter

    这是从System.Drawing.ImageSystem.Windows.Media.ImageSource 的转换器;

    using System;
    using System.Drawing.Imaging;
    using System.Globalization;
    using System.IO;
    using System.Windows.Data;
    
    namespace System.Windows.Media
    {
        /// <summary>
        /// One-way converter from System.Drawing.Image to System.Windows.Media.ImageSource
        /// </summary>
        [ValueConversion(typeof(System.Drawing.Image), typeof(System.Windows.Media.ImageSource))]
        public class ImageConverter : IValueConverter
        {
            public object Convert(object value, Type targetType,
                object parameter, CultureInfo culture)
            {
                // empty images are empty...
                if (value == null) { return null; }
    
                var image = (System.Drawing.Image)value;
                // Winforms Image we want to get the WPF Image from...
                var bitmap = new System.Windows.Media.Imaging.BitmapImage();
                bitmap.BeginInit();
                MemoryStream memoryStream = new MemoryStream();
                // Save to a memory stream...
                image.Save(memoryStream, ImageFormat.Bmp);
                // Rewind the stream...
                memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
                bitmap.StreamSource = memoryStream;
                bitmap.EndInit();
                return bitmap;
            }
    
            public object ConvertBack(object value, Type targetType,
                object parameter, CultureInfo culture)
            {
                return null;
            }
        }
    }
    

    那你需要把图片转换器作为资源带入XAML;

    xmlns:med="clr-namespace:System.Windows.Media"
    ...
    
    <ListView.Resources>
        <med:ImageConverter x:Key="imageConverter" />
    </ListView.Resources>
    

    然后你可以在 XAML 中使用它来直接绑定到 Image,使用新的转换器;

    <Image Source="{ Binding Path=Image, Converter={StaticResource imageConverter} }" />
    

    【讨论】:

    • 我有一个关于内存使用的问题:这种转换只发生一次还是每次图像显示在 ListBox 的可见部分时??
    • 不能说——每次 WPF 需要它时都会完成转换——所以我认为这只是一个内部实现细节。我认为它没有任何理由一遍又一遍地转换,但它可能值得坚持在柜台上看看......
    • memoryStream 从未关闭或处置,这是一个问题吗?我有一些非常相似的代码,甚至可能来自这个问题,但它更丑。
    • 对于未来的读者,请记住在属性设置器中处置以前的Image 实例。这是对@Maslow 评论的回应。
    【解决方案2】:

    您不能直接绑定它 - 您需要有某种类型的转换器,可以将 GDI 图像转换为 WPF 图像。

    这里是one approach - 它使用内存流从 GDI 图像中提取数据并创建 BitmapSource 对象。

    【讨论】:

    • 嗨——感谢您的指点。目前,我正在阅读您的“更好的用户和开发人员体验——从 Windows 窗体到带有 MVVM 的 WPF”文章的一半;好东西。无论如何,这给了我足够的答案;我已经把它贴在旁边了。
    • @Steve:很高兴听到你喜欢这个系列 ;)
    • 这真的很有帮助。 WPF 模型与 windows 窗体有很大的不同,你的文章正在帮助我解锁它。
    • 该示例中的 memoryStream 永远不会被释放,也不会处于使用或关闭状态。这是个问题吗?
    猜你喜欢
    • 2012-02-12
    • 1970-01-01
    • 2011-04-01
    • 2011-11-04
    • 1970-01-01
    • 2012-08-15
    • 2013-03-29
    • 1970-01-01
    • 2012-10-09
    相关资源
    最近更新 更多