Recursive Hiearchy using TreeView in WPF (databinding)
- 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?
Réponses
- 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>
Hope that helpspublic 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; } }
- Marqué comme réponseJim Zhou - MSFTModérateurvendredi 13 novembre 2009 08:40
- 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- Marqué comme réponseJim Zhou - MSFTModérateurvendredi 13 novembre 2009 08:40
Toutes les réponses
- 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>
Hope that helpspublic 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; } }
- Marqué comme réponseJim Zhou - MSFTModérateurvendredi 13 novembre 2009 08:40
- 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- Marqué comme réponseJim Zhou - MSFTModérateurvendredi 13 novembre 2009 08:40
- 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.
- 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 - Thanks a ton!
You are welcome, Wil Burton, if you are still having any issues with this, please feel free to ask.
Thanks.
Sincerely.
Jim Zhou -MSFT

