TreeView with CheckBoxes dynamically WPF. How to know the name of the elements selected

0 votes
asked Sep 11, 2017 by lk009

I have a code that displays the files and folders names in a TreeView and put a checkbox from each element. What I don't know how to do is how to know the elements in the TreeView that are selected with the checkboxes.

XAML:

<TreeView Name="treeView" Grid.Row="10" Grid.ColumnSpan="3">
        <TreeView.Resources>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="HeaderTemplate">
                    <Setter.Value>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <CheckBox Focusable="False" IsChecked="False" VerticalAlignment="Center"/>
                                <TextBlock Text="{Binding}" Margin="5,0" />
                            </StackPanel>
                        </DataTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </TreeView.Resources>
    </TreeView>

Program:

    DirectoryInfo di = new DirectoryInfo(folder);
    treeView.Items.Add(getTree(di));

    public TreeViewItem getTree(DirectoryInfo di)
    {
        TreeViewItem item = new TreeViewItem();
        item.Header = di.Name;
        item.FontWeight = FontWeights.Normal;
        foreach (DirectoryInfo s in di.GetDirectories())
        {
            item.Items.Add(getTree(s)); 
        }
        foreach (FileInfo fi in di.GetFiles())
        {
            item.Items.Add(fi.Name);
        }
        return item;
    }

1 Answer

0 votes
answered Sep 11, 2017 by mm8

Create your own TreeViewItem type:

public class Node
{
    public string Name { get; set; }
    public bool IsChecked { get; set; }
    public List<Node> Children { get; } = new List<Node>();
}

Add instance of this type to the TreeView:

public Node getTree(DirectoryInfo di)
{
    Node item = new Node();
    item.Name = di.Name;
    foreach (DirectoryInfo s in di.GetDirectories())
    {
        item.Children.Add(getTree(s));
    }
    foreach (FileInfo fi in di.GetFiles())
    {
        item.Children.Add(new Node { Name = fi.Name });
    }
    return item;
}

Bind to the properties of this type in the view:

<TreeView Name="treeView" Grid.Row="10" Grid.ColumnSpan="3">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:Node}" ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <CheckBox Focusable="False" IsChecked="{Binding IsChecked}" VerticalAlignment="Center"/>
                <TextBlock Text="{Binding Name}" Margin="5,0" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

You could then iterate through the items recursively and check the value of the IsChecked property:

private List<string> GetSelectedNames()
{
    List<string> selectedNames = new List<string>();
    foreach (var item in treeView.Items.OfType<Node>())
        GetSelected(item, ref selectedNames);
    return selectedNames;
}

public void GetSelected(Node node, ref List<string> s)
{
    if (node.IsChecked)
        s.Add(node.Name);

    foreach (Node child in node.Children)
        GetSelected(child, ref s);
}

If you want to take this a step further, you bind the ItemsSource property of the TreeView to an IEnumerable<Node> property of your view model and iterate through this one instead of the Items property of the TreeView control.

Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
...