Home > Blockchain >  Binding different types of selected item in hierarchical treeview?
Binding different types of selected item in hierarchical treeview?

Time:12-09

I have a hierarchical list of objects whose children are objects of a different type. The classes for them are described as follows:

public class Production
{
    public string name { get; set; }
    public string id { get; set; }
    public List<Plant> plants { get; set; }
}

public class Plant
{
    public string name { get; set; }
    public string id { get; set; }
    public List<Scheme> schemes { get; set; }
}

public class Scheme
{
    public string name { get; set; }
    public string id { get; set; }
}

And the main class which contains a list of productions and methods for filling the main menu:

public class DocumentProviderMenu
{
    public List<Production> productions { get; set; }
    public DocumentProviderMenu()
    {
        ExecuteUpdateMenu();
    }
private void ExecuteUpdateMenu() {/*Uploding menu method}

Finally, the TreeView xaml:

<TreeView ItemsSource="{Binding Menu.productions}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type mod:Production}"
                                      ItemsSource="{Binding plants}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type mod:Plant}"
                                      ItemsSource="{Binding schemes}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type mod:Scheme}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding name}"/>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>

Where Menu is a property of ViewModel.So I declared the fields in ViewModel like:

public Production SelectedProduction
    {
        get => _SelectedProduction;
        set
        {
            _SelectedProduction = value;
            OnPropertyChanged(nameof(SelectedProduction));
        }
    }
private Production _SelectedProduction;

for 3 types - Production,Plant,Scheme.I can bind the selected item but only to one type (this question helped me enter image description here

XAML:

<Window x:Class="WpfApp1.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:WpfApp1" Width="640" Height="480"
        mc:Ignorable="d" d:DataContext="{d:DesignInstance local:Model}">
    <Window.DataContext>
        <local:Model />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding SelectedProduction, StringFormat='{}Selected item: {0}' }" />
        <TreeView ItemsSource="{Binding Productions}" SelectedItemChanged="TreeView_OnSelectedItemChanged" Grid.Row="1">
            <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:Production}"
                                          ItemsSource="{Binding Plants}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Plant}"
                                          ItemsSource="{Binding Schemes}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
                <HierarchicalDataTemplate DataType="{x:Type local:Scheme}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
    </Grid>
</Window>

Code:

using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;

namespace WpfApp1;

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        (DataContext as Model)!.SelectedProduction = e.NewValue as ITreeElement;
    }
}

internal class Model : INotifyPropertyChanged
{
    private ITreeElement? _selectedProduction;

    public Model()
    {
        Productions = new List<ITreeElement>
        {
            new Production
            {
                Name = "production",
                Plants = new List<Plant>
                {
                    new()
                    {
                        Name = "plant 1",
                        Schemes = new List<Scheme>
                        {
                            new()
                            {
                                Name = "scheme 1"
                            },
                            new()
                            {
                                Name = "scheme 2"
                            }
                        }
                    },
                    new()
                    {
                        Name = "plant 2",
                        Schemes = new List<Scheme>
                        {
                            new()
                            {
                                Name = "scheme 3"
                            },
                            new()
                            {
                                Name = "scheme 4"
                            }
                        }
                    }
                }
            }
        };
    }

    public List<ITreeElement> Productions { get; }

    public ITreeElement? SelectedProduction
    {
        get => _selectedProduction;
        set => SetField(ref _selectedProduction, value);
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

public interface ITreeElement
{
    string Name { get; set; }

    string Id { get; set; }
}

public class Production : ITreeElement
{
    public List<Plant> Plants { get; set; }

    public string Name { get; set; }

    public string Id { get; set; }
}

public class Plant : ITreeElement
{
    public List<Scheme> Schemes { get; set; }

    public string Name { get; set; }

    public string Id { get; set; }
}

public class Scheme : ITreeElement
{
    public string Name { get; set; }

    public string Id { get; set; }
}
  • Related