Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind Any XML document to WPF TreeView

I would like to bind any XML document to WPF TreeView using TypeConverter.

My original solution was to use recursion, but when document is large UI is heavily tied up.

Following link talks about TypeConverter but for particular node/element combination: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/edd843b7-b378-4c2d-926f-c053dbd7b340

What if not known what XML document looks like? Since this is for display purposes only I don't care much about functionality at this point I just want to bind XML to a TreeView.

like image 883
Boris Kleynbok Avatar asked May 07 '09 13:05

Boris Kleynbok


3 Answers

It works for other node types with a few simple modifications. First, HierarchicalDataTemplate.ItemsSource Binding XPath must be changed to "child::node()|attribute::*" to allow any child node and any attribute. Then, add DataTriggers for other NodeTypes. The example below worked for me. NOTE that i added icons for various NodeTypes, you might want to remove them:

        <HierarchicalDataTemplate x:Key="NodeTemplate">
        <StackPanel Orientation="Horizontal">
        <Image x:Name="icon" VerticalAlignment="Center" Margin="1,1,4,1"/>
        <TextBlock x:Name="name" Text="" />
        <TextBlock x:Name="inter" Text="" />
        <TextBlock x:Name="value" Text="" />
        </StackPanel>
        <HierarchicalDataTemplate.ItemsSource>
            <Binding XPath="child::node()|attribute::*" />
        </HierarchicalDataTemplate.ItemsSource>
        <HierarchicalDataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
                <Setter TargetName="icon" Property="Source" Value="icons/element.png"></Setter>
                <Setter TargetName="name" Property="Text" Value="{Binding Path=Name}"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
                <Setter TargetName="icon" Property="Source" Value="icons/text.png"></Setter>
                <Setter TargetName="value" Property="Text" Value="{Binding Path=Value}"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="Attribute">
                <Setter TargetName="icon" Property="Source" Value="icons/attribute.png"></Setter>
                <Setter TargetName="name" Property="Text" Value="{Binding Path=Name}"></Setter>
                <Setter TargetName="inter" Property="Text" Value=": "></Setter>
                <Setter TargetName="value" Property="Text" Value="{Binding Path=Value}"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="CDATA">
                <Setter TargetName="icon" Property="Source" Value="icons/cdata.png"></Setter>
                <Setter TargetName="value" Property="Text" Value="{Binding Path=Value}"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="Comment">
                <Setter TargetName="icon" Property="Source" Value="icons/comment.png"></Setter>
                <Setter TargetName="value" Property="Text" Value="{Binding Path=Value}"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=NodeType}" Value="ProcessingInstruction">
                <Setter TargetName="icon" Property="Source" Value="icons/pi.png"></Setter>
                <Setter TargetName="value" Property="Text" Value="{Binding Path=Value}"></Setter>
            </DataTrigger>
        </HierarchicalDataTemplate.Triggers>
    </HierarchicalDataTemplate>
like image 77
receptor Avatar answered Nov 03 '22 01:11

receptor


So I have asked a question on how to bind any XML document regardless of schema to tree view in the following way: 1. Bind XML Document to WPF TreeView via XML Provider and HierarchicalDataTemplate. 2. Display all nodes of the XML Document including those that have child nodes in following format:

>Node1

Node1 Contents

    >ChildNode1

       ChildNode1 Contents

            >ChildNode1'sChildNode

              ChildNode1'sChildNode Contents

>Node2

  Node2 Contents

Problem was that my TreeView was binding each XmlNode name property to TreeItem. In case of text XmlNode it would bind #text to the TreeItem which was not what I wanted.

So via a post on MSDN forum I got my answer: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/cbdb2420-1403-436f-aa7f-b1e3b1acb398/

So the trick was to use triggers to set value based on type of node encountered.

Caveat is that other types of nodes will be ignored and XML document may contain diffrent elements, so this might not work for every type of node encountered.

Here's 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>

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;
    }
like image 41
Boris Kleynbok Avatar answered Nov 03 '22 00:11

Boris Kleynbok


Have a look at my answer on the following thread - Binding XML data to WPF treeview Control i believe this is exactly what you're looking for.The link in the thread points to a post which gives you a step by step example with an option to download the source code.The example is written in such a way as to bind any XML document to a WPF tree view

like image 30
Denys Wessels Avatar answered Nov 03 '22 01:11

Denys Wessels