使用MVVM获取选定的TreeViewItem [英] Get Selected TreeViewItem Using MVVM

查看:131
本文介绍了使用MVVM获取选定的TreeViewItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So someone suggested using a WPF TreeView, and I thought: "Yeah, that seems like the right approach." Now, hours and hours later, I simply can't believe how difficult it has been to use this control. Through a bunch of research, I was able to get the TreeView` control working, but I simply cannot find the "proper" way to get the selected item to the view model. I do not need to set the selected item from code; I just need my view model to know which item the user selected.

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

So far, I have this XAML, which isn't very intuitive on its own. This is all within the UserControl.Resources tag:

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

这可以按环境正确显示服务器(dev,QA,prod).但是,我在SO上找到了多种获取所选项目的方法,其中许多方法都是令人费解且困难的.是否有简单方法将所选项目添加到我的视图模型?

This correctly shows servers by environment (dev, QA, prod). However, I've found various ways on SO to get the selected item, and many are convoluted and difficult. Is there a simple way to get the selected item to my view model?

注意:TreeView`上有一个SelectedItem属性,但它是只读的.让我感到沮丧的是,只读就好了.我不想通过代码更改它.但是我不能使用它,因为编译器抱怨它是只读的.

Note: There is a SelectedItem property on the TreeView`, but it's read-only. What's frustrating to me is that read-only is just fine; I don't want to change it via code. But I can't use it because the compiler complains that it's read-only.

似乎也有这样的建议:

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

然后我问了一个问题:您的视图模型如何获取此信息?我得到ContentPresenter保留选定的项目,但是如何将其传递给视图模型呢?"但是还没有答案.

And I asked this question: "How can your a view model get this information? I get that ContentPresenter holds the selected item, but how do we get that over to the view model?" But there is no answer yet.

因此,我的总体问题是:是否有简单方法将所选项目添加到我的视图模型?"

So, my overall question is: "Is there a simple way to get the selected item to my view model?"

推荐答案

要执行所需的操作,可以修改TreeViewItemContainerStyle:

To do what you want you can modify the ItemContainerStyle of the TreeView:

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

您的视图模型(树中每个项目的视图模型)必须公开一个布尔型IsSelected属性.

Your view-model (the view-model for each item in the tree) then has to expose a boolean IsSelected property.

如果您希望能够控制是否扩展了特定的TreeViewItem,也可以对该属性使用设置器:

If you want to be able to control if a particular TreeViewItem is expanded you can use a setter for that property too:

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

然后,您的视图模型必须公开布尔IsExpanded属性.

Your view-model then has to expose a boolean IsExpanded property.

请注意,这些属性同时起作用,因此,如果用户在树中选择一个节点,则视图模型的IsSelected属性将设置为true.另一方面,如果在视图模型上将IsSelected设置为true,则将选择该视图模型的树中的节点.以及扩展.

Note that these properties work both ways so if the user selects a node in the tree the IsSelected property of the view-model will be set to true. On the other hand if you set IsSelected to true on a view-model the node in the tree for that view-model will be selected. And likewise with expanded.

如果您没有树中每个项目的视图模型,那么您应该得到一个.没有视图模型意味着您将模型对象用作视图模型,但是要使其正常工作,这些对象需要一个IsSelected属性.

If you don't have a view-model for each item in the tree, well, then you should get one. Not having a view-model means that you are using your model objects as view-models, but for this to work these objects require an IsSelected property.

要在父视图模型上公开一个SelectedItem属性(绑定到TreeView并具有子视图模型的集合),可以这样实现:

To expose an SelectedItem property on your parent view-model (the one you bind to the TreeView and that has a collection of child view-models) you can implement it like this:

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


如果您不想跟踪树上每个项目的选择,您仍然可以使用TreeView上的SelectedItem属性.但是,要使其具有"MVVM风格",您需要使用Blend行为(可作为各种NuGet软件包使用-搜索混合交互性".)


If you don't want to track selection on each individual item on the tree you can still use the SelectedItem property on the TreeView. However, to be able to do it "MVVM style" you need to use a Blend behavior (available as various NuGet packages - search for "blend interactivity").

在这里,我添加了EventTrigger,每当树中所选项目更改时,该命令就会调用一个命令:

Here I have added an EventTrigger that will invoke a command each time the selected item changes in the tree:

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

您将必须在TreeViewDataContext上添加属性SetSelectedItemCommand,并返回ICommand.当树形视图的选定项目更改时,将以选定项目为参数调用命令上的Execute方法.创建命令的最简单方法可能是使用DelegateCommand(使用Google来获取实现,因为它不是WPF的一部分).

You will have to add a property SetSelectedItemCommand on the DataContext of the TreeView returning an ICommand. When the selected item of the tree view changes the Execute method on the command is called with the selected item as the parameter. The easiest way to create a command is probably to use a DelegateCommand (google it to get an implementation as it is not part of WPF).

一种可能更好的替代方法,它允许在没有笨拙命令的情况下进行双向绑定,请使用由Steve Greatrex提供的 BindableSelectedItemBehavior 堆栈溢出.

A perhaps better alternative that allows two-way binding without the clunky command is to use BindableSelectedItemBehavior provided by Steve Greatrex here on Stack Overflow.

这篇关于使用MVVM获取选定的TreeViewItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