0
votes

I am trying to bind a hierarchical structure to a TreeView using Data Binding, but nothing is displayed in the TreeView.

XAML code in the Control:

<UserControl x:Class="CQViewer.Views.HierarchyView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:h="clr-namespace:CQViewer.Hierarchy"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
  <Grid>
    <TabControl Margin="5, 0, 5, 5" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
      <TabItem Header="Repository">
        <TreeView Margin="5, 5, 5, 5" HorizontalAlignment="Stretch" ItemsSource="{Binding Path=Nodes}">
          <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type h:HierarchyNode}"
                                      ItemsSource="{Binding ChildNodes}">
              <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
      </TabItem>
      <TabItem Header="Libraries">
        <ListBox Margin="5, 5, 5, 5" HorizontalAlignment="Stretch" />
      </TabItem>
    </TabControl>
  </Grid>
</UserControl>

The class that I am using:

using System.Collections.Generic;

namespace CQViewer.Hierarchy
  {
  class HierarchyNode
    {
    #region Fields
    private IList<HierarchyNode> childNodes_;
    #endregion

    #region Construction/Deconstruction/Initialisation
    /// <summary>
    /// Constructor
    /// </summary>
    public HierarchyNode (string Name)
      {
      this.Name = Name;
      childNodes_ = new List<HierarchyNode> ();
      }
    #endregion

    #region Properties
    public string Name { get; set; }
    public IList<HierarchyNode> ChildNodes
      {
      get { return childNodes_; }
      set { childNodes_ = value; }
      }
    #endregion
    }
  }

What I want to do is populate the TreeView using the ChildNodes in the HierarchyNode objects using the HierarchicalDataTemplate, while displaying a TextBlock for the name of the current object. The root HierarchyNode is created in the constructor of the ViewModel. Data Binding in this UserControl works, since binding a List<> to the ListBox works fine.

What is wrong with what I am doing, and why it is not working?

EDIT: The ViewModel used for the View

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using CQViewer.Hierarchy;

namespace CQViewer.ViewModels
  {
  class HierarchyViewModel : ViewModelBase
    {
    #region Fields

    #endregion

    #region Construction/Deconstruction/Initialisation
    /// <summary>
    /// Constructor
    /// </summary>
    public HierarchyViewModel ()
      {
      Nodes = new HierarchyNode ("Test1");
      HierarchyNode Node2 = new HierarchyNode ("TestX");
      Node2.ChildNodes.Add (new HierarchyNode ("TestY"));

      Nodes.ChildNodes.Add (Node2);
      Nodes.ChildNodes.Add (new HierarchyNode ("Test3"));
      }
    #endregion

    #region Properties
    public HierarchyNode Nodes { get; set; }
    #endregion

    #region Public Access Interface
    /// <summary>
    /// Creates/Recreates the hierarchy
    /// </summary>
    public void InitializeHierarchy ()
      {
      // TODO Clear the tree view
      }

    /// <summary>
    /// Gets the folder currently selected in the tree view hierarchy
    /// </summary>
    public string GetCurrentlySelected ()
      {
      return "$/";
      }
    #endregion

    #region Private Functions

    #endregion
    }
  }
2
Could you show a view model that is used by HierarchyView control?Michał Komorowski
@MichałKomorowski Done. It is mostly test stuff anyway.MKII

2 Answers

1
votes

The problem is that ItemsSource property of TreeViewItem expects a collection where as HierarchyViewModel.Nodes property is of type HierarchyNode. I suggest to change it to ObservableCollection<HierarchyNode>. i.e.:

public ObservableCollection<HierarchyNode> Nodes { get; set; }

Your solution with ItemsSource="{Binding Nodes.ChildNodes}" works partially because a tree view will not display a root node (Test1 in your case).

0
votes

I have managed to get this to work by changing the TreeView code to the following:

    <TreeView Margin="5, 5, 5, 5" HorizontalAlignment="Stretch">
      <TreeViewItem Header="{Binding Nodes.Name}" ItemsSource="{Binding Nodes.ChildNodes}">
        <TreeViewItem.Resources>
          <HierarchicalDataTemplate DataType="{x:Type h:HierarchyNode}"
                                    ItemsSource="{Binding ChildNodes}">
            <TextBlock Text="{Binding Name}" />
          </HierarchicalDataTemplate>
        </TreeViewItem.Resources>
      </TreeViewItem>
    </TreeView>

But I am sure that there is a better way to handle this.