<HierarchicalDataTemplate x:Key="LargeAreaTemplate" DataType="{x:Type vm:LargeArea}" >If one needs one hierarchical structure with consistent parent-child relationship, defining DataType in HierarchicalDataTemplate will do the trick. However, what if one needs two different hierarchies in a tree view? If two different categories (let's say, for many-to-many relationship) should be shown in a give tree view, how can it be done with HierarchicalDataTemplate? The following picture shows an example.
There are 2 categories. By Area category shows Age child nodes. By Age category shows Area child nodes.
In a XAML, we can add different hierarchical data templates per each category. For [By Area] view, Area is parent and Age is child node type and vice versa for [By Age] view. If you look at below example, you can see that each category view has different data templates.
<Window x:Class="Tree.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="323" Width="253" xmlns:vm="clr-namespace:Tree" > <Window.Resources> <vm:MyTemplateSelector x:Key="MyTemplateSelector" /> <!-- AREA VIEW --> <HierarchicalDataTemplate x:Key="LargeAreaTemplate" DataType="{x:Type vm:LargeArea}" ItemsSource="{Binding AgeCollection}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> <TextBlock Text=" : Size=" /> <TextBlock Text="{Binding AreaSize}" /> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="SmallAreaTemplate" DataType="{x:Type vm:SmallArea}" ItemsSource="{Binding AgeCollection}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> <TextBlock Text=" : Population=" /> <TextBlock Text="{Binding Population}" /> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="LeafAgeTemplate" DataType="{x:Type vm:Age}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> </StackPanel> </HierarchicalDataTemplate> <!-- AGE VIEW --> <HierarchicalDataTemplate x:Key="AgeTemplate" DataType="{x:Type vm:Age}" ItemsSource="{Binding AreaCollection}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="LeafLargeAreaTemplate" DataType="{x:Type vm:LargeArea}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> <TextBlock Text=" : Size=" /> <TextBlock Text="{Binding AreaSize}" /> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="LeafSmallAreaTemplate" DataType="{x:Type vm:SmallArea}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" /> <TextBlock Text=" : Population=" /> <TextBlock Text="{Binding Population}" /> </StackPanel> </HierarchicalDataTemplate> <!-- Style --> <Style TargetType="TreeViewItem"> <Setter Property="IsExpanded" Value="True"/> </Style> </Window.Resources> <Grid Height="282" Width="230"> <Button Content="By Area" Height="23" HorizontalAlignment="Left" Margin="20,20,0,0" Name="btnArea" VerticalAlignment="Top" Width="90" Click="btnArea_Click" /> <Button Content="By Age" Height="23" HorizontalAlignment="Right" Margin="0,20,26,0" Name="btnAge" VerticalAlignment="Top" Width="90" Click="btnAge_Click" /> <TreeView Name="treeView1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="20,49,0,0" Width="184" Height="216" ItemsSource="{Binding Path=MyItems}" ItemTemplateSelector="{StaticResource MyTemplateSelector}"> </TreeView> </Grid> </Window>
Since TreeView only selects one unique data template at a time for any given type, the sample above is using custom data template selector in ItemTemplateSelector. In a code behind file, the following class is defined.
public class MyTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { MethodInfo mi = container.GetType().GetMethod("FindResource") as MethodInfo; if (mi != null) { if (MainWindow.ViewMode == ViewMode.ByArea) { switch (item.ToString()) { case "Tree.LargeArea": return mi.Invoke(container, new object[] { "LargeAreaTemplate" }) as DataTemplate; case "Tree.SmallArea": return mi.Invoke(container, new object[] { "SmallAreaTemplate" }) as DataTemplate; case "Tree.Age": return mi.Invoke(container, new object[] { "LeafAgeTemplate" }) as DataTemplate; } } else switch (item.ToString()) { case "Tree.Age": return mi.Invoke(container, new object[] { "AgeTemplate" }) as DataTemplate; case "Tree.LargeArea": return mi.Invoke(container, new object[] { "LeafLargeAreaTemplate" }) as DataTemplate; case "Tree.SmallArea": return mi.Invoke(container, new object[] { "LeafSmallAreaTemplate" }) as DataTemplate; } } return null; } }
Basically what it does is to find appropriate data template and return it back to TreeView. If null is returned, TreeView searches for appropriate hierarchical data template for the DataType.
showing data in TreeView bound with data
ReplyDelete