I am attempting to create a dynamically generated TreeView in a WPF project using MVVM. I have created a HierarchicalDataTemplate and a CheckableItem model that it will bind to. I have a CheckableItem type property on my ViewModel that I populate when the ViewModel is constructed. I then have the XAML use the template to create the TreeView, but nothing is displaying. I need the TreeView to contain Checkboxes and if I higher-level checkbox is checked, it should check all the lower-level ones. It should look something like this:
I am not sure what is wrong that is causing it not to display.
ChekableItem class:
public class CheckableItem
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public ObservableCollection<CheckableItem> Children { get; set; }
private Visibility _isChecked;
public Visibility IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
CheckChildren(value);
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void CheckChildren(Visibility parentIsChecked)
{
foreach (CheckableItem child in Children)
{
child.IsChecked = parentIsChecked;
}
}
ViewModel:
private CheckableItem miscellaneousImports;
public CheckableItem MiscellaneousImports
{
get { return miscellaneousImports; }
set
{
miscellaneousImports = value;
OnPropertyChanged("MiscellaneousImports");
}
}
private void LoadCheckableItems()
{
miscellaneousImports = new CheckableItem()
{
Name = "Miscellaneous Imports"
};
miscellaneousImports.Children = new ObservableCollection<CheckableItem>();
miscellaneousImports.Children.Add(new CheckableItem()
{
Name = "GPO Import"
});
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
View XAML:
<Window x:Class="CAVA_IAS.Views.CaImportView"
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:models="clr-namespace:CAVA_IAS.Models"
mc:Ignorable="d"
Title="CaImportView" SizeToContent="WidthAndHeight">
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:CheckableItem}" ItemsSource="{Binding
Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel>
<Label Content="Miscellaneous Imports" HorizontalAlignment="Center" />
<ScrollViewer>
<TreeView ItemsSource="{Binding MiscellaneousImports, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" FontSize="10" Height="450"/>
</ScrollViewer>
</StackPanel>
Your problem is that the ItemsSource of the TreeView needs to be a list of some sort. Now you are binding it to a single CheckableItem.
In your ViewModel, you should have something like this :
private ObservableCollection<CheckableItem> miscellaneousImports;
public ObservableCollection<CheckableItem> MiscellaneousImports
{
get { return miscellaneousImports; }
set
{
miscellaneousImports = value;
OnPropertyChanged("MiscellaneousImports");
}
}
Or Bind to the Children property of CheckableItem in the Xaml, like so :
<TreeView ItemsSource="{Binding MiscellaneousImports.Children, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="10" Height="450"/>