WPF - Assigning Icon to Image control
When working with WPF applications, display images is a breeze. The Image control provides rich features to display images of various formats like JPEG, PNG, ICO, BMP, GIF etc. Displaying an image is as simple as setting the Image.Source property to the appropriate image file path. No special coding is required to work with different file formats.
<Image Name="icoDisplay" Source="myfile.jpg" />
Ofcourse you need to worry about other aspects like location of the Image control, its size and also setting the Stretch property to appropriately display the image. I haven't shown all that here for sake of simplicity.
However, this is all fine when working with image files directly. What happens when you don't have a direct file path, but an image in memory like an Icon or Bitmap? If you try to assign say an Icon directly to Image.Source, you get a type cast error stating that conversion from Icon to ImageSource isn't possible. ImageSource incidently is the type that Image.Source property expects.
So how do you get this working. I found some hints at the WPF forum. However this still deals with Icon files that are available as application resources.
I was actually building another example where I wanted to display icon associated with any file type, as displayed in the Windows explorer. I could use the Icon.ExtractAssociatedIcon method to get the required Icon and then display it.
Since I was working on a WPF application, I had to display this icon using the Image control and there is where I landed in trouble. Refering to the above forum question, I tried various options and the simplest of code that worked for me is as below. I am providing the complete code here.
Note that directly using Icon in the code conflicts with Window.Icon property and hence I used the IconImage alias to refer to System.Drawing.Icon class. This also requires adding the reference to System.Drawing assembly.
XAML Code
<Window x:Class="WPFWindowAPP.IconLoader"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPFWindowAPP" Height="164" Width="405"
>
<Canvas>
<TextBox Name="filePath" Canvas.Top="10" Canvas.Left="10" Width="375" ></TextBox>
<Button Name="browse" Click="browseClick" Canvas.Top="40" Canvas.Right="10" Width="75">Browse</Button>
<Button Name="btn" Click="btnClick" Canvas.Top="40" Canvas.Right="90" Width="75">Load Icon</Button>
<Image Name="icoDisplay" Canvas.Left="10" Canvas.Top="80" Stretch="None" />
</Canvas>
</Window>
Code behind code
using System;using System.Collections.Generic;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;using IconImage=System.Drawing.Icon;
using Microsoft.Win32;using System.IO;namespace WPFWindowAPP{/// <summary>
/// Interaction logic for IconLoader.xaml
/// </summary>
public partial class IconLoader : System.Windows.Window
{ public IconLoader() {InitializeComponent();
}
void browseClick(object sender, RoutedEventArgs e)
{OpenFileDialog dlg = new OpenFileDialog();
dlg.ShowDialog();
filePath.Text = dlg.FileName;
}
void btnClick(object sender, RoutedEventArgs e)
{IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
MemoryStream strm = new MemoryStream();
ico.Save(strm);
IconBitmapDecoder ibd = new IconBitmapDecoder(strm, BitmapCreateOptions.None, BitmapCacheOption.Default);
icoDisplay.Source = ibd.Frames[0];
}
}
}
You can copy this code to your own WPF Windows application and try it out. Do also note that the .NET method to extract icon returns a large icon. In case you want to get the small icon, you will have to use p/invoke and call Win32 SHGetFileInfo API from Shell32. You can get a sample implementation of this API here.
There is a catch with this code however. If you implement and run it, you will see that the icons loose their color and are displayed as gray scale. Following code fixes this.
void btnClick(object sender, RoutedEventArgs e)
{IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
Bitmap bmp = ico.ToBitmap();MemoryStream strm = new MemoryStream();
bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png); strm.Seek(0, SeekOrigin.Begin);PngBitmapDecoder pbd = new PngBitmapDecoder(strm, BitmapCreateOptions.None, BitmapCacheOption.Default);
icoDisplay.Source = pbd.Frames[0];
}
Finally, there is yet another way to display the icon and that uses BitmapImage class as shown in the code below.
void btnClick(object sender, RoutedEventArgs e)
{IconImage ico = IconImage.ExtractAssociatedIcon(filePath.Text);
Bitmap bmp = ico.ToBitmap();MemoryStream strm = new MemoryStream();
bmp.Save(strm, System.Drawing.Imaging.ImageFormat.Png);BitmapImage bmpImage = new BitmapImage();
bmpImage.BeginInit();
strm.Seek(0, SeekOrigin.Begin);bmpImage.StreamSource = strm;
bmpImage.EndInit();
icoDisplay.Source = bmpImage;
}
Note that you can use the System.Drawing.Imaging.ImageFormat.Jpeg option as well, but you will loose the transparency effect and the icon will be displayed with a black background.
Comments welcome !

