Skip to content

Databinding a System.Drawing.Image into a WPF System.Windows.Image

by Steve Cooper on August 6th, 2010

I’m learning WPF, very slowly, as a background thing.

I’m working very slowly through some WPF at the moment, and discovered something I thought was really odd. The classic .Net Image class — System.Drawing.Image — can’t be easily databound into the WPF Image control.

That seemed crazy to me — it’s like having a PictureBox control without an Image property. I resolved to fix it in the most ‘WPFy’ way I could.

What I’d tried was binding a ListView to a list of objects, like so;

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

Id bound to an object which declares two properties;

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

I wanted to populate a DataTemplate but if I did this in my template;

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

The text appears but the image does not. It turns out that WPF can’t find a suitable converter.

So, thanks to Reed Copsey and his very helpful pointer on Stack Overflow, and this tutorial, I’ve found a way I’m happy with; one that doesn’t involve c# code-behind.

I’ve created an IValueConverter which does the conversion from System.Drawing.Image to System.Windows.Media.ImageSource. A big thank-you to Matt Galbraith of Microsoft for providing the core code;

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, image.RawFormat);
            // 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;
        }
    }
}

Then you need to bring the image converter into XAML as a resource. Add the namespace declaration to the window;

xmlns:med="clr-namespace:System.Windows.Media"

Stick an instance of the ImageConverter into a static resource;

<ListView.Resources>
    <med:ImageConverter x:Key="imageConverter" />
</ListView.Resources>

Then you can use it in XAML to bind directly to the Image, using the new converter;

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

So. A re-usable converter which allows databinding directly to GDI image objects.

Originally discussed on stack overflow

From → Uncategorized

11 Comments
  1. Thanks a lot! Short and clear explanation!

    I’m also learning WPF as a background thing

  2. Alex permalink

    I tried this, and my images, which have a transparent background, are now displayed with a black background.

  3. @Alex; try poking around in the System.Windows.Media.Imaging namespace. My guess is that the System.Windows.Media.Imaging.BitmapImage class isn’t handling the alpha channel present in your image. I notice that there are PngBitmapDecoder and PngBitmapEncoder classes, which may or may not help.

    (http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.aspx)

  4. Gunnar Lilleaasen permalink

    To preserve all features of the original image, I think you should replace

    image.Save(memoryStream, ImageFormat.Bmp);

    with

    image.Save(memoryStream, image.RawFormat);

    By doing this, you’ll keep features like transparency/alpha channels from image formats like PNG.

  5. Thanks, Gunnar — Updated.

  6. Nik permalink

    Great, thanks!

  7. Blake permalink

    Hey Steve. Thanks for the post. I wanted to share a VB.Net conversion I made on the code you provided in case anybody else is looking for one.

    http://blakepell.wordpress.com/2011/12/22/databinding-a-system-drawing-image-in-wpf-with-vb-net/

  8. Nadiya permalink

    Thanks a lot! I’ve spent 2 days on it without any result.

  9. mark permalink

    where is the corret position of this code?

    I don’t know to create a good static resources.

  10. Sulik permalink

    Thanks a lot!

Trackbacks & Pingbacks

  1. Databinding a System.Drawing.Image in WPF with VB.Net « Blake's Application Development Blog

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS