1

I'm beginner for C# and WPF.

When I tried to figure out how to bind data to treeview, I find a example in Microsoft learn, the link is https://learn.microsoft.com/en-us/dotnet/api/system.windows.hierarchicaldatatemplate?view=windowsdesktop-7.0.

It is a pity in this example only XAML code is provided, for objects there is only description but not code. Please see the picture below for the objects description.

enter image description here

I code the objects with my limited C# knowledge, as below.

Objects: ListLeagueList

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

namespace Treeview01
{
    public class ListLeagueList : ObservableCollection<League>
    {
        public ListLeagueList() : base()
        {
            Add(new League("League A"));
            Add(new League("League B"));
            Add(new League("League C"));
        }
    }
}

Objects: League

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

namespace Treeview01
{
    public class League
    {
        public string Name { get; set; }

        List<Division> Divisions  = new List<Division>();
        public League(string name) //: base()
        {
            Name = name;
            Divisions.Add(new Division("DivisionA"));
            Divisions.Add(new Division("DivisionB"));
            Divisions.Add(new Division("DivisionC"));
        }
        private League()
        {
        }
    }
}

Objects: Division

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

namespace Treeview01
{
    public class Division
    {
        public string Name { get; set; }

        List<Team> Teams = new List<Team>();
        public Division(string name) //: base()
        {
            Name = name;
            Teams.Add(new Team("Bear"));
            Teams.Add(new Team("Rocket"));
        }
        private Division()
        {
        }

    }
}

Objects: Team

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

namespace Treeview01
{
    public class Team
    {
        public string Name { get; set; }

        public Team(string name)
        {
            Name = name;
        }

        private Team()
        {
        }
    }
}

XAML:

<Window x:Class="Treeview01.Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="HierarchicalDataTemplate Sample"
      xmlns:src="clr-namespace:Treeview01">
        <DockPanel>
            <DockPanel.Resources>
                <src:ListLeagueList x:Key="MyList"/>
    
                <HierarchicalDataTemplate DataType    = "{x:Type src:League}"
                                    ItemsSource = "{Binding Path=Divisions}">
                    <TextBlock Text="{Binding Path=Name}"/>
                </HierarchicalDataTemplate>
    
                <HierarchicalDataTemplate DataType    = "{x:Type src:Division}"
                                    ItemsSource = "{Binding Path=Teams}">
                    <TextBlock Text="{Binding Path=Name}"/>
                </HierarchicalDataTemplate>
    
                <DataTemplate DataType="{x:Type src:Team}">
                    <TextBlock Text="{Binding Path=Name}"/>
                </DataTemplate>
                
            </DockPanel.Resources>
    
            <Menu Name="menu1" DockPanel.Dock="Top" Margin="10,10,10,10">
                <MenuItem Header="My Soccer Leagues"
                      ItemsSource="{Binding Source={StaticResource MyList}}" />
            </Menu>
    
            <TreeView>
                <TreeViewItem ItemsSource="{Binding Source={StaticResource MyList}}" Header="My Soccer Leagues" />
            </TreeView>
    
        </DockPanel>
    </Window>

XAML.CS:

using System.Windows;

namespace Treeview01
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

    }
}

With the code above, only the first level data is represented, as the picture below.

enter image description here

Please check and correct my code.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
Colin
  • 23
  • 4

1 Answers1

2

Divisions and Teams can not be recognized in Xaml, because they are not public properties.

Devisions

public List<Division> Divisions { set; get; } = new List<Division>();

Teams

public List<Team> Teams { set; get; } = new List<Team>();
Muhammad Sulaiman
  • 2,399
  • 4
  • 14
  • 28
  • Many thanks! It's do work properly when I changed the code as your sample. Furthermore, can I ask why here '{set; get;}' must be used? As far as I know it will become a property from a field. But why it must be a property in this case? – Colin Sep 25 '22 at 23:34
  • Furthermore, in case I want to add a new node to the treeview (add a new league e.g.), via click a button. Could you show me the code? Thank you in advance! – Colin Sep 26 '22 at 08:31
  • 1
    You can add do it like this `(DockPanel.Resources["MyList"] as ListLeagueList)?.Add(new League("Z"));`.. for the first question you can check this [post](https://stackoverflow.com/q/6220585/4108016).. it's just required by binding engine.. – Muhammad Sulaiman Sep 26 '22 at 09:32
  • Forget to mention to give `DockPanel` a name in xaml `x:Name="DockPanel"` – Muhammad Sulaiman Sep 26 '22 at 09:46
  • Thanks again for your answer! (DockPanel.Resources["MyList"] as ListLeagueList)?.Add(new League("Z")); this is the instance name I don't know how to express. – Colin Sep 27 '22 at 00:31
  • ...when I try to add a new object "Division" in collection "Divisions", I've trid the code `((DockPanel01.Resources["MyList"] as League).Divisions).Add(new Division("Division D"));`, but it doesn't work. Could you check and correct my code again? Thank you very much! – Colin Sep 27 '22 at 00:57
  • Make Divisions an observableCollection instead of List – Muhammad Sulaiman Sep 27 '22 at 02:59
  • Yes, I'd tried to use observableCollection instead of List, but still didn't work. The code can be compiled, but there will be a error happen when I trigger the "add divison" command. The message is: _System.NullReferenceException: 'Object reference not set to an instance of an object.'(... as Treeview01.League) returned null._ – Colin Sep 27 '22 at 03:49
  • Your code is wrong, because `(DockPanel01.Resources["MyList"] as League)` will return a list of Leagues.. To add a division to the first league, you can do `(DockPanel01.Resources["MyList"] as ListLeagueList)?[0]?.Divisions.Add(new Division("Division D"));` – Muhammad Sulaiman Sep 27 '22 at 04:14
  • ...It seem `[]` is not supported, for the reason of "Cann't apply indexing with[] to an expression of type 'league'". – Colin Sep 27 '22 at 05:07
  • No, [] is applied over ListLeagueList, which is a collection, make sure to copy the code from my comment.. I've tried it and it works, [screenshot](https://i.stack.imgur.com/ikCfp.png) – Muhammad Sulaiman Sep 27 '22 at 05:14
  • Yes, my mistake. Now it is work properly! I guess that's all my questions for this moment. Thank you very much for your time and patient answer!! – Colin Sep 27 '22 at 05:58