WPF MVVM:从列表视图中选择treeviewem

本文关键字:选择 treeviewem 视图 列表 MVVM WPF | 更新日期: 2023-09-27 18:08:59

我有一个基于MVVM软件架构的wpf应用程序。它由treeView和ListView组成。当单击一个treeView节点时,该节点的所有子节点都显示在列表视图中。我能够做到这一点。

但是当用户点击listView中的一个项目时,这个特定的项目(它是treeview中的一个节点)应该在treeview中被选中。我不知道该怎么做。基本上我想绑定属性SelectedItem到listview selected item。但是好像treeview的selectedItem属性是只读的

    <TreeView Name="tv" ItemsSource="{Binding ChildAndAttributes}" VerticalAlignment="Stretch" Margin="12,12,12,35">
        <TreeView.Resources>
            <DataTemplate DataType="{x:Type tvcc:NodeViewModel}">
                <TextBlock Text="{Binding Text}" />
            </DataTemplate>
            <DataTemplate DataType="{x:Type tvcc:NodeAttributeViewModel}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding AttributeName}"  />
                    <TextBlock Text="{Binding AttributeValue}" Padding="2,0,0,0" Foreground="Blue" />
                </StackPanel>
            </DataTemplate>
        </TreeView.Resources>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildAndAttributes}">
                <ContentControl Content="{Binding}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>

WPF MVVM:从列表视图中选择treeviewem

下面是tree https://stackoverflow.com/a/18265571/634219的一些扩展,允许您绑定树的selecteditem:

public class TreeViewEx : TreeView
{
    public TreeViewEx()
    {
        SelectedItemChanged += TreeViewEx_SelectedItemChanged;
    }
    void TreeViewEx_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        SelectedItem = e.NewValue;
    }
    #region SelectedItem
    /// <summary>
    /// Gets or Sets the SelectedItem possible Value of the TreeViewItem object.
    /// </summary>
    public new object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }
    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public new static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(object), typeof(TreeViewEx), new PropertyMetadata(SelectedItemProperty_Changed));
    static void SelectedItemProperty_Changed(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var targetObject = dependencyObject as TreeViewEx;
        if (targetObject != null)
        {
            var tvi = targetObject.FindItemNode(targetObject.SelectedItem);
            if (tvi != null)
                tvi.IsSelected = true;
        }
    }
    #endregion SelectedItem
    public TreeViewItem FindItemNode(object item)
    {
        TreeViewItem node = null;
        foreach (object data in Items)
        {
            node = ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
            if (node != null)
            {
                if (data == item)
                    break;
                node = FindItemNodeInChildren(node, item);
                if (node != null)
                    break;
            }
        }
        return node;
    }
    protected TreeViewItem FindItemNodeInChildren(TreeViewItem parent, object item)
    {
        TreeViewItem node = null;
        bool isExpanded = parent.IsExpanded;
        if (!isExpanded) //Can't find child container unless the parent node is Expanded once
        {
            parent.IsExpanded = true;
            parent.UpdateLayout();
        }
        foreach (object data in parent.Items)
        {
            node = parent.ItemContainerGenerator.ContainerFromItem(data) as TreeViewItem;
            if (data == item && node != null)
                break;
            node = FindItemNodeInChildren(node, item);
            if (node != null)
                break;
        }
        if (node == null && parent.IsExpanded != isExpanded)
            parent.IsExpanded = isExpanded;
        if (node != null)
            parent.IsExpanded = true;
        return node;
    }
} 

TreeView中选择TreeViewItem的最简单方法之一是将数据绑定到TreeViewItem.IsSelected属性。这个确实意味着您必须向数据类型类添加一个额外的bool IsSelected属性,但是它将使您能够从视图模型中选择任何项。您可以在Style:

中对此属性进行数据绑定。
<Style TargetType="{x:Type TreeViewItem}">
    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>

可选地,您可能还希望数据绑定到TreeViewItem.IsExpanded属性,以便您可以选择从视图模型展开相关项:

YourDataType item = Items.First(i => i.Id == someValue);
item.IsSelected = true;
item.IsExpanded = true;