Answered by:
Binding any XML document to WPF TreeView

Question
-
I have tried to do the following:
1. Bind XML Document to WPF TreeView via XML Provider and HierarchicalDataTemplate. I was able to do this successfully.
2. Display all nodes of the XML Document including those that have child nodes in following format:
>Node1
Node Contents
>ChildNode1
ChildNode1 Contents
>ChildNode1'sChildNode
ChildNode1'sChildNode Contents
>Node2
Node 2 Contents
I have achieved above by writing a recursive function which parses XML.
Problem is that it is not best way to solve this problem. It takes some time to parse XML document and construct TreeViewItems.
There is a way to bind XML Document directly to TreeeView via XML Document Provider and HierarchicalDataTemplate.
It works only partially.
Here's my XAML:<Window x:Class="BWorkerWPF.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="XML Loader" Height="680" Width="718"> <Window.Resources> <HierarchicalDataTemplate x:Key="NodeTemplate"> <HierarchicalDataTemplate.ItemsSource> <Binding XPath="child::*" /> </HierarchicalDataTemplate.ItemsSource> <TextBlock Text="{Binding Path=Name}" /> </HierarchicalDataTemplate> <XmlDataProvider x:Key="xmlDataProvider"></XmlDataProvider> </Window.Resources> <Grid> <TreeView Margin="0,24,0,273" Name="treeView1" Background="AliceBlue" ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}" ItemTemplate= "{StaticResource NodeTemplate}"/> <TextBox Height="210" Margin="0,0,0,65" Name="textBox1" VerticalAlignment="Bottom" IsReadOnly="True" TextWrapping="Wrap" /> <DockPanel Height="59" Name="dockPanel1" VerticalAlignment="Bottom" Background="AliceBlue"></DockPanel> <DockPanel Height="23" Name="dockPanel2" VerticalAlignment="Top" Background="AliceBlue"> <Button Height="23" Name="button1" Width="75" Click="button1_Click">Open</Button> <TextBox Height="22.48" Name="txtFileName" Background="AliceBlue" BorderThickness="0" /> </DockPanel> </Grid> </Window>
C#:
private void button1_Click(object sender, RoutedEventArgs e) { OpenFileDialog open = new OpenFileDialog(); open.Filter = "XML Files (*.xml)|*.xml"; if (open.ShowDialog(this) == true) { txtFileName.Text = open.FileName; xmlDocument.Load(txtFileName.Text); XmlDataProvider dataProvider = this.FindResource("xmlDataProvider") as XmlDataProvider; dataProvider.Document = xmlDocument; }
Currently this code binds to WPF TreeView but the layout is in following format:
>Node1
>ChildNode1
Node
Node
Node
>ChildNode2
Node
Node
Node
This is not what I wanted. I want all the nodes and node contents displayed in the TreeView.
I don't know the format and the schema of the XML document.
Please help me out.
-BorisThursday, May 28, 2009 8:57 PM
Answers
-
Hi,
change your XPath-Expression to child::node() and implement a datatrigger to distinguish between Element and Text to display Value or ElementName.
Here the XAML:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window1" Height="250" Width="450"> <Window.Resources> <HierarchicalDataTemplate x:Key="NodeTemplate"> <TextBlock x:Name="text" Text="?" /> <HierarchicalDataTemplate.ItemsSource> <Binding XPath="child::node()" /> </HierarchicalDataTemplate.ItemsSource> <HierarchicalDataTemplate.Triggers> <DataTrigger Binding="{Binding Path=NodeType}" Value="Text"> <Setter TargetName="text" Property="Text" Value="{Binding Path=Value}"></Setter> </DataTrigger> <DataTrigger Binding="{Binding Path=NodeType}" Value="Element"> <Setter TargetName="text" Property="Text" Value="{Binding Path=Name}"></Setter> </DataTrigger> </HierarchicalDataTemplate.Triggers> </HierarchicalDataTemplate> <XmlDataProvider x:Key="xmlDataProvider"></XmlDataProvider> </Window.Resources> <Grid > <TreeView Name="treeView1" Background="AliceBlue" ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}" ItemTemplate= "{StaticResource NodeTemplate}"/> </Grid> </Window>
public Window1() { InitializeComponent(); XmlDataProvider dataProvider = this.FindResource("xmlDataProvider") as XmlDataProvider; XmlDocument doc = new XmlDocument(); // Testdocument
kind regards hapevau
doc.LoadXml( @"<root> <child1>text1<child11>text11</child11> </child1> <child2>text2<child21>text21</child21> <child22>text22</child22> </child2> </root>"); dataProvider.Document = doc; }- Proposed as answer by Jim Zhou - MSFT Wednesday, June 3, 2009 1:34 PM
- Marked as answer by Boris Kleynbok Wednesday, June 3, 2009 2:00 PM
Saturday, May 30, 2009 5:34 PM
All replies
-
Hi,
change your XPath-Expression to child::node() and implement a datatrigger to distinguish between Element and Text to display Value or ElementName.
Here the XAML:
<Window x:Class="WpfApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window1" Height="250" Width="450"> <Window.Resources> <HierarchicalDataTemplate x:Key="NodeTemplate"> <TextBlock x:Name="text" Text="?" /> <HierarchicalDataTemplate.ItemsSource> <Binding XPath="child::node()" /> </HierarchicalDataTemplate.ItemsSource> <HierarchicalDataTemplate.Triggers> <DataTrigger Binding="{Binding Path=NodeType}" Value="Text"> <Setter TargetName="text" Property="Text" Value="{Binding Path=Value}"></Setter> </DataTrigger> <DataTrigger Binding="{Binding Path=NodeType}" Value="Element"> <Setter TargetName="text" Property="Text" Value="{Binding Path=Name}"></Setter> </DataTrigger> </HierarchicalDataTemplate.Triggers> </HierarchicalDataTemplate> <XmlDataProvider x:Key="xmlDataProvider"></XmlDataProvider> </Window.Resources> <Grid > <TreeView Name="treeView1" Background="AliceBlue" ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}" ItemTemplate= "{StaticResource NodeTemplate}"/> </Grid> </Window>
public Window1() { InitializeComponent(); XmlDataProvider dataProvider = this.FindResource("xmlDataProvider") as XmlDataProvider; XmlDocument doc = new XmlDocument(); // Testdocument
kind regards hapevau
doc.LoadXml( @"<root> <child1>text1<child11>text11</child11> </child1> <child2>text2<child21>text21</child21> <child22>text22</child22> </child2> </root>"); dataProvider.Document = doc; }- Proposed as answer by Jim Zhou - MSFT Wednesday, June 3, 2009 1:34 PM
- Marked as answer by Boris Kleynbok Wednesday, June 3, 2009 2:00 PM
Saturday, May 30, 2009 5:34 PM -
Thank you that worked out great!Wednesday, June 3, 2009 2:01 PM