Edward Tanguay
Edward Tanguay

Reputation: 193372

How can I get child tree nodes to appear in a WPF TreeView when binding to an ObservableCollection?

What do I have to change in the following code to make the "A Child Section" node appear as a child of the First Section and Second Section:

The following code gives me a XamlParseException.

XAML:

<Window x:Class="TestTr32322.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestTr32322"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <HierarchicalDataTemplate x:Key="sectionTemplate" 
            ItemsSource="{Binding ChildSections}"
            DataType="{x:Type local:Section}">
            <TextBlock Text="{Binding Title}" />
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <TreeView ItemsSource="{Binding Sections}" 
                  ItemTemplate="{StaticResource sectionTemplate}">
        </TreeView>
    </Grid>
</Window>

Code Behind:

using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace TestTr32322
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        #region ViewModelProperty: Sections
        private ObservableCollection<Section> _sections = new ObservableCollection<Section>();
        public ObservableCollection<Section> Sections
        {
            get
            {
                return _sections;
            }

            set
            {
                _sections = value;
                OnPropertyChanged("Sections");
            }
        }
        #endregion

        public Window1()
        {
            InitializeComponent();
            DataContext = this;

            Sections = Section.GetSections();
        }

        #region INotifiedProperty Block
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

    }

    public class Section
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public ObservableCollection<Section> ChildSections { get; set; }

        public static ObservableCollection<Section> GetSections()
        {
            ObservableCollection<Section> sections = new ObservableCollection<Section>();

            {
                Section section = new Section();
                section.Title = "First Section";
                section.ChildSections.Add(new Section
                {
                    Title = "A Child Section",
                    Description = "this is the description",
                    ChildSections = new ObservableCollection<Section>()
                });
                sections.Add(section);
            }

            {
                Section section = new Section();
                section.Title = "Second Section";
                section.ChildSections.Add(new Section
                {
                    Title = "A Child  Section",
                    Description = "this is the description",
                    ChildSections = new ObservableCollection<Section>()
                });
                sections.Add(section);
            }

            return sections;
        }
    }

}

Upvotes: 0

Views: 832

Answers (2)

olli-MSFT
olli-MSFT

Reputation: 2546

Have a look at this question and the accepted answer. It should point you into the right direction, too.

The basic idea is to define HierarchicalDataTemplates with an ItemsSource property and make them match by type.

In your case:

<HierarchicalDataTemplate DataType="{x:Type local:Section}" 
                          ItemsSource="{Binding ChildSection}">
    <TextBlock Text="{Binding Path=Title}" />
</HierarchicalDataTemplate>

Edit: In your code you should create a new collection before adding a value to it:

// The new was missing and resulted in the end in your XAML Parse Exception
section.ChildSections = new ObservableCollection<Section>();
section.ChildSections.Add( /*... */);

Upvotes: 1

Anvaka
Anvaka

Reputation: 15823

It looks like you need HierarchicalDataTemplate. They have an example in the article...

Upvotes: 1

Related Questions