Click here to Skip to main content
13,357,973 members (59,767 online)
Click here to Skip to main content
Add your own
alternative version


154 bookmarked
Posted 8 Nov 2007

A Simple WPF Explorer Tree

, 8 Nov 2007
Rate this:
Please Sign up or sign in to vote.
A Simple WPF Explorer Tree



I am still getting to grips with WPF, and last night, as part of a larger article that I am still working on, I wanted to create a simple (basic version) of an explorer tree, which shows drives and folders. I wanted to display a drive image if the TreeViewItem is a drive, and a folder image otherwise. Sounds easy right. Wrong, it turned out to be quite tricky, well at least it was for me. So I thought that as the big article where this technique is used is still being written, I would break out the tree view implementation into a smaller article (this one). I think it's probably going to be a fairly common requirement to display different images for the current TreeViewItem based on some condition. So that's what this article is all about.

Solving the Problem

The finished product looks like this:

Really simple, isn't it.

So How did I Get the WPF TreeView to do that

The first step is to get it to display the correct tree, which is really down to the following two methods.

private void Window_Loaded(object sender, RoutedEventArgs e)
    foreach (string s in Directory.GetLogicalDrives())
        TreeViewItem item = new TreeViewItem();
        item.Header = s;
        item.Tag = s;
        item.FontWeight = FontWeights.Normal;
        item.Expanded += new RoutedEventHandler(folder_Expanded);

void folder_Expanded(object sender, RoutedEventArgs e)
    TreeViewItem item = (TreeViewItem)sender;
    if (item.Items.Count == 1 && item.Items[0] == dummyNode)
            foreach (string s in Directory.GetDirectories(item.Tag.ToString()))
                TreeViewItem subitem = new TreeViewItem();
                subitem.Header = s.Substring(s.LastIndexOf("\\") + 1);
                subitem.Tag = s;
                subitem.FontWeight = FontWeights.Normal;
                subitem.Expanded += new RoutedEventHandler(folder_Expanded);
    catch (Exception) { }

That's enough to get us the drive/folder hierarchy for the TreeView. Next step, I wanted images for the individual TreeViewItems.

By default, the WPF TreeView control does NOT display images, for example the image below shows what the WPF control looks like out of the box (Note I am using Vista, so it may look slightly different on XP)

This isn't what I wanted. So I started to look around to see if there was an Image property or something like that on the TreeViewItem, and guess what, there isn't. But of course WPF lets us change the look and feel of controls using Styles/Templates. So that's a good place to start, to maybe develop a Style/Template. Note: I would recommend not using Expression Blend for this task, as it creates about 200 lines of XAML the minute you decide to start editing the WPF TreeView control using Expression Blend, and that's before you've even changed it. So it will likely be more. Don't get me wrong. Expression Blend is handy but for some things like Style/Template editing VS2005/VS2008 and hard crafted code are the way to go, you get much less code to do the job.

Ok rant over, so we need to create some sort of Style for the WPF TreeView control, so I started going down that road and ended up with the following:

<TreeView x:Name="foldersItem"


          Width="Auto" Background="#FFFFFFFF"


        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="HeaderTemplate">
                        <StackPanel Orientation="Horizontal">
                            <Image Name="img"




                            <TextBlock Text="{Binding}" Margin="5,0" />

This style ends up with the following, where we now have some images against our TreeViewItem, which is cool. We're getting there. But all the images are the same. But that's because this style is using a fixed path for all the Image Source properties. So it's bound not to work. Grrr. Maybe there's something more that can be done in the style. As it happens that's exactly what is done. Let's see.

I'll just include the part of the Style that is different from that shown above.

<Image Name="img"  Width="20" Height="20" Stretch="Fill"
    Source="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
    AncestorType={x:Type TreeViewItem}},
    Converter={x:Static local:HeaderToImageConverter.Instance}}"

Now I have to say this is probably the most complicated bit of binding code that I've ever written in XAML. So what it does then, eh?

