简体   繁体   中英

Get parent TreeViewItem of a selected node in WPF

I want the parent of a node that is selected as TreeViewItem

I have a Person class with 2 fields. Name(String) and Children(List of string)

This is my xaml code

<Grid x:Name="gridView" Margin="10">
    <TreeView Name="treeView1" TreeViewItem.Selected="TreeViewItem_OnItemSelected" ItemsSource="{Binding}">
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Source=Check, Mode=TwoWay}" />
            </Style>
        </TreeView.ItemContainerStyle>
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type loc:Person}" ItemsSource="{Binding Children}" >
                <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
        </TreeView.Resources>
    </TreeView>
</Grid>

this is my code behind. I set the item source to a list of Person objects.

void set()
{
    if (treeView1.Items.IndexOf(treeView1.SelectedItem) != -1)
    {
        //is a parent 
        //returns -1 for children
        Person selected = (Person)treeView1.SelectedItem;
        int index = search(selected);
        TreeViewItem parent = treeView1.Tag as TreeViewItem;
        setSelected(parent,index);
    }
    else
    {
        //is a child
        TreeViewItem child = treeView1.Tag as TreeViewItem; //returns the selected node
        TreeViewItem parent = child.Parent as TreeViewItem; //returns null
    }
}
private void TreeViewItem_OnItemSelected(object sender, RoutedEventArgs e)
{
    treeView1.Tag = e.OriginalSource;
    int ind = 0;
    foreach (var _item in treeView1.Items)
    {
        if (_item == treeView1.SelectedItem)
        {
            selectedIndex = ind;
            break;
        }
        ind++;
    }
}

In the else part, The child.Parent always returns null. I tried other methods but none of them return a TreeViewItem instead they return DependencyObject or ItemsControl .

I also tried ContainerFromItem method but it only works for direct children(parent) and not the children of the parent.

Please help

You could use the VisualTreeHelper.GetParent() method: https://msdn.microsoft.com/de-de/library/system.windows.media.visualtreehelper.getparent(v=vs.110).aspx

Example Code:

private TreeViewItem FindParentTreeViewItem(object child)
{
    try
    {
        var parent = VisualTreeHelper.GetParent(child as DependencyObject);
        while ((parent as TreeViewItem) == null)
        {
            parent = VisualTreeHelper.GetParent(parent);
        }
        return parent as TreeViewItem;
    }
    catch (Exception e)
    {
        //could not find a parent of type TreeViewItem
        return null;
    }
}

The while loop is needed, as the visual parent of a tree view item isn't its parent tree view item as can be seen in this WPF Tree Visualizer:

WPF Tree Visualizer showing tree view

ItemsSource is typically a collection of DependencyObject s which you can bind to. It doesn't reflect any information about UI. What you are looking for is actually the ItemContainer of each Item which is a part of WPF UI.

In most cases you can access a UIElement from another without any problem. But in my experience as the UI gets complicated by Styles, Templates and hierarchical items, some UIElements will be hard to find.

I suggest the following way:

Implement a Parent property in your ViewModel (Person Class) with type of Person and initialize it in the constructor of Person, Then you can get both the parent Person and the parent TreeViewItem like this:

var parentPerson = (treeView1.SelectedItem as Person).Parent;
var parentNode = treeView1.ItemContainerGenerator.ContainerFromItem(parentPerson);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM