使用TreeView的主/详细信息视图 [英] Master/detail view using TreeView

查看:126
本文介绍了使用TreeView的主/详细信息视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的实施主/详细信息使用一个TreeView和一个自定义的详细信息,我的应用程序视图中查看控制。我也想坚持到MVVM模式。

I'm working on implementing a master/details view in my application using a TreeView and a custom details view control. I'm also trying to stick to the MVVM pattern.

眼下TreeView控件绑定到包含所有的细节视图模型对象的集合,并详细查看绑定到TreeView的选定项目。

Right now the TreeView is bound to a collection of view model objects that contain all of the details and the details view is bound to the selected item of the TreeView.

这伟大的工程...直到TreeView的节点之一有5000名儿童和应用程序突然占用了500MB RAM

This works great... until one of the TreeView nodes has 5,000 children and the application is suddenly taking up 500MB of RAM.

主窗口视图模型:

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();
    }

    // ...
}

项目视图模型:

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

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

    // ...
}

下面是我如何结合详情查看:

Here's how I'm binding the details view:

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



我是相当新的WPF和MVVM模式,但似乎我想要的浪费到TreeView到一个较小的,简化的对象,只需要显示的项目(如名称和ID)属性集合绑定,那么一旦它被选中都装载的细节。我怎么会去这样做这样的事情?

I'm fairly new to WPF and the MVVM pattern, but it seems like a waste to I want to bind the TreeView to a collection of a smaller, simplified object that only has properties necessary for displaying the item (like Name and ID), then once it is selected have all of the details loaded. How would I go about doing something like this?

推荐答案

概述

这的的是TreeView的所选项目属性绑定到你的源上的东西一件简单的事情。但是,由于方式的TreeView控件建,你必须编写更多的代码来获得一个MVVM友好的解决方案,采用外装即用WPF。

This should be a simple matter of binding the TreeView's selected item property to something on your source. However, because of the way the TreeView control was built, you have to write more code to get an MVVM-friendly solution, using out-of-the-box WPF.

如果您使用的香草WPF(这我假设你是),那么我建议你用一个附加行为去。附加的行为将绑定到你的主视图模型的动作,将被TreeView的选择更改时调用。您也可以调用命令,而不是一个动作,但我要告诉你如何使用操作。

If you're using vanilla WPF (which I'm assuming you are), then I'd recommend going with an attached behavior. The attached behavior would bind to an action on your main view model that would be invoked when the TreeView's selection changes. You could also invoke a command instead of an action, but I'm going to show you how to use an action.

基本上,总体思路是用一个实例您的详细信息视图模式,将提供为你的主视图模型的属性。然后,而不是数百视图模型的实例您RootItems集合,你可以使用简单的对节点的显示名称,也许某种他们身后id字段的重量轻的物体。当您的TreeView变化的选择,你要通知您的详细信息通过调用一个方法或设置一个属性查看模式。在下面的演示代码,我设置的DetailsViewModel属性叫做选择。

Basically, the overall idea is to use one instance of your details view model that will be made available as a property of your master view model. Then, instead of your RootItems collection having hundreds of instances of view models, you can use light-weight objects that simply have a display name for the node and perhaps some kind of id field behind them. When the selection on your TreeView changes, you want to notify your details view model by either calling a method or setting a property. In the demonstration code below, I'm setting a property on the DetailsViewModel called Selection.

演练与代码

下面是附加的行为的代码:

Here's the code for the attached behavior:

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,适用以下内容:地方:TreeViewBehavior.SelectionChangedAction ={绑定路径= SelectionChangedAction}。请注意,您需要替换本地的 TreeViewBehavior 类的命名空间。

Then, in the XAML on your TreeView element, apply the following: local:TreeViewBehavior.SelectionChangedAction="{Binding Path=SelectionChangedAction}". Note that you will have to substitute local for the namespace of the TreeViewBehavior class.

现在,添加以下属性您MainWindowViewModel:

Now, add the following properties to your MainWindowViewModel:

public Action<object> SelectionChangedAction { get; private set; } 
public DetailsViewModel DetailsViewModel { get; private set; }

在您MainWindowViewModel的构造函数,你需要设置SelectionChangedAction属性的东西。你可能会做 SelectionChangedAction =项目=> DetailsViewModel.Selection =项目; 如果你的DetailsViewModel上有一个选择属性。 。这完全取决于你

In your MainWindowViewModel's constructor, you need to set the SelectionChangedAction property to something. You might do SelectionChangedAction = item => DetailsViewModel.Selection = item; if your DetailsViewModel has a Selection property on it. That's entirely up to you.

最后,在你的XAML,线材细节查看最多的浏览模式,像这样:

And finally, in your XAML, wire the details view up to its view model like so:

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

这是一个使用WPF直MVVM一个友好的解决方案的基本架构。现在,随着中说,如果你使用像Caliburn.Micro或棱镜的框架,你的方法可能会比在这里提供什么,我不同。只要保持这一点。

That's the basic architecture of an MVVM friendly solution using straight WPF. Now, with that said, if you're using a framework like Caliburn.Micro or PRISM, your approach would probably be different than what I've provided here. Just keep that in mind.

这篇关于使用TreeView的主/详细信息视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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