2
votes

Note: See the bottom of this post for the solution.

I'm trying to use XAML's "HierarchicalDataTemplate" to display an xml document in a TreeView. My current XAML code will display the first child of the "Parent" node but not subsequent child nodes of different types.

Can I use XAML to display children of different types under a common parent?

I've boiled the problem down to a very basic sample for illustrative purposes.

I want my treeview to look like this (minus the stuff in parenthesis):

Parent: Roger (Type="Parent")
 |--Rug rats (Type="Children")
 |     |--Bob (Type="Child")
 |     |--Tom
 |
 |--Gear (Type="Equipment")  <-- **can't display this or its child nodes**
       |--Canoe (Type="Item")
       |--Tent

In this example, "Parent" nodes have 2 types of child nodes; "Children" and "Equipment".

Here's the XML:

<Parent Name="Roger">
   <Children>
     <Child Name="Bob"/>
     <Child Name="Tom"/>
  </Children>
  <EquipmentList>
     <Item Name="Canoe"/>
     <Item Name="Tent"/>
   </EquipmentList>
</Parent>

Here's the XAML data templates to render the tree nodes:

<Window.Resources>
    <HierarchicalDataTemplate DataType="Parent" ItemsSource="{Binding XPath=Children}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text=": "/>
            <TextBlock Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="Children" ItemsSource="{Binding XPath=Child}">
        <TextBox Width="Auto" Text="Rug Rats" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="Child">
        <TextBox Width="Auto" Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="EquipmentList" ItemsSource="{Binding XPath=Item}">
        <TextBox Width="Auto" Text="Gear" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="Item">
        <TextBox Width="Auto" Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
    </HierarchicalDataTemplate>

</Window.Resources>

In the interest of completeness, here is the code behind that fills the tree:

_xmlDoc = new XmlDocument();
_xmlDoc.Load(@"..\..\SampleXMLFile.xml");

treeViewToolDescription.ItemsSource = _xmlDoc;

I've been Googling combinations of "XML", "TreeView", "HierarchicalDataTemplate" and "heterogeneous" for a couple of days so I've seen (yet obviously not understood) quite a few articles that looked promising but never seemed relevant enough.

SOLUTION

The solution was to use an asterisk for the ItemsSource to get all the children regardless of type i.e. ItemsSource="{Binding XPath=*}"

Before (ItemsSource set explicitly to type "Children"):

    <HierarchicalDataTemplate DataType="Parent" ItemsSource="{Binding XPath=Children}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Parent: "/>
            <TextBlock Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </HierarchicalDataTemplate>

After (ItemsSource set to "*" instead of specifying a type):

    <HierarchicalDataTemplate DataType="Parent" ItemsSource="{Binding XPath=*}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Parent: "/>
            <TextBlock Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </HierarchicalDataTemplate>
1

1 Answers

2
votes

The short answer is you can't as it stands. You'll need to create one property which collates all children of a given node as one property.

So in this case you need a SubNodes property like the following

Parent.SubNodes => a list {Rug Rats, Gear}
Children.SubNodes for Rug Rats=> a list {Bob, Tom} 
Equipment.SubNodes for Gear => a list {Canoe, Tent} Items

and you can use DataTemplates for each type to render how each leaf node looks. A similar question WPF TreeView HierarchicalDataTemplate - binding to object with multiple child collections