Search code examples
wpfpowershellwinformsdata-binding

Powershell + WPF - TreeListView hierarchical checkboxes


I have a problem. I need to create dynamicly created TreeListView with checkboxes. I already have that, but what i need to do, is automaticly select all children nodes, when parent is selected. How can i do that? This is my code i created already

[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="My TreeView" Height="300" Width="300">
    <Grid>
        <TreeView Name="MyTreeView" Margin="10">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" VerticalAlignment="Center"/>
                        <TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
</Window>
"@

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$window=[Windows.Markup.XamlReader]::Load( $reader )

# Define the data structure for the treeview
class Node {
    [string]$Name
    [System.Collections.ObjectModel.ObservableCollection[Node]]$Children
    [bool]$IsChecked
}

# Populate treeview with sample data
$root = New-Object Node
$root.Name = "Root"
$root.Children = New-Object System.Collections.ObjectModel.ObservableCollection[Node]

$child1 = New-Object Node
$child1.Name = "Child 1"
$child1.Children = New-Object System.Collections.ObjectModel.ObservableCollection[Node]

$child2 = New-Object Node
$child2.Name = "Child 2"
$child2.Children = New-Object System.Collections.ObjectModel.ObservableCollection[Node]

$root.Children.Add($child1)
$root.Children.Add($child2)

$treeview = $window.FindName("MyTreeView")

$treeview.ItemsSource = @($root)

$window.ShowDialog() | Out-Null


Solution

  • How can i do that?

    Add some logic to the setter of the IsChecked property that sets the corresponding property of all items in Children collection, and implement the INotifyPropertyChanged interface to notify the view:

    Add-Type -TypeDefinition @"
        using System.ComponentModel;
        using System.Collections.ObjectModel;
    
        public class Node : INotifyPropertyChanged  {
            public string Name { get; set; }
            public ObservableCollection<Node> Children { get; set; }
    
            private bool isChecked;
            public bool IsChecked {
                get { return isChecked; }
                set {
                    isChecked = value;
                    OnPropertyChanged("IsChecked");
                    foreach (var node in Children)
                      node.IsChecked = true;
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            protected virtual void OnPropertyChanged(string propertyName) {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    "@