.NET Framework Developer Center > .NET Development Forums > Windows Presentation Foundation (WPF) > Recursive Hiearchy using TreeView in WPF (databinding)
Ask a questionAsk a question
 

AnswerRecursive Hiearchy using TreeView in WPF (databinding)

  • Friday, November 06, 2009 8:59 PMWil Burton Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I have a hiearchy I want to use in a treeview control. The closest approximation of my data is an organization chart. Each entity is child of another entity in the group. The schema I'm trying to use currently has just two fields: Name, ParentName both strings. The ParentName is nullable for those rows that sit at the top of the hierarchy. The child rows will just use the name of the parent to establish the link/hierarchy. I am completely new to WPF so I'm somewhat lost.

    I'm using Visual Studio 2010, though I would think this would work prior as well. Can anyone point me in the right direction on how to accomplish this?

Answers

  • Saturday, November 07, 2009 9:36 PMGuenter Schwaiger Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Hi Wil,

    use a HirarchicalDataTemplate.

    <Window x:Class="WpfApplication1.Window26"
    		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:local="clr-namespace:WpfApplication1"
    		Title="Window26" Height="300" Width="300">
        <Grid>
    		<TreeView ItemsSource="{Binding Items}" >
    			<TreeView.Resources>
    				<HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Childs}">
    					<TextBlock Text="{Binding Name}" />
    				</HierarchicalDataTemplate>
    			</TreeView.Resources>
    		</TreeView>
    	</Grid>
    </Window>
    
    


    public partial class Window26 : Window
    {
    	public Window26()
    	{
    		InitializeComponent();
    
    		this.Items = new List<Item>();
    
    		var item1 = new Item("Item 1");
    		item1.Childs.Add(new Item("Item 1.1"));
    		this.Items.Add(item1);
    
    		var item2 = new Item("Item 2");
    		var item2_1 = new Item("Item 2.1");
    
    		item2_1.Childs.Add(new Item("Item 2.3"));			
    		item2.Childs.Add(item2_1);
    		this.Items.Add(item2);
    
    		this.DataContext = this;
    	}
    
    	public List<Item> Items { get; private set; }
    }
    
    public class Item
    {
    	public Item(string name)
    	{
    		this.Childs = new List<Item>();
    		this.Name = name;
    	}
    
    	public List<Item> Childs { get; private set; }
    	public string Name { get; private set; }
    }
    
    Hope that helps
  • Friday, November 13, 2009 8:40 AMJim Zhou - MSFTModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi Wil Burton,

    If I understood you correctly, you have a recursive data source and want to display it via TreeView, this is the typical scenario HierarchicalDataTemplate comes into play. In the HierarchicalDataTemplate, you set ItemsSource property as data source for the next hierarchy, and put a UI element in the HierarchicalDataTemplate to bind the propety of the underlying data item. The following is a small code same of how to use HierarchicalDataTemplate, please check it out.
    Code snippet:

      <Window.Resources>

                <XmlDataProvider x:Key="treeData" XPath="*">

                    <x:XData>

                        <Items Name="Items" xmlns="">

                            <Item1/>

                            <Item2>

                                <Item22/>

                                <Item12/>

                                <Item13>

                                    <Item131/>

                                    <Item131/>

                                </Item13>

                            </Item2>

                        </Items>

                    </x:XData>

                </XmlDataProvider>

                <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}"

                                          x:Key="template">

                    <TextBlock Name="textBlock"

                               Text="{Binding Name}"/>

            </HierarchicalDataTemplate>

            </Window.Resources>

            <TreeView ItemTemplate="{StaticResource template}"

                  ItemsSource="{Binding Source={StaticResource treeData}}">

                <TreeView.ItemContainerStyle>

                    <!--Using style setter to set the TreeViewItem.IsExpanded property to true, this will be applied

          to all TreeViweItems when they are generated-->

                    <Style TargetType="{x:Type TreeViewItem}">

                        <Setter Property="IsExpanded" Value="True"/>

                    </Style>

                </TreeView.ItemContainerStyle>

            </TreeView>

    Any issues, please feel free to feed back.
    Thanks.
    Sincerely.


    Jim Zhou -MSFT

