Saturday, January 7, 2012

WPF, XAML: TreeView HierarchicalDataTemplate databinding to unknown XML/DataSource

Problem description
  • I wish to bind my TreeView to a datasource.
  • The TreeView should build its child nodes dynamically (unknows childs in datasource).
  • Each node should display its data or (if no data) its element name.

Solution
You need to use and understand these parts:
  1. HierarchicalDataTemplate
    1. HierarchicalDataTemplate.Triggers
  2. Binding XPath

Usage Example
Just copy paste and start playing / reading each part's help.

XAML
Code Snippet
  1. <Window x:Class="TreeViewDataBinding.Window1"
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.     Title="Window1" Height="300" Width="300">
  5.     <Window.Resources>
  6.         <HierarchicalDataTemplate x:Key="NodeTemplate" >
  7.  
  8.             <TextBlock x:Name="tbName" Text="?" />
  9.  
  10.             <HierarchicalDataTemplate.ItemsSource>
  11.                 <Binding XPath="child::node()" />
  12.             </HierarchicalDataTemplate.ItemsSource>
  13.  
  14.             <HierarchicalDataTemplate.Triggers>
  15.                 <DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
  16.                     <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
  17.                 </DataTrigger>
  18.                 <DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
  19.                     <Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
  20.                 </DataTrigger>
  21.             </HierarchicalDataTemplate.Triggers>
  22.         </HierarchicalDataTemplate>
  23.  
  24.         <XmlDataProvider x:Key="xmlDataProvider"/>
  25.     </Window.Resources>
  26.     
  27.     <StackPanel>
  28.         <Button Click="Button_Click">Reload</Button>
  29.         
  30.         <TreeView
  31.             ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=*}"
  32.             ItemTemplate="{StaticResource NodeTemplate}" />
  33.     </StackPanel>
  34. </Window>

Code behind
Code Snippet
  1. using System.Windows;
  2. using System.Windows.Data;
  3. using System;
  4.  
  5. namespace TreeViewDataBinding
  6. {
  7.     public partial class Window1 : Window
  8.     {
  9.         public Window1()
  10.         {
  11.             InitializeComponent();
  12.         }
  13.  
  14.         private void Button_Click(object sender, RoutedEventArgs e)
  15.         {
  16.             var provider = (XmlDataProvider)this.Resources["xmlDataProvider"];
  17.             provider.Source = new Uri(@"Data\standard.xml", UriKind.Relative);
  18.         }
  19.     }
  20. }

Additional files



Performance
I was able to load 100MB of xml data in around ~6 seconds first time, ~4 seconds from the second time.

Testbench station
  • i7 (8 cores) @ 2.80GHz
  • 4.00GB RAM
  • 64-Bit OS, Win7 Pro.
CPU & memory usage
The CPU was at idle when i started, the RAM was at the base line.

Results

Resources

Hope it helps.

1 comment: