WPF: Skinning a TreeView with Resources

Tom 420 words

In my first WPF project (a port of a WinForms picture viewer), I needed to create a TreeView with icons on each node. It doesn’t take long to realize that the WPF TreeView doesn’t have this functionality built-in anymore.

I found a bunch of Google resources, but none of them did quite what I wanted. Which was: I wanted to put a folder icon on expandable nodes and a file icon on each leaf. I also wanted an icon to indicate an error condition on the file/folder. Seems like a pretty standard set of requirements to me, but all of the examples I managed to find only showed you how to put the same image on every node or leaf.

First I tried “skinning” the images in the XAML as shown here. That didn’t work, because as I said above it only put the same image on every node.

Next I tried programmatically adding the images (also shown here) by putting a StackPanel in each TreeViewItem.Header. That didn’t work either, because it stopped indenting the TreeView, not to mention that all of the collapse/expand icons disappeared!

From the XAML examples on Google, it seemed clear that I needed to set the TreeViewItem.HeaderTemplate property instead of Header. So I next tried to programmatically create a DataTemplate for use with HeaderTemplate. That quickly devolved into a syntactic nightmare, so I went back into the XAML.

After some more stumbling around I finally ended up defining a DataTemplate resource for each type of node I wanted.

«/font>TreeView Name=“tvFiles” Grid.RowSpan=“3″ Loaded=“tvFiles_Loaded” SelectedItemChanged=“tvFiles_SelectedItemChanged” Margin=“0,0,12,0″>

«/font>TreeView.Resources>

<!- These templates are accessible through tvFiles.Resources ->

«/font>DataTemplate x:Key=“GreenFolder”>

«/font>StackPanel Orientation=“Horizontal”>

«/font>Image Source=“icon_folder.gif” Margin=“0,0,2,0″ />

«/font>TextBlock Text=”{Binding}" FontWeight=“Bold” />

</StackPanel>

</DataTemplate>

«/font>DataTemplate x:Key=“RedFolder”>

«/font>StackPanel Orientation=“Horizontal”>

«/font>Image Source=“icon_folder.gif” Margin=“0,0,2,0″ />

«/font>TextBlock Text=”{Binding}" FontWeight=“Bold” Foreground=“DarkRed” />

«/font>Image Source=“icon_warning.gif” Margin=“2,0,0,2″ />

</StackPanel>

</DataTemplate>

«/font>DataTemplate x:Key=“GreenFile”>

«/font>StackPanel Orientation=“Horizontal”>

«/font>Image Source=“icon_picture.gif” Margin=“0,0,2,0″ />

«/font>TextBlock Text=”{Binding}” />

</StackPanel>

</DataTemplate>

«/font>DataTemplate x:Key=“RedFile”>

«/font>StackPanel Orientation=“Horizontal”>

«/font>Image Source=“icon_picture.gif” Margin=“0,0,2,0″ />

«/font>TextBlock Text=”{Binding}" Foreground=“DarkRed” />

«/font>Image Source=“icon_warning.gif” Margin=“2,0,0,2″ />

</StackPanel>

</DataTemplate>

</TreeView.Resources>

</TreeView>

Then in the code that populates the TreeView, I grabbed the appropriate DataTemplate from the TreeView.Resources collection and set the HeaderTemplate property.

TreeViewItem item = new TreeViewItem();

item.Header = text;

if( isDir )

{

item.HeaderTemplate = hasDescription ?

(DataTemplate)tvFiles.Resources[“GreenFolder”] : (DataTemplate)tvFiles.Resources[“RedFolder”];

}

else

{

item.HeaderTemplate = hasDescription ?

(DataTemplate)tvFiles.Resources[“GreenFile”] : (DataTemplate)tvFiles.Resources[“RedFile”];

}

nodes.Add( item );

It ended up looking like this:

It’s a much more powerful and flexible TreeView in WPF, but it’s sure a lot more work to add icons than it used to be.

Originally posted on my personal blog which was active from 2003 to 2020. You may have arrived here by redirection from the original permalink.

Elsewhere: Loading...

Sorry, new comments are disabled on older posts. This helps reduce spam. Active commenting almost always occurs within a day or two of new posts.

AI Disclosure: I write all posts by hand, but I may use AI assistance for image generation (they will be marked as such), file management, titles, summaries, tagging, HTML coding.