Infosys Microsoft Alliance and Solutions blog

« WPF/E is now Silverlight | Main | VSTS (Orcas March CTP) Profiler - Comparing Performance Reports »

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 !

TrackBack

Listed below are links to weblogs that reference WPF - Assigning Icon to Image control:

» WPF Icon as ImageSource from Parker's DevEd Blog
Assigning the Icon of a window in WPF, should seem rather simpllistic and straight forward. You should [Read More]

Comments

Thank you very much. It helps me a lot.

For some reason(s) VS 8.0 is not letting me to use IconImage = System.Drawing.Icon;
:-(

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."

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.

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.

Ben, thanks for sharing the code and glad this blog helped you

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());

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.

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.

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.

Hello Atul Gupta,

I only want to leave a quick "Thanks!" here, because this Blog entry makes my day today!

Meik, Glad it helped.

Sorry, this is not that complicated.

1. Add the ico file to your project.

2. Make sure the build action for the ico file is set to Resource.

3. For the Window element in the XAML declaration add, Icon="MyIcon.ico"

That's it. For some reason, the drop down for icon in the window icon propery does not accept the filename. The work around is to type it directly into the XAML declaration.

Peter, thanks, but the point in question isn't really about icon files that I have physically available on the machine. It was more about if you have them available as embedded resources or in form of stream.

Hello Atul,

Really nice posting. I was searching for how to set images in wpf. And I like your code style. Keep the good work. Thanks for sharing code.

pls help me to decompress an image in wpf(i am using lossy compression ).bcos after decompression i need to decrypt it for a project. immediate help is sought. thanks

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)

Please key in the two words you see in the box to validate your identity as an authentic user and reduce spam.

Subscribe to this blog's feed

Follow us on

Blogger Profiles

Infosys on Twitter