locked
bind Xml to treeview using a HierarchicalDataTemplate RRS feed

  • Question

  • Hello,

     

    I've some problem to bind a XDocument to my treeview using WPF. Here is the xml structure I want to bind :

     

    Code Snippet
    <Root>
     <Category>
      <Name>category 1</Name>
      <Item>
       <Name>item 1</Name>
      </Item>
      <Item>
       <Name>item 2</Name>
      </Item>
      <Category>
       <Name>category 1.1</Name>
       <Item>
        <Name>item 1</Name>
       </Item>
      </Category>  
     </Category>
     <Category>
      <Name>category 2</Name>
      <Item>
       <Name>item 1</Name>
      </Item>
     </Category>
    </Root>

     

     

    In the treeview, I would like to display the names of categories and the names of the Items with different templates.

     

    I wrote this XAML code :

     

    Code Snippet
    <Window.Resources>
     <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding Path=Elements}">
      <TextBlock Background="Red" Text="{Binding Path=Element[Name].Value}" />
     </HierarchicalDataTemplate>
     <DataTemplate DataType="Item">
      <TextBlock Background="Green" Text="{Binding Path=Element[Name].Value}" />
     </DataTemplate>
    </Window.Resources>
    <Grid>
     <TreeView Name="treeView1" ItemsSource="{Binding Path=Root.Elements[Category]}" />
    </Grid>

     

     

    The problem is on the ItemsSource property of the HierarchicalDataTemplate. I cannot point only to the elements which names are either "Category" or "Item". I can just write either "Elements" or "Elements[Category]" or "Elements[Item]" but not something like this : "Elements[Item or Category]". As a result all the sub-elements of a Category will be displayed in the treeview whereas I just want those who name are "Item" or "Category".

    Do you have any solution to get around this problem ?

     

    regards,

     

    mathmax   

    Sunday, January 27, 2008 10:00 PM

Answers

  • You can use a value converter to select sub nodes for Category element. Here is a sample code which shows how to do this.

     

    Code Snippet

    <Window

       x:Class="ForumProjects.MainWindow"

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       xmlns:local="clr-namespace:ForumProjects"

       Title="MainWindow" Height="700" Width="800">

        <Window.Resources>

            <local:XElementConverter x:Key="Converter"/>

            <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding Converter={StaticResource Converter}}">

                <TextBlock Text="{Binding Path=Element[Name].Value}" />

            </HierarchicalDataTemplate>

            <DataTemplate DataType="Item">

                <TextBlock Text="{Binding Path=Element[Name].Value}" />

            </DataTemplate>

        </Window.Resources>

        <TreeView ItemsSource="{Binding Path=Root.Elements[Category]}"/>

    </Window>

     

    namespace ForumProjects

    {

        public partial class MainWindow : Window

        {

            public MainWindow()

            {

                InitializeComponent();

     

                XDocument doc = XDocument.Load("Test.xml");

                this.DataContext = doc;

            }

        }

     

        public class XElementConverter : IValueConverter

        {

            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

            {

                XElement element = value as XElement;

                if (element == null) return null;

                return element.XPathSelectElements("Category|Item");

            }

     

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

            {

                throw new NotImplementedException();

            }

        }

    }

     

     

    Best Regards,

    Wei Zhou

    Tuesday, January 29, 2008 9:40 AM
  • I don't know it's why. I think that I can only say it may be implemented for XDocument at future.

     

    Best Regards,

    Wei Zhou

    Thursday, January 31, 2008 8:22 AM

All replies

  • You can use XPath query to do this. Here is the sample which shows how to do this.

     

    Code Snippet

    <Window

       x:Class="ForumProjects.MainWindow"

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       Title="MainWindow" Height="700" Width="800">

        <Window.Resources>

            <XmlDataProvider x:Key="DataSource">

                <x:XData>

                    <Root xmlns="">

                        <Category>

                            <Name>category 1</Name>

                            <Item>

                                <Name>item 1</Name>

                            </Item>

                            <Item>

                                <Name>item 2</Name>

                            </Item>

                            <Category>

                                <Name>category 1.1</Name>

                                <Item>

                                    <Name>item 1</Name>

                                </Item>

                            </Category>

                        </Category>

                        <Category>

                            <Name>category 2</Name>

                            <Item>

                                <Name>item 1</Name>

                            </Item>

                        </Category>

                    </Root>

                </x:XData>

            </XmlDataProvider>

     

            <local:DataSourceDataTemplateSelector x:Key="DataSourceDataTemplateSelector"/>

     

            <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding XPath=Category|Item}">

                <TextBlock Text="{Binding XPath=Name}" />

            </HierarchicalDataTemplate>

     

            <DataTemplate DataType="Item">

                <TextBlock Text="{Binding XPath=Name}" />

            </DataTemplate>

        </Window.Resources>

        <TreeView ItemsSource="{Binding Source={StaticResource DataSource}, XPath=Root/Category}"/>

    </Window>

     

     

    Best Regards,

    Wei Zhou

    Tuesday, January 29, 2008 3:09 AM
  •  

    Yes but I cannot use XPath if the binding source is an XDocument.

     

    I can put the content of the XDocument to a XmlDocument and then bind the XmlDocument instance but the user interface will no more be notiefied of the changes on the original XDocument instance.

    I really don't understand why Microsoft doesn't have implemented XPath with XDocument.

    Tuesday, January 29, 2008 4:11 AM
  • You can use a value converter to select sub nodes for Category element. Here is a sample code which shows how to do this.

     

    Code Snippet

    <Window

       x:Class="ForumProjects.MainWindow"

       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       xmlns:local="clr-namespace:ForumProjects"

       Title="MainWindow" Height="700" Width="800">

        <Window.Resources>

            <local:XElementConverter x:Key="Converter"/>

            <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding Converter={StaticResource Converter}}">

                <TextBlock Text="{Binding Path=Element[Name].Value}" />

            </HierarchicalDataTemplate>

            <DataTemplate DataType="Item">

                <TextBlock Text="{Binding Path=Element[Name].Value}" />

            </DataTemplate>

        </Window.Resources>

        <TreeView ItemsSource="{Binding Path=Root.Elements[Category]}"/>

    </Window>

     

    namespace ForumProjects

    {

        public partial class MainWindow : Window

        {

            public MainWindow()

            {

                InitializeComponent();

     

                XDocument doc = XDocument.Load("Test.xml");

                this.DataContext = doc;

            }

        }

     

        public class XElementConverter : IValueConverter

        {

            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

            {

                XElement element = value as XElement;

                if (element == null) return null;

                return element.XPathSelectElements("Category|Item");

            }

     

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

            {

                throw new NotImplementedException();

            }

        }

    }

     

     

    Best Regards,

    Wei Zhou

    Tuesday, January 29, 2008 9:40 AM
  • Ok, thank you very much for this solution.  But do you understand why XPath is not implemented for XDocument ?

    Wednesday, January 30, 2008 2:31 PM
  • I don't know it's why. I think that I can only say it may be implemented for XDocument at future.

     

    Best Regards,

    Wei Zhou

    Thursday, January 31, 2008 8:22 AM
  • Hi, its possible to do it more flexible, so there is no limit of how many sub-items have the XML file or query?

     

    Any ideas would be appreciated.

     

    Rodrigo Esquivel

    Tuesday, February 12, 2008 12:23 AM