Click here to Skip to main content
11,502,845 members (45,009 online)
Click here to Skip to main content

Custom TreeView Layout in WPF

, 24 Jan 2007 CPOL 395.3K 8K 216
Rate this:
Please Sign up or sign in to vote.
Shows how to turn a TreeView into an Org Chart.

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

          <!--<span class="code-comment"> This Border and ContentPresenter displays the
               content of the TreeViewItem. --></span>
          <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>

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

        <ControlTemplate.Triggers>
          <!--<span class="code-comment">When the item is selected in the TreeView, use the
              "selected" colors and give it a drop shadow. --></span>
          <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>

  <!--<span class="code-comment"> Make each TreeViewItem show it's children
       in a horizontal StackPanel. --></span>
  <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>
        <!--<span class="code-comment"> Import the resource dictionary file which
             contains the Style that makes TreeViewItems
             display their child items in an organization
             chart layout. --></span>
        <ResourceDictionary.MergedDictionaries>
          <ResourceDictionary Source="OrgChartTreeViewItemStyle.xaml" />
        </ResourceDictionary.MergedDictionaries>

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

    <!--<span class="code-comment"> Put the root item(s) in a centered Grid so that
         they will be centered and retain their width. --></span>
    <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)

Share

About the Author

Josh Smith
Software Developer (Senior) Cynergy Systems
United States United States
Josh creates software, for iOS and Windows.

He works at Cynergy Systems as a Senior Experience Developer.

Read his iOS Programming for .NET Developers[^] book to learn how to write iPhone and iPad apps by leveraging your existing .NET skills.

Use his Master WPF[^] app on your iPhone to sharpen your WPF skills on the go.

Check out his Advanced MVVM[^] book.

Visit his WPF blog[^] or stop by his iOS blog[^].
Follow on   Twitter

Comments and Discussions

 
QuestionKeyboard Navigation Pin
_Chris_Turner_20-Dec-13 22:53
member_Chris_Turner_20-Dec-13 22:53 
QuestionApply Same Style while Binding Treeview to Dataset [modified] Pin
deeps107018-Mar-13 8:08
memberdeeps107018-Mar-13 8:08 
QuestionExpand children on click Pin
Luigi Saggese6-Nov-12 0:54
memberLuigi Saggese6-Nov-12 0:54 
Questionhow can i draw line between the rectangles ? Pin
pouyan momeny22-Jan-12 22:20
memberpouyan momeny22-Jan-12 22:20 
QuestionDrag and Drop Pin
Member 248296826-Sep-11 20:44
memberMember 248296826-Sep-11 20:44 
QuestionTemplating a potentially infinite TreeView Pin
Ákos György Pfeff14-Mar-11 8:00
memberÁkos György Pfeff14-Mar-11 8:00 
GeneralSerialization of Default ControlTemplate Pin
gilles211-Feb-11 0:14
membergilles211-Feb-11 0:14 
GeneralHi Josh Pin
hovhannisyankaren11-Sep-10 8:43
memberhovhannisyankaren11-Sep-10 8:43 
GeneralRe: Hi Josh Pin
Josh Smith11-Sep-10 14:53
mvpJosh Smith11-Sep-10 14:53 
hovhannisyankaren wrote:
can I make TreeView like graph.


No, that's not possible to accomplish with the TreeView. You could render lines between a child and multiple "parents" but in terms of the TreeView/TreeViewItem object model, each node has one and only one parent node.
:josh:
Advanced MVVM[^]
Advance your MVVM skills

