Setting WPF image source in code

Viewed 607435

I'm trying to set a WPF image's source in code. The image is embedded as a resource in the project. By looking at examples I've come up with the below code. For some reason it doesn't work - the image does not show up.

By debugging I can see that the stream contains the image data. So what's wrong?

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;

The icon is defined something like this: <Image x:Name="_icon" Width="16" Height="16" />

19 Answers

This is a bit less code and can be done in a single line.

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;

Very easy:

To set a menu item's image dynamically, only do the following:

MyMenuItem.ImageSource = 
    new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));

...whereas "icon.ico" can be located everywhere (currently it's located in the 'Resources' directory) and must be linked as Resource...

You can also reduce this to one line. This is the code I used to set the Icon for my main window. It assumes the .ico file is marked as Content and is being copied to the output directory.

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));

Have you tried:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;

Here is an example that sets the image path dynamically (image located somewhere on disc rather than build as resource):

if (File.Exists(imagePath))
{
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
}

Reflections on Icons...

First thought, you would think that the Icon property can only contain an image. But it can actually contain anything! I discovered this by accident when I programmatically tried to set the Image property directly to a string with the path to an image. The result was that it did not show the image, but the actual text of the path!

This leads to an alternative to not have to make an image for the icon, but use text with a symbol font instead to display a simple "icon". The following example uses the Wingdings font which contains a "floppydisk" symbol. This symbol is really the character <, which has special meaning in XAML, so we have to use the encoded version &lt; instead. This works like a dream! The following shows a floppydisk symbol as an icon on the menu item:

<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
  <MenuItem.Icon>
    <Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings">&lt;</Label>
  </MenuItem.Icon>
</MenuItem>

Put the frame in a VisualBrush:

VisualBrush brush = new VisualBrush { TileMode = TileMode.None };

brush.Visual = frame;

brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;

Put the VisualBrush in GeometryDrawing

GeometryDrawing drawing = new GeometryDrawing();

drawing.Brush = brush;

// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;

Now put the GeometryDrawing in a DrawingImage:

new DrawingImage(drawing);

Place this on your source of the image, and voilĂ !

You could do it a lot easier though:

<Image>
    <Image.Source>
        <BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
    </Image.Source>
</Image>

And in code:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };

There's also a simpler way. If the image is loaded as a resource in the XAML, and the code in question is the codebehind for that XAML:

Here's the resource dictionary for a XAML file - the only line you care about is the ImageBrush with the key "PosterBrush" - the rest of the code is just to show context

<UserControl.Resources>
        <ResourceDictionary>
            <ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>

        </ResourceDictionary>
    </UserControl.Resources>

Now, in the code behind, you can just do this

ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];

Here is if you want to locate it next to your executable (relative from the executable)

img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + @"\Images\image.jpg", UriKind.Absolute));

Force chose UriKind will be correct:

Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));

UriKind options:

UriKind.Relative // relative path
UriKind.Absolute // exactly path
Related