Comments
Thank you very much. It helps me a lot.
Posted by: snow00 | July 5, 2007 03:01 AM
For some reason(s) VS 8.0 is not letting me to use IconImage = System.Drawing.Icon;
:-(
Posted by: Agha | January 30, 2008 08:07 PM
Agha, I just tried it and it works. Not sure why you say VS 2008 isn't allowing you. Can you share the code you have written and what error you are getting.
Also note as I have explained earlier in the blog - "Note that directly using Icon in the code conflicts with Window.Icon property and hence I used the IconImage alias to refer to System.Drawing.Icon class. This also requires adding the reference to System.Drawing assembly."
Posted by: Atul Gupta | January 31, 2008 03:42 AM
I am trying to write a converter that uses this concept
http://www.bendewey.name/code/FilenameIconImageConverter.html
I'm having a problem with the quality. Is there a way to set the color depth of these? Everything I get is coming our at like 256 colors. Any help would greatly be appreciated.
Posted by: Ben Dewey | February 8, 2008 10:13 PM
I updated my code at http://www.bendewey.name/code/FilenameIconImageConverter.html Everything is working fine now.
Please note, I had to change the caching option on the Decoder to OnLoad, otherwise I was getting a "Cannot access a closed Stream." Exception.
I couldn't have done it without your help. Thanks.
Posted by: Ben Dewey | February 11, 2008 05:23 PM
Ben, thanks for sharing the code and glad this blog helped you
Posted by: Atul Gupta | February 12, 2008 05:38 AM
Like Ben, I am using a converter too...
Here's the code that worked for me:
IntPtr hIcon = Icon.ExtractAssociatedIcon(path).Handle;
or
SHFILEINFO shinfo = new SHFILEINFO();
Win32.SHGetFileInfo(path, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), Win32.SHGFI_ICON | Win32.SHGFI_SMALLICON);
and then
return InteropImaging.CreateBitmapSourceFromHIcon(shinfo.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
Posted by: Priyadarshini Gorur | June 12, 2008 08:51 PM
Ben, Priyadarshini, thanks for sharing. The code i had posted is way too old and was also when I had just playing around with WPF. There is an updated blog here - http://infosysblogs.com/microsoft/2008/04/wpf_binding_to_image_control.html
Priyadarshini, I have also used ExtractAssociatedIcon and the SHGetFileInfo APIs extensively. I just wish that .net will support extracting the small icons as well, so there will be no need to do a pinvoke to SHGetFileInfo.
Posted by: Atul Gupta | June 13, 2008 09:44 AM
Is there another way of retrieving file icons without using SHFILEINFO??
I'm making a 'windows explorer'-like program but it's a web application.
Posted by: grew | June 17, 2008 05:56 AM
Grew, I am not aware of any other method. The .net API ExtractAssociatedIcon doesn't return the small sized icon and hence one has to work with SHGetFileInfo.
You should be able to use these APIs on your web application as well.
Another approach that you can try is to write a windows program, run it with the specific file types that you want to support, extract and save the icons and then work with them directly.
Posted by: Atul Gupta | June 23, 2008 04:00 AM