【问题标题】:WPF MVVM : Select TreeViewItem from ListViewWPF MVVM:从 ListView 中选择 TreeViewItem
【发布时间】:2014-08-07 00:55:51
【问题描述】:

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

但是当用户从 listView 中单击一个项目时,该特定项目(它是树视图中的一个节点)应该在树视图中被选中。我不知道该怎么做。 基本上我想将属性 SelectedItem 绑定到 listview 选定项目。但似乎 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>

【问题讨论】:

    标签: c# wpf xaml listview mvvm


    【解决方案1】:

    这是树https://stackoverflow.com/a/18265571/634219 的一些扩展,允许您绑定树的选定项:

    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;
        }
    } 
    

    【讨论】:

      【解决方案2】:

      TreeView 中选择TreeViewItem 的最简单方法之一是将数据绑定到TreeViewItem.IsSelected Property。这确实意味着您必须将额外的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 Property,以便您可以选择从视图模型中展开相关项目:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-20
        • 1970-01-01
        • 2010-12-26
        • 1970-01-01
        相关资源
        最近更新 更多