All Replies

  • Saturday, November 07, 2009 9:36 PMGuenter Schwaiger Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Hi Wil,

    use a HirarchicalDataTemplate.

    <Window x:Class="WpfApplication1.Window26"
    		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    		xmlns:local="clr-namespace:WpfApplication1"
    		Title="Window26" Height="300" Width="300">
        <Grid>
    		<TreeView ItemsSource="{Binding Items}" >
    			<TreeView.Resources>
    				<HierarchicalDataTemplate DataType="{x:Type local:Item}" ItemsSource="{Binding Childs}">
    					<TextBlock Text="{Binding Name}" />
    				</HierarchicalDataTemplate>
    			</TreeView.Resources>
    		</TreeView>
    	</Grid>
    </Window>
    
    


    public partial class Window26 : Window
    {
    	public Window26()
    	{
    		InitializeComponent();
    
    		this.Items = new List<Item>();
    
    		var item1 = new Item("Item 1");
    		item1.Childs.Add(new Item("Item 1.1"));
    		this.Items.Add(item1);
    
    		var item2 = new Item("Item 2");
    		var item2_1 = new Item("Item 2.1");
    
    		item2_1.Childs.Add(new Item("Item 2.3"));			
    		item2.Childs.Add(item2_1);
    		this.Items.Add(item2);
    
    		this.DataContext = this;
    	}
    
    	public List<Item> Items { get; private set; }
    }
    
    public class Item
    {
    	public Item(string name)
    	{
    		this.Childs = new List<Item>();
    		this.Name = name;
    	}
    
    	public List<Item> Childs { get; private set; }
    	public string Name { get; private set; }
    }
    
    Hope that helps
  • Friday, November 13, 2009 8:40 AMJim Zhou - MSFTModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi Wil Burton,

    If I understood you correctly, you have a recursive data source and want to display it via TreeView, this is the typical scenario HierarchicalDataTemplate comes into play. In the HierarchicalDataTemplate, you set ItemsSource property as data source for the next hierarchy, and put a UI element in the HierarchicalDataTemplate to bind the propety of the underlying data item. The following is a small code same of how to use HierarchicalDataTemplate, please check it out.
    Code snippet:

      <Window.Resources>

                <XmlDataProvider x:Key="treeData" XPath="*">

                    <x:XData>

                        <Items Name="Items" xmlns="">

                            <Item1/>

                            <Item2>

                                <Item22/>

                                <Item12/>

                                <Item13>

                                    <Item131/>

                                    <Item131/>

                                </Item13>

                            </Item2>

                        </Items>

                    </x:XData>

                </XmlDataProvider>

                <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}"

                                          x:Key="template">

                    <TextBlock Name="textBlock"

                               Text="{Binding Name}"/>

            </HierarchicalDataTemplate>

            </Window.Resources>

            <TreeView ItemTemplate="{StaticResource template}"

                  ItemsSource="{Binding Source={StaticResource treeData}}">

                <TreeView.ItemContainerStyle>

                    <!--Using style setter to set the TreeViewItem.IsExpanded property to true, this will be applied

          to all TreeViweItems when they are generated-->

                    <Style TargetType="{x:Type TreeViewItem}">

                        <Setter Property="IsExpanded" Value="True"/>

                    </Style>

                </TreeView.ItemContainerStyle>

            </TreeView>

    Any issues, please feel free to feed back.
    Thanks.
    Sincerely.


    Jim Zhou -MSFT
  • Friday, November 13, 2009 9:05 PMWil Burton Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    This works really well, thanks! On a semi-related note, how hard is it to customize the look of the TreeView control? What I really want is a top down, hierarchical tree like an org. chart rather than the default look.
  • Monday, November 16, 2009 8:23 AMJim Zhou - MSFTModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,

    -->how hard is it to customize the look of the TreeView control?

    To customize the TreeView, you first need to have a basic understanding about the default template, and then you can custom it to what you want it to be. In terms of customizing the TreeView, I recommend that you can check out the below two blog posts, both of them are extraordinary and informative:
     http://www.codeproject.com/KB/WPF/AdvancedCustomTreeViewLyt.aspx
    http://www.codeproject.com/KB/WPF/CustomTreeViewLayout.aspx

    For your reference, you can using XamlWriter.Save method to get the build-in template of Control, the following is the control template of TreeView.

    XAML markup:

     <ControlTemplate

       TargetType="TreeView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

        <Border

          BorderThickness="{TemplateBinding Border.BorderThickness}"

          BorderBrush="{TemplateBinding Border.BorderBrush}"

          Name="Bd"

          SnapsToDevicePixels="True">

            <ScrollViewer

             CanContentScroll="False"

             HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"

             VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"

             Background="{TemplateBinding Panel.Background}"

             Padding="{TemplateBinding Control.Padding}"

             Name="_tv_scrollviewer_"

             SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"

             Focusable="False">

                <ItemsPresenter />

            </ScrollViewer>

        </Border>

        <ControlTemplate.Triggers>

            <Trigger

             Property="UIElement.IsEnabled">

                <Setter

                Property="Panel.Background"

                TargetName="Bd">

                    <Setter.Value>

                        <DynamicResource

                      ResourceKey="{x:Static SystemColors.ControlBrushKey}" />

                    </Setter.Value>

                </Setter>

                <Trigger.Value>

                    <s:Boolean>False</s:Boolean>

                </Trigger.Value>

            </Trigger>

            <Trigger

             Property="VirtualizingStackPanel.IsVirtualizing">

                <Setter

                Property="ScrollViewer.CanContentScroll"

                TargetName="_tv_scrollviewer_">

                    <Setter.Value>

                        <s:Boolean>True</s:Boolean>

                    </Setter.Value>

                </Setter>

                <Trigger.Value>

                    <s:Boolean>True</s:Boolean>

                </Trigger.Value>

            </Trigger>

        </ControlTemplate.Triggers>

    </ControlTemplate>


    Thanks.
    Sincerely.
    Jim Zhou -MSFT
  • Monday, November 16, 2009 2:55 PMWil Burton Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks a ton!
  • Tuesday, November 17, 2009 8:23 AMJim Zhou - MSFTModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    You are welcome, Wil Burton, if you are still having any issues with this, please feel free to ask.

    Thanks.
    Sincerely.


    Jim Zhou -MSFT