Well basically it sets the Image Source property to be bound to the TreeViewItems Header property (The Header property, is the one that holds the text shown on the rendered TreeView control, so it would hold strings like c:\\, Program Files, Windows etc. etc.

But what use is that, these c:\\, Program Files, Windows string values aren't Image Source Uri's, are they. They aren't even close, an Image Source Uri, should be something like C:\Windows\Web\Azul.jpg or something shouldn't it?

Well yeah they should actually. But WPF Databinding has one last trick up its very long and vacuumous (is that a word, it should be, I reckon) sleeve, Value Converters. Value Converters allow us to create a class that will use the original DataBound value and return a different object that will be used as the final binding value.

This is the trick that I use to get the image source to point to the correct location. Basically in the Image Source binding shown above, I also specify a converter called HeaderToImageConverter which I use to check whether the actual TreeViewItems Header property contains a \ character. And if it does, I consider that TreeViewItem to be a diskdrive, so I return a diskdrive Image Source Uri, otherwise I return a folder Image Source Uri. This may become clearer once you see the actual converter.

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media.Imaging;

namespace WPF_Explorer_Tree
    #region HeaderToImageConverter

    [ValueConversion(typeof(string), typeof(bool))]
    public class HeaderToImageConverter : IValueConverter
        public static HeaderToImageConverter Instance =
            new HeaderToImageConverter();

        public object Convert(object value, Type targetType,
            object parameter, CultureInfo culture)
            if ((value as string).Contains(@"\"))
                Uri uri = new Uri
                BitmapImage source = new BitmapImage(uri);
                return source;
                Uri uri = new Uri("pack://application:,,,/Images/folder.png");
                BitmapImage source = new BitmapImage(uri);
                return source;

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
            throw new NotSupportedException("Cannot convert back");

    #endregion // HeaderToImageConverter

So it can be seen that the HeaderToImageConverter accepts a string and returns an object. Basically the value parameter coming in is the TreeViewItems Header property, which we specified in the original binding. We don't care about the other parameters, but the Convert and ConvertBack method signature are dictated by the IValueConverter interface, so we must have the correct method signature, despite which parameters we actually end up using.

Anyway so the value parameter = the TreeViewItems Header property, that's all we care about right now. The next step was to see if this value (the TreeViewItems Header) contains a \ character, and if it does return the diskdrive Image Source Uri, otherwise I return a folder Image Source Uri. So that's pretty easy now, we just do a little string test, and then create the appropriate Uri. The only tricky bit here is that because the images are actually set to have a build action in Visual Studio of "Resource", we need to get the image path out of the application.

"Where does that awful tripple comma syntax come from?


What the heck does that mean.

The pack URI format is part of the XML Paper Specification (XPS), which can be found at

The specified format is pack://packageURI/partPath

The packageURI is actually a URI within a URI, so its encoded by converting its forward slashes into commas. This packageURI could point to an XPS document, such as file:///C:/Document.xps encoded as file:,,,c:,Documenr.xps, Or, in WPF programs it can be one of two URIs treated specially by the platform

  • siteOfOrigin:/// (encoded as siteOfOrigin:,,,)
  • application:/// (encoded as application:,,,)

Therefore, the tripple commas are actually encoded forward slashes bit place holders for original parameters. (Note that these can also be specified with two slashes/commas rather than three).

The application:/// package is implicitly used by all the resource references that don't use siteOfOrigin. In other words, the following URI specified in XAML:


is really just shorthand notation for


and this URI


is shorthand notation for:


You could use these longer and more explicit URIs in XAML, but there's no good reason to."

Windows Presentation Foundation Unleashed. Adam Nathan, Sams. 2007

That's It

I hope this helps anyone that wants to create a better fully functional, explorer tree in WPF. This one satisfied my requirements.

What do you Think ?

I would just like to ask, if you liked the article please vote for it, and leave some comments, as it lets me know if the article was at the right level or not, and whether it contained what people need to know.


  • v1.0 09/11/07: Initial issue


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.


I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

You may also be interested in...


Comments and Discussions

QuestionWere you able to implement Incremental Search? Pin
asseem14-Jul-12 8:07
memberasseem14-Jul-12 8:07 
GeneralGreate,thx! Pin
lingyun.china28-Jun-12 17:51
memberlingyun.china28-Jun-12 17:51 
QuestionAdditional to the form Pin
elkoko8731-May-12 12:30
memberelkoko8731-May-12 12:30 
QuestionThank you Pin
anthride23-Feb-12 6:10
memberanthride23-Feb-12 6:10 
GeneralMy vote of 5 Pin
David Wainwright10-Jan-12 2:04
memberDavid Wainwright10-Jan-12 2:04 
QuestionWhat do you have to do if you only want to have the content of one directory map? Pin
the original stinger28-Nov-11 0:02
memberthe original stinger28-Nov-11 0:02 
AnswerRe: What do you have to do if you only want to have the content of one directory map? Pin
Sacha Barber28-Nov-11 1:11
mvpSacha Barber28-Nov-11 1:11 
GeneralRe: What do you have to do if you only want to have the content of one directory map? Pin
Member 842698629-Mar-12 2:46
memberMember 842698629-Mar-12 2:46 
What if i want the images to display in a listView along the side of the files and folders like windows explorer?
What will i use instead of Setter Property="HeaderTemplate" in my listview

GeneralMy vote of 5 Pin
Deep Ash27-Dec-10 22:29
memberDeep Ash27-Dec-10 22:29 
GeneralVery good [modified] Pin
jian.zeng6-Dec-10 23:46
memberjian.zeng6-Dec-10 23:46 
GeneralNice one Pin
Member 365035817-Nov-10 19:26
memberMember 365035817-Nov-10 19:26 
GeneralVerry very helpful Pin
Member 220236126-Oct-10 7:21
memberMember 220236126-Oct-10 7:21 
GeneralGreat ! Pin
Aybe21-Sep-09 5:27
memberAybe21-Sep-09 5:27 
QuestionHow to display treeview from database Pin
Member 603819613-May-09 19:50
memberMember 603819613-May-09 19:50 
GeneralMy vote of 1 Pin
winSharp9318-Feb-09 5:38
memberwinSharp9318-Feb-09 5:38 
GeneralNice job Pin
holy_spirit4-Feb-09 8:34
memberholy_spirit4-Feb-09 8:34 
GeneralRe: Nice job Pin
Sacha Barber4-Feb-09 10:23
mvpSacha Barber4-Feb-09 10:23 
GeneralRe: Nice job Pin
holy_spirit4-Feb-09 22:58
memberholy_spirit4-Feb-09 22:58 
GeneralRe: Nice job Pin
Sacha Barber5-Feb-09 1:13
mvpSacha Barber5-Feb-09 1:13 
GeneralDodge the horrible ,,, syntax Pin
captainplanet012310-Nov-08 0:50
membercaptainplanet012310-Nov-08 0:50 
GeneralRe: Dodge the horrible ,,, syntax Pin
Sacha Barber10-Nov-08 3:15
mvpSacha Barber10-Nov-08 3:15 
GeneralExcellent work, thank you. Pin
makaveli_000030-Oct-08 6:22
membermakaveli_000030-Oct-08 6:22 
GeneralRe: Excellent work, thank you. Pin
Sacha Barber30-Oct-08 8:17
mvpSacha Barber30-Oct-08 8:17 
GeneralJust a proposal.. Pin
ezazazel1-Oct-08 12:53
memberezazazel1-Oct-08 12:53 
GeneralRe: Just a proposal.. Pin
Sacha Barber1-Oct-08 22:48
mvpSacha Barber1-Oct-08 22:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180111.1 | Last Updated 9 Nov 2007
Article Copyright 2007 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid