概述
这应该是一个简单的问题,将 TreeView 的 selected item 属性绑定到您的源上的某些东西。但是,由于 TreeView 控件的构建方式,您必须使用开箱即用的 WPF 编写更多代码来获得对 MVVM 友好的解决方案。
如果您使用的是香草 WPF(我假设您是),那么我建议您使用附加行为。附加的行为将绑定到主视图模型上的一个操作,当 TreeView 的选择更改时将调用该操作。您也可以调用命令而不是操作,但我将向您展示如何使用操作。
基本上,总体思路是使用细节视图模型的一个实例,该实例将作为主视图模型的属性提供。然后,您可以使用轻量级对象,而不是拥有数百个视图模型实例的 RootItems 集合,这些对象仅具有节点的显示名称,并且可能在它们后面具有某种 id 字段。当 TreeView 上的选择发生变化时,您希望通过调用方法或设置属性来通知您的详细信息视图模型。在下面的演示代码中,我在 DetailsViewModel 上设置了一个名为 Selection 的属性。
代码演练
这是附加行为的代码:
public static class TreeViewBehavior
{
public static readonly DependencyProperty SelectionChangedActionProperty =
DependencyProperty.RegisterAttached("SelectionChangedAction", typeof (Action<object>), typeof (TreeViewBehavior), new PropertyMetadata(default(Action), OnSelectionChangedActionChanged));
private static void OnSelectionChangedActionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var treeView = sender as TreeView;
if (treeView == null) return;
var action = GetSelectionChangedAction(treeView);
if (action != null)
{
// Remove the next line if you don't want to invoke immediately.
InvokeSelectionChangedAction(treeView);
treeView.SelectedItemChanged += TreeViewOnSelectedItemChanged;
}
else
{
treeView.SelectedItemChanged -= TreeViewOnSelectedItemChanged;
}
}
private static void TreeViewOnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var treeView = sender as TreeView;
if (treeView == null) return;
InvokeSelectionChangedAction(treeView);
}
private static void InvokeSelectionChangedAction(TreeView treeView)
{
var action = GetSelectionChangedAction(treeView);
if (action == null) return;
var selectedItem = treeView.GetValue(TreeView.SelectedItemProperty);
action(selectedItem);
}
public static void SetSelectionChangedAction(TreeView treeView, Action<object> value)
{
treeView.SetValue(SelectionChangedActionProperty, value);
}
public static Action<object> GetSelectionChangedAction(TreeView treeView)
{
return (Action<object>) treeView.GetValue(SelectionChangedActionProperty);
}
}
然后,在 TreeView 元素的 XAML 中,应用以下内容:local:TreeViewBehavior.SelectionChangedAction="{Binding Path=SelectionChangedAction}"
. 请注意,您必须用 local 替换TreeViewBehavior
类的命名空间。
现在,将以下属性添加到 MainWindowViewModel:
public Action<object> SelectionChangedAction { get; private set; }
public DetailsViewModel DetailsViewModel { get; private set; }
在 MainWindowViewModel 的构造函数中,您需要将 SelectionChangedAction 属性设置为某个值。SelectionChangedAction = item => DetailsViewModel.Selection = item;
如果您的 DetailsViewModel 上有一个 Selection 属性,您可能会这样做。这完全取决于你。
最后,在您的 XAML 中,将详细信息视图连接到其视图模型,如下所示:
<View:ItemDetails DataContext="{Binding Path=DetailsViewModel}" />
这是使用直接 WPF 的 MVVM 友好解决方案的基本架构。现在,话虽如此,如果您使用像 Caliburn.Micro 或 PRISM 这样的框架,您的方法可能与我在这里提供的不同。要时刻铭记在心。