0

I need to show constants, which are based on other constants, in a TreeView but can't get it working. I already searched for an answer and tried to implement something similar to the tutorials I've found so far.

My aim is to show a TreeView (with dummy data for now) like this:

c1 (Parent)
     c3 (Child)
c2 (Parent)
     c4 (Child)
     c5 (Child)

My code looks like this (it's without the data I'm going to process later)

MainViewModel

{
  internal class MVM : INotifyPropertyChanged
  {
    public static ObservableCollection<Const> constants = new ObservableCollection<Const>();

    public event PropertyChangedEventHandler PropertyChanged;

    public MVM()
    {
      Const c1 = new Const("ABL", null);
      Const c2 = new Const("ASL", null);
      Const c3 = new Const("BBL", c1);
      Const c4 = new Const("BSL", c2);
      Const c5 = new Const("CBL", c2);


      constants.Add(c1);
      constants.Add(c2);

      c1.setChildren(new List<Const> { c3 });
      c2.setChildren(new List<Const> { c4, c5 });

      OnPropertyChange(nameof(constants));
    }

    protected void OnPropertyChange(string propertyName)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}

MainWindow.xaml header

<Window x:Class="ConstSearch.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ConstSearch" 
        xmlns:vm="clr-namespace:ConstSearch"
        mc:Ignorable="d"
        Title="ConstSearch" Height="450" Width="450" MinHeight="450" MinWidth="450">
  <Window.DataContext>
    <vm:MVM/>
  </Window.DataContext>

MainWindow.xaml TreeView

<TreeView x:Name="constOutput"  Margin="25,76,25,0" Height="130" HorizontalAlignment="Stretch" VerticalAlignment="Top" ItemsSource="{Binding constants}"><!--Style="{StaticResource lightGrayTV}"-->
      <TreeView.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:Const}" ItemsSource="{Binding Children}">
          <TextBlock Text="{Binding Path=Name}"/>
          <HierarchicalDataTemplate.ItemTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:Const}" ItemsSource="{Binding Children}">
              <TextBlock Text="{Binding Path=Name}"/>
            </HierarchicalDataTemplate>
          </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
      </TreeView.ItemTemplate>
    </TreeView>

Const.cs Model

namespace ConstSearch
{
  class Const
  {
    public string Name { get; set; }
    public Const Parent { get; set; }
    public List<Const> Children { get; set; }

    public Const(string name, Const con)
    {
      Name = name;
      Parent = con;
    }

    public void setChildren(List<Const> children)
    {
      Children = children;
    }

    public override string ToString()
    {
      return $"Name: {Name}";
    }
  }
}

Thank you for your help in advance!

Szwajcer
  • 11
  • 1
  • 3
  • 1
    `ItemsSource="{Binding constants}"` requires that `constants` is a public property, not a field. It should also not be static. Change the declaration to `public ObservableCollection constants { get; } = new ObservableCollection();`. Also note that properties are typically named using Pascal Casing, so it should be `Constants`. – Clemens Apr 05 '22 at 13:43
  • Instead of writing `if (PropertyChanged != null) { PropertyChanged(...); }` better write `PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));`. In your view model it is however redundant to call it at all, since the property `constants` is only set once in the constructor. There is no need for a change notification. – Clemens Apr 05 '22 at 13:48
  • Could you please post this, as an answer? With the proposition, you made, the TreeView works and I would like to mark is as the resolution. Thanks – Szwajcer Apr 05 '22 at 13:54
  • Your question is already marked as a duplicate. – Clemens Apr 05 '22 at 13:55
  • Ah, ok. I'm new to stackoverflow so it's good to know, how things work. Thank you very much. – Szwajcer Apr 05 '22 at 13:56

1 Answers1

-1

Everything seems fine from WPF and binding at first glance but the data.. which are fake if I get it...

      Const **c1** = new Const("ABL", null);
      Const c2 = new Const("ASL", null);
      Const *c3* = new Const("BBL", **c1**);
...
      **c1**.setChildren(new List<Const> { *c3* });

this is not tree as it has cycles, was this your intention? AFAK Hierarchical structures are about trees not graph, this can unfold for eternity or at least what meaning does it really have.

give a try without cycles in your test data

user2147873
  • 107
  • 5
  • The c3, c4 and c5 are children. The 2nd parameter of the constructor is a reference to the parent. My aim is something like this: c1 -> c3; c2 -> c4, c5 I should have put this into my question – Szwajcer Apr 05 '22 at 13:45
  • oh sorry... indeed was miss reading it mmm. as a proposal, very often we face binding issues for a reason or another, maybe you should check if you have any reported in your Output window of Visual Studio something like **Warning... BindingExpression... ** https://developercommunity.visualstudio.com/t/wpf-data-binding-errors-not-showing-in-error-windo/1076936. An old trick is also to provide a custom Converter in your bindings so you can catch what your control is bound to. https://wpf-tutorial.com/data-binding/debugging/ – user2147873 Apr 05 '22 at 13:59