wpf - 使用 MVVM 获取选定的 TreeViewItem

标签 wpf mvvm treeview selecteditem

所以有人建议使用 WPF TreeView,我想:“是的,这似乎是正确的方法。”现在,几个小时后,我简直不敢相信使用这个控件有多么困难。通过大量研究,我能够使 TreeView` 控件正常工作,但我根本找不到将所选项目获取到 View 模型的“正确”方法。我不需要从代码中设置所选项目;我只需要我的 View 模型知道用户选择了哪个项目。

到目前为止,我已经有了这个 XAML,它本身并不是很直观。这些都在 UserControl.Resources 标签内:

<CollectionViewSource x:Key="cvs" Source="{Binding ApplicationServers}">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="DeploymentEnvironment"/>
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

<!-- Our leaf nodes (server names) -->
<DataTemplate x:Key="serverTemplate">
    <TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>

<!-- Note: The Items path refers to the items in the CollectionViewSource group (our servers).
           The Name path refers to the group name. -->
<HierarchicalDataTemplate x:Key="categoryTemplate"
                          ItemsSource="{Binding Path=Items}"
                          ItemTemplate="{StaticResource serverTemplate}">
    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
</HierarchicalDataTemplate>

这是 TreeView :

<TreeView DockPanel.Dock="Bottom" ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}"
              ItemTemplate="{StaticResource categoryTemplate}">
            <Style TargetType="TreeViewItem">
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
            </Style>
        </TreeView>

这可以按环境(开发、QA、产品)正确显示服务器。然而,我在 SO 上找到了多种获取所选项目的方法,其中许多方法都很复杂且困难。有没有一种简单方法将所选项目获取到我的 View 模型?

注意:TreeView` 上有一个 SelectedItem 属性,但它是只读的。让我沮丧的是,只读就可以了;我不想通过代码更改它。但我无法使用它,因为编译器提示它是只读的。

还有一个看似优雅的建议,可以做这样的事情:

<ContentPresenter Content="{Binding ElementName=treeView1, Path=SelectedItem}" />

我问了这个问题:“你的 View 模型如何获取此信息?我知道 ContentPresenter 保存了所选项目,但我们如何将其传递给 View 模型?”但目前还没有答案。

所以,我的总体问题是:“是否有一种简单方法将所选项目获取到我的 View 模型?”

最佳答案

要执行您想要的操作,您可以修改 TreeViewItemContainerStyle:

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>

您的 View 模型(树中每个项目的 View 模型)必须公开一个 bool IsSelected 属性。

如果您希望能够控制特定的 TreeViewItem 是否展开,您也可以为该属性使用 setter:

<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>

然后,您的 View 模型必须公开一个 bool IsExpanded 属性。

请注意,这些属性是双向工作的,因此如果用户在树中选择一个节点, View 模型的 IsSelected 属性将设置为 true。另一方面,如果您在 View 模型上将 IsSelected 设置为 true,则将选择该 View 模型的树中的节点。扩展也是如此。

如果您没有树中每个项目的 View 模型,那么您应该获得一个。没有 View 模型意味着您正在使用模型对象作为 View 模型,但要使其正常工作,这些对象需要一个 IsSelected 属性。

要在父 View 模型(绑定(bind)到 TreeView 并且具有 subview 模型集合的 View 模型)上公开 SelectedItem 属性,您可以实现像这样:

public ChildViewModel SelectedItem {
  get { return Items.FirstOrDefault(i => i.IsSelected); }
}
<小时/>

如果您不想跟踪树上每个单独项目的选择,您仍然可以使用 TreeView 上的 SelectedItem 属性。但是,为了能够实现“MVVM 风格”,您需要使用 Blend 行为(可作为各种 NuGet 包 - 搜索“blend interactivity”)。

这里我添加了一个EventTrigger,每次树中所选项目发生变化时都会调用一个命令:

<TreeView x:Name="treeView">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
      <i:InvokeCommandAction
        Command="{Binding SetSelectedItemCommand}"
        CommandParameter="{Binding SelectedItem, ElementName=treeView}"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</TreeView>

您必须在返回 ICommandTreeViewDataContext 上添加属性 SetSelectedItemCommand。当 TreeView 的所选项目更改时,将使用所选项目作为参数调用命令上的 Execute 方法。创建命令的最简单方法可能是使用 DelegateCommand(通过 google 获取实现,因为它不是 WPF 的一部分)。

一个可能更好的替代方案是使用 BindableSelectedItemBehavior 来允许双向绑定(bind)而不需要笨重的命令。由 Steve Greatrex 在 Stack Overflow 上提供。

关于wpf - 使用 MVVM 获取选定的 TreeViewItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9143107/

相关文章:

c# - 如何为数据网格的 NewItemPlaceholder 行添加模板?

c# - MVVM + 中介模式 : Registration of Mediator occurs too late

c# - 通过代码向 WPF 功能区添加新项目

c# - 发送 ContentPresented 的内容作为附加的命令参数

python - tkinter Treeview 所选项目的点击事件

c# - 如何在 TreeView 中删除所有未选中的节点及其父节点?

c# - SizeToContent.Width 和 TreeView

c# - 使用数据绑定(bind),根据 ComboBox 中选定的时区在文本框中显示时间

c# - 与 Caliburn Micro 问题的深度属性绑定(bind)

java - ViewPager MVVM、数据绑定(bind) Android