Click here to Skip to main content
6,629,885 members and growing! (24,474 online)
Email Password   helpLost your password?
Platforms, Frameworks & Libraries » Windows Presentation Foundation » Controls     Intermediate License: The Code Project Open License (CPOL)

Custom TreeView Layout in WPF

By Josh Smith

Shows how to turn a TreeView into an Org Chart.
C# 2.0, Windows, .NET 3.0, XAML, WPF, VS2005, Dev
Posted:5 Jan 2007
Updated:24 Jan 2007
Views:133,837
Bookmarked:112 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
35 votes for this article.
Popularity: 7.20 Rating: 4.66 out of 5

1

2
3 votes, 8.6%
3
5 votes, 14.3%
4
27 votes, 77.1%
5

Introduction

This article discusses how to customize the item layout in a WPF TreeView. The layout we will examine is quite similar to an "org chart", where each level of items is displayed in a horizontal row directly beneath their respective parent. Along the way we will see how the power of templates and styles in WPF can provide incredible flexibility for customizing an application's user interface.

This article is not for WPF beginners. It assumes that you already have knowledge of XAML, control templates, styles, triggers, hierarchical data templates, data binding, and other fundamentals of WPF.

I also posted another article regarding layout customization for the TreeView control. If you are interested in seeing another way that the TreeView can be customized, you might want to read Advanced Custom TreeView Layout in WPF.

Graphical overview

Before diving into the XAML which makes the magic happen, let's first take a look at what we are aiming to achieve. If I populate a TreeView with some simple data and view it, by default it looks pretty plain. Here is the "before" picture:

Before

What you see above is certainly not a breathtaking representation of the data. However, after we customize the way that TreeViewItems are rendered and how the TreeView positions its items, the same TreeView control can look like this:

After

How it works

The first step is to create a custom ControlTemplate for the TreeViewItem class. If you wrap that template in a typed Style (i.e. a Style with no Key) then it will automatically be applied to every TreeViewItem instance by default. The TreeViewItem control template should have two things: a ContentPresenter whose Name is 'PART_Header' and an ItemsPresenter. The ContentPresenter is used to display the content of the item. The ItemsPresenter is used to display it's child items.

In addition to customizing the TreeViewItem control template, you also must modify the ItemsPanel of TreeViewItem. In order for the child items to be displayed in a horizontal row, I set the TreeViewItem.ItemsPanel property to a StackPanel with a horizontal orientation. That setting was also applied in the typed Style mentioned previously.

Let's take a look at an abridged version of the typed Style:

<Style TargetType="TreeViewItem">
  <Style.Resources>
    <!-- Resources omitted for clarity… -->
  </Style.Resources>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="TreeViewItem">
        <Grid Margin="2">
          <Grid.RowDefinitions>
            <!--The top row contains the item's content.-->
            <RowDefinition Height="Auto" />
            <!--The bottom row contains the item's children.-->
            <RowDefinition Height="*" />
          </Grid.RowDefinitions>

          <!-- This Border and ContentPresenter displays the
               content of the TreeViewItem. -->
          <Border Name="Bd"
            Background="{StaticResource ItemAreaBrush}"
            BorderBrush="{StaticResource ItemBorderBrush}"
            BorderThickness="0.6"
            CornerRadius="8"
            Padding="6"
            >
            <ContentPresenter Name="PART_Header"                 
              ContentSource="Header"
              HorizontalAlignment="Center"
              VerticalAlignment="Center" />
          </Border>

          <!-- The ItemsPresenter displays the item's children. -->
          <ItemsPresenter Grid.Row="1"/>
        </Grid>

        <ControlTemplate.Triggers>
          <!--When the item is selected in the TreeView, use the
              "selected" colors and give it a drop shadow. -->
          <Trigger Property="IsSelected" Value="True">
            <Setter
              TargetName="Bd"
              Property="Panel.Background"                    
              Value="{StaticResource SelectedItemAreaBrush}" />
            <Setter
              TargetName="Bd"
              Property="Border.BorderBrush"                    
              Value="{StaticResource SelectedItemBorderBrush}" />
            <Setter
              TargetName="Bd"
              Property="TextElement.Foreground"                  
              Value="{DynamicResource
                {x:Static SystemColors.HighlightTextBrushKey}}" />
            <Setter
              TargetName="Bd"
              Property="Border.BitmapEffect"                 
              Value="{StaticResource DropShadowEffect}" />
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>

  <!-- Make each TreeViewItem show it's children
       in a horizontal StackPanel. -->
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <StackPanel
          HorizontalAlignment="Center"
          IsItemsHost="True"
          Margin="4,6"
          Orientation="Horizontal"  />
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
</Style>

The final step is to make the TreeView center the root item(s) horizontally. Doing so will provide symmetry between the items, as seen in the screenshot above. This step is a simple matter of setting the TreeView's ItemsPanel property to a Grid whose HorizontalAlignment is set to 'Center'. Let's take a look at the XAML for a Window which contains our customized TreeView:

<Window x:Class="CustomTreeViewLayout.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CustomTreeViewLayout"
    Title="Custom TreeView" Height="350" Width="780"
    Loaded="OnLoaded"
    WindowStartupLocation="CenterScreen"
    FontSize="11"
    >
  <TreeView Name="tree">
    <TreeView.Resources>
      <ResourceDictionary>
        <!-- Import the resource dictionary file which
             contains the Style that makes TreeViewItems
             display their child items in an organization
             chart layout. -->
        <ResourceDictionary.MergedDictionaries>
          <ResourceDictionary Source="OrgChartTreeViewItemStyle.xaml" />
        </ResourceDictionary.MergedDictionaries>

        <!-- This template explains how to render
             a Node object and its child nodes. -->
        <HierarchicalDataTemplate
          DataType="{x:Type local:Node}"
          ItemsSource="{Binding ChildNodes}"
          >
          <TextBlock Text="{Binding Text}" />
        </HierarchicalDataTemplate>
      </ResourceDictionary>
    </TreeView.Resources>

    <!-- Put the root item(s) in a centered Grid so that
         they will be centered and retain their width. -->
    <TreeView.ItemsPanel>
      <ItemsPanelTemplate>
        <Grid
          HorizontalAlignment="Center"
          IsItemsHost="True" />
      </ItemsPanelTemplate>
    </TreeView.ItemsPanel>
  </TreeView>
