views:

164

answers:

2

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;
        }
    }

}
+1  A: 

Hi Edward,

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

Anvaka
thanks, I added HierarchicalDataTemplate based on what I could get from this article http://bea.stollnitz.com/blog/?p=18 but it still gives me the same result (code changed above)
Edward Tanguay
I see. Convert ChildSection to ObservableCollection and bind HierarchicalDataTemplate.ItemsSource to it.. Will it help?
Anvaka
I made those changes to my code above but now it gives me a XamlParseException, as if ChildSections are null on some Sections, but they seem to be all initialized.
Edward Tanguay
Yah, it looks like you forgot to initialize Section.ChildSections collection before adding anything to it...
Anvaka
excellent, I just had to convert ChildSections into a full INotifyPropertyChanged property and it worked, thanks for you help!
Edward Tanguay
Glad I could help :)
Anvaka
+1  A: 

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( /*... */);
olli
I'll take a look, meanwhile I make your change and posted above but it's still giving me a XamlParseException saying "an object was not instantiated".
Edward Tanguay
I took a look a that example, I actually only need one type: Sections under Sections under Sections. Is it still necessary to define the type then, I thought the x:key was enough to connect the TreeView and the HierarchicalDataTemplate.
Edward Tanguay
x:Key should be enough
Anvaka
Yes, in this case x:Key is enough. If you have heterogeneous nodes in your tree, however, x:Key won't work.
olli