Nested HierarchicalDataTemplate for leaf and node collection
-
13 aprilie 2012 01:40
Hi,
I have an XML file containing node and leaf node and I want to display them in a treeview. But I have some difficulties understanding how the HierarchicalDataTemplate/DataTemplate works.
First this is my XML file :<?xml version="1.0" encoding="utf-8" ?> <root> <node name="Event"> <leaf name="Alarm"></leaf> <leaf name="Historic"></leaf> <leaf name="Configuration"></leaf> </node> <node name="System"> <node name="Configuration"> <leaf name="Base configuration"></leaf> <leaf name="Advance configuration"></leaf> </node> <node name="State"> <leaf name="Initial state"></leaf> <leaf name="Shutdown state"></leaf> </node> </node> </root>
From that I create a SampleDataSource that I add to my document :
<SampleData:root x:Key="XMLMyDataSampleDataSource" d:IsDataSource="True"/>
That's what I've done so far to display in the treeview :
<HierarchicalDataTemplate x:Key="leafTemplate"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="nodeTemplate" ItemsSource="{Binding leafCollection}" ItemTemplate="{StaticResource leafTemplate}"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="menuTemplate" ItemsSource="{Binding nodeCollection}" ItemTemplate="{StaticResource leafTemplate}"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> ... <Grid DataContext="{Binding Source={StaticResource XMLMyDataSampleDataSource}}"> <TreeView ItemsSource="{Binding nodeCollection}" ItemTemplate="{StaticResource menuTemplate}" ClipToBounds="True" DataContext="{Binding}"/> </Grid>But this is not giving the correct representation of the XML tree. So far I havetried many combinations of HierarchicalDataTemplate/DataTemplate,but every timesomething is missing.
I've already done it using an XMLDataSource but as I'm leaning WPF I would like to done it using a SampleData.
Does anyone have an idea on how to do this properly ? I put many hours trying to figure out, but in vain! :(
Best regards,
Toate mesajele
-
13 aprilie 2012 14:09
Hi,
Here's another way I tried, but it still does not work :(
<!-- For each element of type "node" that has a collection of sub node --> <HierarchicalDataTemplate DataType="{x:Type SampleData:node}" ItemsSource="{Binding nodeCollection}"> <HierarchicalDataTemplate.ItemTemplate> <!-- For each sub-element of type "node" *** PROBLEM *** --> <DataTemplate DataType="{x:Type SampleData:node}"> <TextBlock Text="{Binding Path=name}" /> </DataTemplate> </HierarchicalDataTemplate.ItemTemplate> <TextBlock Text="{Binding Path=name}" /> </HierarchicalDataTemplate> <!-- For each element of type "leaf" --> <DataTemplate DataType="{x:Type SampleData:leaf}" > <TextBlock Text="{Binding Path=name}" /> </DataTemplate>Butaccording to logic,it should work ?
But I thinkmy mistake is probably inlineorwhatis written ***PROBLEM***. Itwould have to beanotherHiearchicalDataTemplateinstead ofItemTemplate.But I'm not sure...
So here is another try :<!-- For each element of type "node" that has a collection of sub node --> <HierarchicalDataTemplate DataType="{x:Type SampleData:node}" ItemsSource="{Binding nodeCollection}"> <HierarchicalDataTemplate.ItemTemplate> <!-- For each sub-element of type "node" having sub element of type leafCollection --> <HierarchicalDataTemplate DataType="{x:Type SampleData:node}" ItemsSource="{Binding leafCollection}"> <TextBlock Text="{Binding Path=name}" /> </HierarchicalDataTemplate> </HierarchicalDataTemplate.ItemTemplate> <TextBlock Text="{Binding Path=name}" /> </HierarchicalDataTemplate> <!-- For each element of type "leaf" --> <DataTemplate DataType="{x:Type SampleData:leaf}" > <TextBlock Text="{Binding Path=name}" /> </DataTemplate>
Wow now I'm prety close but this is not working yet. The first level node having only leaf item are not displayed...
-
13 aprilie 2012 17:12
> Nested HierarchicalDataTemplate for leaf and node collection
try using the following example
<Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525"> <TreeView ItemsSource="{Binding Elements[node]}" ItemTemplate="{DynamicResource node}"> <TreeView.Resources> <Style TargetType="TreeViewItem"> <Setter Property="IsExpanded" Value="True" /> </Style> <local:NodeTemplateSelector x:Key="nts" /> <DataTemplate x:Key="leaf"> <TextBlock Text="{Binding Attribute[name].Value, StringFormat='Leaf: {0}'}" /> </DataTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Elements}" x:Key="node" ItemTemplateSelector="{StaticResource nts}"> <TextBlock Text="{Binding Attribute[name].Value, StringFormat='Node: {0}'}" /> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView> </Window>using System.Windows; using System.Windows.Controls; using System.Xml.Linq; namespace WpfApplication1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var xe = XElement.Load("..\\..\\XmlFile1.xml"); this.DataContext = xe; } } public class NodeTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { var xe = item as XElement; if (xe == null) return null; return (container as FrameworkElement).FindResource(xe.Name.LocalName) as DataTemplate; } } }
-
16 aprilie 2012 12:00
Wow thank Malobukv.
But last week I finally find a way to solution this problem. But it seem to be the same solution as your. I've not had time to post the answer here before the weekend: (
<local:MenuItemTemplateSelector x:Key="menuItemTemplateSelector"/>
<DataTemplate x:Key="leafTemplate" DataType="{x:Type SampleData:leaf}"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </DataTemplate> <HierarchicalDataTemplate x:Key="nodeWithSubNodeTemplate" DataType="{x:Type SampleData:node}" ItemsSource="{Binding nodeCollection}"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="nodeWithLeafTemplate" DataType="{x:Type SampleData:node}" ItemsSource="{Binding leafCollection}"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> ... <Grid DataContext="{Binding Source={StaticResource XMLMenuOptionsSampleDataSource}}" ClipToBounds="True" DockPanel.Dock="Bottom" Height="240"> <TreeView ItemsSource="{Binding nodeCollection}" ClipToBounds="True" DataContext="{Binding}" ItemTemplateSelector="{StaticResource menuItemTemplateSelector}"> </TreeView> </Grid>And there is the TemplateSelector
public class MenuItemTemplateSelector : DataTemplateSelector { public override DataTemplate SelectTemplate(object item, DependencyObject container) { Window window = Application.Current.MainWindow; if (item is Expression.Blend.SampleData.XMLMenuOptionsSampleDataSource.node) { Expression.Blend.SampleData.XMLMenuOptionsSampleDataSource.node n = ((Expression.Blend.SampleData.XMLMenuOptionsSampleDataSource.node)item); if (n.nodeCollection.Count > 0) { return (DataTemplate)window.FindResource("nodeWithSubNodeTemplate"); } else if (n.leafCollection.Count > 0) { return (DataTemplate)window.FindResource("nodeWithLeafTemplate"); } } return (DataTemplate)window.FindResource("leafTemplate"); } }
I finally realized it was impossible using just a XAML declaration. Since this would require two HierarchicalDataTemplate. Two with the same DataType, but with different ItemSource. Ex :
<DataTemplate x:Key="Leaf"> <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </DataTemplate> <HierarchicalDataTemplate DataType="{x:Type SampleData:node}" ItemsSource="{Binding nodeCollection}" > <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="{x:Type SampleData:node}" ItemsSource="{Binding leafCollection}" > <StackPanel> <TextBlock Text="{Binding name}"/> </StackPanel> </HierarchicalDataTemplate>
But having two HierarchicalDataTemplate having the same DataType and no Key defined is not authorized...
Anyway, thanks to all for your helps :)
Best regards- Editat de Erakis 16 aprilie 2012 12:02
- Marcat ca răspuns de Sheldon _XiaoModerator 1 mai 2012 07:34
-
16 aprilie 2012 12:11
But your solution intrigues me....
Why using ItemsSource="{Binding Elements}" ? What is Elements exactly ? Using this strategy avoiding having to declare two HierarchicalDataTemplate as my solution ?
I don't understand because I'm not treating my binding source as XML but as a collection. And I don't want too.
Previously, I was treating my collection in XML and I was able to do that in XAML. Here's how I did it:<XmlDataProvider x:Key="XMLMenuOptions" Source="XMLMenuOptions.xml" XPath="/root"> </XmlDataProvider> <HierarchicalDataTemplate DataType="node" ItemsSource="{Binding XPath=./*}"> <StackPanel Orientation="Horizontal"> <TextBlock FontWeight="Bold" Margin="5,0,0,0" Text="{Binding XPath=@name}"></TextBlock> </StackPanel> </HierarchicalDataTemplate> <HierarchicalDataTemplate DataType="leaf"> <StackPanel Orientation="Horizontal"> <TextBlock Margin="5,0,0,0" FontWeight="Normal" Text="{Binding XPath=@name}"></TextBlock> </StackPanel> </HierarchicalDataTemplate> -
17 aprilie 2012 05:56Moderator
Hi Erakis,
If you have resolved your issue?
best regards,
Sheldon _Xiao[MSFT]
MSDN Community Support | Feedback to us
Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.