</Window>

I am not going to discuss the code which populates the TreeView with dummy data. Feel free to peruse that code (and all the rest of it) in the source code download, which is available at the top of this article.

Tip

Customizing the ControlTemplate for the TreeViewItem class was easy once I discovered a little trick. I serialized the default TreeViewItem control template to XAML and then modified that until I got the result I was looking for.

The Big Bummer

Unfortunately there is no supported way to programmatically set the selected item in a TreeView. The TreeView's SelectedItem property does not have a setter. As a result, I could not customize the keyboard navigation for the TreeView. The demo project prevents the TreeView from responding to keyboard input altogether. If you enable keyboard navigation in the demo you will find that it is very unintuitive to navigate the items. Hopefully one day there will be a way to customize the keyboard navigation of a TreeView, but until then...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Josh Smith


Member
Josh creates software, mostly with C# and XAML.

He works at IdentityMine as a Senior UX Developer.

He plays the music of J.S. Bach on the piano, but has started branching into other composers recently.

Get his runtime debugging and scripting tool, called Crack.NET, right here[^].

Download his WPF.JoshSmith library here[^]

You can check out his WPF blog here[^].

You can take his guided tour of WPF here[^].

You can check out a powerful debugger visualizer he worked on called Mole for Visual Studio here[^].

His Microsoft MVP profile can be viewed here[^].
Occupation: Software Developer (Senior)
Company: IdentityMine, Inc.
Location: United States United States

Other popular Windows Presentation Foundation articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 25 of 51 (Total in Forum: 51) (Refresh)FirstPrevNext
GeneralI am not familiar with WPF can u send me a c# version on ASP.NET Pinmemberpantherab3:22 10 Nov '09  
GeneralIs it possible to get the look of the ultratree (infragistic's winform) with columns? PinmemberJoan20099:54 5 Jun '09  
GeneralHow to ADD GrandChild Items to Treeview in WPF Pinmembervenuvolla21:38 18 May '09  
GeneralProgrammatically toggle the template? PinmemberRick Hansen7:19 17 May '09  
GeneralYou the man PinmemberRick Hansen12:01 15 May '09  
GeneralTabControl Pinmemberroberlamerma5:40 4 May '09  
QuestionBottom Up Pinmemberdfreeser15:18 16 Apr '09  
Questionhow can i use custom treview(wpf) in my webpage Pinmemberanandvara2:57 10 Jan '09  
AnswerRe: how can i use custom treview(wpf) in my webpage PinmvpJosh Smith4:28 10 Jan '09  
GeneralExpander PinmemberMember 21297155:18 8 Dec '08  
QuestionHow about Using Expander ?? PinmemberGufran Sheikh5:07 20 Oct '08  
GeneralRe: How about Using Expander ?? PinmemberGufran Sheikh22:23 22 Oct '08  
GeneralRe: How about Using Expander ?? PinmemberGufran Sheikh22:46 24 Oct '08  
GeneralRe: How about Using Expander ?? PinmvpJosh Smith3:07 25 Oct '08  
GeneralRe: How about Using Expander ?? PinmvpJosh Smith3:15 25 Oct '08  
AnswerRe: How about Using Expander ?? [modified] PinmemberGufran Sheikh3:23 25 Oct '08  
GeneralRe: How about Using Expander ?? PinmvpJosh Smith3:26 25 Oct '08  
QuestionMultiple first-level items question PinmemberShulamit342344:27 26 Jun '08  
GeneralVery nice and well done! [modified] PinmemberR A Roldan11:33 19 Jun '08  
GeneralImplementing WPF into vb.net applications Pinmembervirtual.aussie23:25 11 Nov '07  
GeneralRe: Implementing WPF into vb.net applications PinmvpJosh Smith3:10 12 Nov '07  
virtual.aussie wrote:
If I correctly understood, WPF is used for making independent applications, wrote completely in XAML and it cannot be incorporated into existed VB.NET applications. Is that true?

Well, it depends on what you mean by "existed VB.NET applications."  If you are referring to a VB.NET WinForms app, you can use WPF controls there.  If you mean ASP.NET apps, you can compile some WPF app into an XBAP and serve that up to the user. 

WPF apps are not necessarily written only in XAML.  You can use code if you want to.  In fact, XAML is not at all necessary!

virtual.aussie wrote:
I was looking for a way to implement skins into my application and it seemed to me that the WPF could be a nice way to do it.

I wrote an article about creating skinned UIs in WPF, check it out here[^].


:josh:
My WPF Blog[^]
Without a strive for perfection I would be terribly bored.

Sign In·View Thread·PermaLink
GeneralHow to add a node PinmemberArribajuan13:32 1 Nov '07  
GeneralRe: How to add a node PinmvpJosh Smith14:53 1 Nov '07  
GeneralSetting a node explicitly Pinmemberanshubansal11:52 27 Aug '07  
Generalprogrammatically set the selected item in a TreeView Pinmemberlotec4:28 23 Aug '07  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 24 Jan 2007
Editor: Sean Ewington
Copyright 2007 by Josh Smith
Everything else Copyright © CodeProject, 1999-2009
Web10 | Advertise on the Code Project