Bob*_*orn 16 wpf treeview selecteditem mvvm
所以有人建议使用WPF TreeView,我想:"是的,这似乎是正确的方法." 现在,几个小时后,我简直无法相信使用这个控件有多困难.通过一系列研究,我能够使TreeView`控件正常工作,但我找不到"正确"的方法来将所选项目添加到视图模型中.我不需要从代码中设置所选项目; 我只需要我的视图模型就可以知道用户选择了哪个项目.
到目前为止,我有这个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>
Run Code Online (Sandbox Code Playgroud)
这是树视图:
<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>
Run Code Online (Sandbox Code Playgroud)
这通过环境(dev,QA,prod)正确显示服务器.但是,我已经在SO上找到了各种方法来获取所选项目,而且很多都很复杂和困难.有没有一种简单的方法可以将所选项目添加到我的视图模型中?
注意:SelectedItemTreeView`上有一个属性,但它是只读的.让我感到沮丧的是,只读是好的; 我不想通过代码更改它.但我无法使用它,因为编译器抱怨它是只读的.
做这样的事情也有一个看似优雅的建议:
<ContentPresenter Content="{Binding ElementName=treeView1, Path=SelectedItem}" />
Run Code Online (Sandbox Code Playgroud)
我问了这个问题:"你的视图模型如何获取这些信息?我得到的是ContentPresenter所选项目,但我们如何将其转化为视图模型?" 但是还没有答案.
所以,我的整体问题是:"是否有一种简单的方法可以将所选项目添加到我的视图模型中?"
Mar*_*age 29
做你想做的,你可以修改什么ItemContainerStyle的TreeView:
<TreeView>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Run Code Online (Sandbox Code Playgroud)
然后,您的视图模型(树中每个项目的视图模型)必须公开布尔IsSelected属性.
如果您希望能够控制某个特定TreeViewItem的扩展,那么您也可以使用该属性的setter:
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
Run Code Online (Sandbox Code Playgroud)
然后,您的视图模型必须公开布尔IsExpanded属性.
请注意,这些属性可以双向工作,因此,如果用户在树中选择一个节点IsSelected,则视图模型的属性将设置为true.另一方面,如果IsSelected在视图模型上设置为true,则将选择树视图模型中的节点.同样扩大了.
如果你没有树中每个项目的视图模型,那么你应该得到一个.没有视图模型意味着您将模型对象用作视图模型,但为了使其工作,这些对象需要一个IsSelected属性.
要SelectedItem在父视图模型上显示一个属性(绑定到该视图模型TreeView并具有子视图模型集合的属性),您可以像这样实现它:
public ChildViewModel SelectedItem {
get { return Items.FirstOrDefault(i => i.IsSelected); }
}
Run Code Online (Sandbox Code Playgroud)
如果您不想跟踪树上每个项目的选择,您仍然可以使用该SelectedItem属性TreeView.但是,为了能够实现"MVVM样式",您需要使用Blend行为(可用作各种NuGet包 - 搜索"混合交互").
在这里,我添加了一个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>
Run Code Online (Sandbox Code Playgroud)
你必须在返回的a SetSelectedItemCommand上添加一个属性.当树视图的选定项更改时,将使用所选项作为参数调用命令上的方法.创建命令的最简单方法可能是使用a (谷歌获取实现,因为它不是WPF的一部分).DataContextTreeViewICommandExecuteDelegateCommand
允许双向绑定而不使用clunky命令的更好的替代方法是使用Steve Greatrex在Stack Overflow上提供的BindableSelectedItemBehavior.