locked
Binding any XML document to WPF TreeView RRS feed

  • 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.

    -Boris

    Thursday, 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
    doc.LoadXml( @"<root> <child1>text1<child11>text11</child11> </child1> <child2>text2<child21>text21</child21> <child22>text22</child22> </child2> </root>"); dataProvider.Document = doc; }
    kind regards hapevau
    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
    doc.LoadXml( @"<root> <child1>text1<child11>text11</child11> </child1> <child2>text2<child21>text21</child21> <child22>text22</child22> </child2> </root>"); dataProvider.Document = doc; }
    kind regards hapevau
    Saturday, May 30, 2009 5:34 PM
  • Thank you that worked out great!
    Wednesday, June 3, 2009 2:01 PM