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