GeneralRe: Hi Josh Pin
hovhannisyankaren15-Sep-10 8:46
memberhovhannisyankaren15-Sep-10 8:46 
QuestionHow to display connecting lines along with node? Pin
Viji Raj5-Mar-10 20:36
memberViji Raj5-Mar-10 20:36 
QuestionRe: How to display connecting lines along with node? Pin
BaharDev1-Sep-10 18:30
memberBaharDev1-Sep-10 18:30 
AnswerRe: How to display connecting lines along with node? Pin
darrellp17-Dec-10 4:22
memberdarrellp17-Dec-10 4:22 
GeneralI am not familiar with WPF can u send me a c# version on ASP.NET Pin
pantherab10-Nov-09 2:22
memberpantherab10-Nov-09 2:22 
QuestionIs it possible to get the look of the ultratree (infragistic's winform) with columns? Pin
Joan20095-Jun-09 8:54
memberJoan20095-Jun-09 8:54 
QuestionHow to ADD GrandChild Items to Treeview in WPF Pin
venuvolla18-May-09 20:38
membervenuvolla18-May-09 20:38 
QuestionProgrammatically toggle the template? Pin
Rick Hansen17-May-09 6:19
memberRick Hansen17-May-09 6:19 
GeneralYou the man Pin
Rick Hansen15-May-09 11:01
memberRick Hansen15-May-09 11:01 
GeneralTabControl Pin
roberlamerma4-May-09 4:40
memberroberlamerma4-May-09 4:40 
QuestionBottom Up Pin
dfreeser16-Apr-09 14:18
memberdfreeser16-Apr-09 14:18 
AnswerRe: Bottom Up Pin
Member 80240312-Aug-11 23:28
memberMember 80240312-Aug-11 23:28 
Questionhow can i use custom treview(wpf) in my webpage Pin
anandvara10-Jan-09 1:57
memberanandvara10-Jan-09 1:57 
AnswerRe: how can i use custom treview(wpf) in my webpage Pin
Josh Smith10-Jan-09 3:28
mvpJosh Smith10-Jan-09 3:28 
GeneralExpander Pin
Member 21297158-Dec-08 4:18
memberMember 21297158-Dec-08 4:18 
QuestionHow about Using Expander ?? Pin
Gufran Sheikh20-Oct-08 4:07
memberGufran Sheikh20-Oct-08 4:07 
GeneralRe: How about Using Expander ?? Pin
Gufran Sheikh22-Oct-08 21:23
memberGufran Sheikh22-Oct-08 21:23 
GeneralRe: How about Using Expander ?? Pin
Gufran Sheikh24-Oct-08 21:46
memberGufran Sheikh24-Oct-08 21:46 
GeneralRe: How about Using Expander ?? Pin
Josh Smith25-Oct-08 2:07
mvpJosh Smith25-Oct-08 2:07 
GeneralRe: How about Using Expander ?? Pin
Josh Smith25-Oct-08 2:15
mvpJosh Smith25-Oct-08 2:15 
AnswerRe: How about Using Expander ?? [modified] Pin
Gufran Sheikh25-Oct-08 2:23
memberGufran Sheikh25-Oct-08 2:23 
GeneralRe: How about Using Expander ?? Pin
Josh Smith25-Oct-08 2:26
mvpJosh Smith25-Oct-08 2:26 
QuestionMultiple first-level items question Pin
Shulamit3423426-Jun-08 3:27
memberShulamit3423426-Jun-08 3:27 
GeneralVery nice and well done! [modified] Pin
R A Roldan19-Jun-08 10:33
memberR A Roldan19-Jun-08 10:33 
GeneralImplementing WPF into vb.net applications Pin
virtual.aussie11-Nov-07 22:25
membervirtual.aussie11-Nov-07 22:25 
GeneralRe: Implementing WPF into vb.net applications Pin
Josh Smith12-Nov-07 2:10
mvpJosh Smith12-Nov-07 2:10 
QuestionHow to add a node Pin
Arribajuan1-Nov-07 12:32
memberArribajuan1-Nov-07 12:32 
AnswerRe: How to add a node Pin
Josh Smith1-Nov-07 13:53
mvpJosh Smith1-Nov-07 13:53 
GeneralSetting a node explicitly Pin
anshubansal27-Aug-07 10:52
memberanshubansal27-Aug-07 10:52 
Generalprogrammatically set the selected item in a TreeView Pin
lotec23-Aug-07 3:28
memberlotec23-Aug-07 3:28 
GeneralRe: programmatically set the selected item in a TreeView Pin
anshubansal27-Aug-07 11:11
memberanshubansal27-Aug-07 11:11 
AnswerRe: programmatically set the selected item in a TreeView Pin
lotec28-Aug-07 3:08
memberlotec28-Aug-07 3:08 
GeneralRe: programmatically set the selected item in a TreeView Pin
Member 419148524-Oct-08 6:41
memberMember 419148524-Oct-08 6:41 
GeneralSpacing between the nodes Pin
sophia_singapore1-Jul-07 17:53
membersophia_singapore1-Jul-07 17:53 
GeneralRe: Spacing between the nodes Pin
Josh Smith2-Jul-07 1:52
mvpJosh Smith2-Jul-07 1:52 
QuestionSize of items and line between them? Pin
salsafyren22-Feb-07 4:22
membersalsafyren22-Feb-07 4:22 
AnswerRe: Size of items and line between them? Pin
Josh Smith2-Feb-07 6:08
mvpJosh Smith2-Feb-07 6:08 
GeneralRe: Size of items and line between them? Pin
salsafyren24-Feb-07 22:57
membersalsafyren24-Feb-07 22:57 
GeneralRe: Size of items and line between them? Pin
Josh Smith5-Feb-07 5:07
mvpJosh Smith5-Feb-07 5:07 
GeneralRe: Size of items and line between them? Pin
roland rodriguez26-May-08 19:25
memberroland rodriguez26-May-08 19:25 
GeneralRe: Size of items and line between them? Pin
Josh Smith27-May-08 3:20
mvpJosh Smith27-May-08 3:20 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150520.1 | Last Updated 24 Jan 2007
Article Copyright 2007 by Josh Smith
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid