gpt4 book ai didi

c# - 使用 TreeView 的主视图/详细 View

转载 作者:行者123 更新时间:2023-11-30 17:06:46 24 4
gpt4 key购买 nike

我正在使用 TreeView 和自定义详细信息 View 控件在我的应用程序中实现主/详细信息 View 。我也在努力坚持 MVVM 模式。

现在 TreeView 绑定(bind)到包含所有详细信息的 View 模型对象集合,详细信息 View 绑定(bind)到 TreeView 的选定项。

效果很好……直到其中一个 TreeView 节点有 5,000 个子节点并且应用程序突然占用了 500MB 的 RAM。

主窗口 View 模型:

public class MainWindowViewModel
{
private readonly List<ItemViewModel> rootItems;

public List<ItemViewModel> RootItems { get { return rootItems; } } // TreeView is bound to this property.

public MainWindowViewModel()
{
rootItems = GetRootItems();
}

// ...
}

项目 View 模型:

public ItemViewModel
{
private readonly ModelItem item; // Has a TON of properties
private readonly List<ItemViewModel> children;

public List<ItemViewModel> Children { get { return children; } }

// ...
}

下面是我如何绑定(bind)详细信息 View :

<View:ItemDetails DataContext="{Binding SelectedItem, ElementName=ItemTreeView}" />

我对 WPF 和 MVVM 模式相当陌生,但我想将 TreeView 绑定(bind)到一个较小的简化对象集合,该集合仅具有显示项目所需的属性(如 Name 和ID),然后在选择它后加载所有详细信息。我将如何着手做这样的事情?

最佳答案

概览

应该是将 TreeView 的选定项属性绑定(bind)到源上的某个内容的简单问题。但是,由于 TreeView 控件的构建方式,您必须使用开箱即用的 WPF 编写更多代码才能获得 MVVM 友好的解决方案。

如果您使用的是 vanilla WPF(我假设您是),那么我建议您使用附加行为。附加行为将绑定(bind)到主视图模型上的一个操作,当 TreeView 的选择发生变化时将调用该操作。您也可以调用命令而不是操作,但我将向您展示如何使用操作。

基本上,总体思路是使用详细 View 模型的一个实例,该实例将作为主视图模型的一个属性提供。然后,您的 RootItems 集合不再有数百个 View 模型实例,您可以使用轻量级对象,这些对象只具有节点的显示名称,并且可能在它们后面有某种 id 字段。当 TreeView 上的选择发生变化时,您希望通过调用方法或设置属性来通知详细信息 View 模型。在下面的演示代码中,我在 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 属性。如果您的 DetailsViewModel 具有 Selection 属性,您可以执行 SelectionChangedAction = item => DetailsViewModel.Selection = item;。这完全取决于您。

最后,在您的 XAML 中,将详细信息 View 连接到它的 View 模型,如下所示:

<View:ItemDetails DataContext="{Binding Path=DetailsViewModel}" />

这是使用直接 WPF 的 MVVM 友好解决方案的基本架构。现在,话虽如此,如果您使用的是 Caliburn.Micro 或 PRISM 之类的框架,您的方法可能与我在此处提供的方法不同。请记住这一点。

关于c# - 使用 TreeView 的主视图/详细 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15206671/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com