Maclay
Maclay

Reputation: 15

How do I make a TreeView with different parent and child nodes?

I'm developing an application on Win UI and I need to make a TreeView with different parent and child nodes. The parent nodes are objects of the "Silos" class.

public class Silos : BindableBase
{
  private ObservableCollection<Wire> wiresObservable;

  public ObservableCollection<Wire> WiresObservable
  {
      get => wiresObservable; set=>SetProperty(ref this.wiresObservable, value);
  }
}

Each "Silos" object has child "Wire" objects.

public class Wire : BindableBase
{
    private int id; // уникальный идентификатор подвески
    private int number;
}

I am able to output a list of Silos, but it does not output Wire objects. How do I do this?

The code that outputs the Silos list.

<TreeView x:Name="TreeSilos" SelectionMode="Multiple"  ItemsSource="{x:Bind ViewModel.Siloses}">
    <TreeView.ItemTemplate>
        <DataTemplate x:DataType="local:Silos">
            <TreeViewItem  ItemsSource="{x:Bind Wires, Mode=OneWay}" Content="{x:Bind Name}" >
            </TreeViewItem>
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

Result

I looked at the examples on the Microsoft website. https://learn.microsoft.com/ru-ru/windows/apps/design/controls/tree-view

Upvotes: 1

Views: 85

Answers (1)

Andrew KeepCoding
Andrew KeepCoding

Reputation: 13666

You can create a custom DataTemplateSelector and select a DataTemplate for each type.

Let me show you an example for a Parent type and a Child type:

Parent.cs

public partial class Parent(string name) : ObservableObject
{
    [ObservableProperty]
    private string _name = name;

    [ObservableProperty]
    private ObservableCollection<Child> _children = [];
}

Child.cs

public partial class Child(string name) : ObservableObject
{
    [ObservableProperty]
    private string _name = name;
}

TreeViewItemTemplateSelector.cs

public class TreeViewItemTemplateSelector : DataTemplateSelector
{
    public DataTemplate ParentItemTemplate { get; set; } = new();

    public DataTemplate ChildItemTemplate { get; set; } = new();

    protected override DataTemplate SelectTemplateCore(object item)
    {
        return item switch
        {
            Parent => ParentItemTemplate,
            Child => ChildItemTemplate,
            _ => base.SelectTemplateCore(item)
        };
    }
}

ShellViewModel.cs

public partial class ShellViewModel : ObservableObject
{

    [ObservableProperty]
    private ObservableCollection<Parent> _parents = [];

    public ShellViewModel()
    {
        var parent1 = new Parent("Parent 1");
        parent1.Children.Add(new Child("Child 1"));

        var parent2 = new Parent("Parent 2");
        parent2.Children.Add(new Child("Child 1"));
        parent2.Children.Add(new Child("Child 2"));

        var parent3 = new Parent("Parent 3");
        parent3.Children.Add(new Child("Child 1"));
        parent3.Children.Add(new Child("Child 2"));
        parent3.Children.Add(new Child("Child 3"));

        Parents.Add(parent1);
        Parents.Add(parent2);
        Parents.Add(parent3);
    }
}

Shell.xaml.cs

public sealed partial class Shell : Page
{
    public Shell()
    {
        InitializeComponent();
    }

    public ShellViewModel ViewModel { get; } = new();
}

Shell.xaml

<Page
    x:Class="WinUIDemoApp.Shell"
    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:local="using:WinUIDemoApp"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Page.Resources>
        <local:TreeViewItemTemplateSelector x:Name="TreeViewItemTemplateSelector">
            <local:TreeViewItemTemplateSelector.ParentItemTemplate>
                <DataTemplate x:DataType="local:Parent">
                    <TreeViewItem
                        Content="{x:Bind Name}"
                        ItemsSource="{x:Bind Children}" />
                </DataTemplate>
            </local:TreeViewItemTemplateSelector.ParentItemTemplate>
            <local:TreeViewItemTemplateSelector.ChildItemTemplate>
                <DataTemplate x:DataType="local:Child">
                    <TreeViewItem Content="{x:Bind Name}" />
                </DataTemplate>
            </local:TreeViewItemTemplateSelector.ChildItemTemplate>
        </local:TreeViewItemTemplateSelector>
    </Page.Resources>

    <TreeView
        ItemTemplateSelector="{StaticResource TreeViewItemTemplateSelector}"
        ItemsSource="{x:Bind ViewModel.Parents, Mode=OneWay}" />

</Page>

BTW, ObservableObject and ObservableProperty come from the CommunityToolkit.Mvvm NuGet package.

Upvotes: 3

Related Questions