Winform中的IHierarchyData和IHierarchicalEnumerable

时间:2010-03-13 13:08:33

标签: c# winforms treeview hierarchical-data

目前,我知道如何在树视图控件中执行延迟实现节点的加载过程,并在stackoverflow中读取相关问题,但我也在阅读asp.net中的IHierarchyData和IHierarchicalEnumerable接口(I不知道编写asp.net)允许将集合绑定到树视图以自动显示项目。

我想知道我是否可以在winforms和C#中做同样的事情。我认为之前提到的接口在winforms中不可用。

感谢。

3 个答案:

答案 0 :(得分:3)

Windows窗体TreeView不知道如何绑定到IHierarchyData实例,这并不奇怪,因为IHierarchyData和相关接口打算供Web控件使用(特别是网站地图)。

但是,构建自己的数据绑定类真的不太难。这似乎是一个有趣的问题所以我把它们放在一起只是为了好玩。我会引导你完成内部工作。

首先,创建一个基本的Component类。 Visual Studio将使用以下代码启动您:

public partial class TreeViewHierarchyBinding : Component
{
    public TreeViewHierarchyBinding()
    {
        InitializeComponent();
    }

    public TreeViewHierarchyBinding(IContainer container)
    {
        container.Add(this);
        InitializeComponent();
    }
}

此组件需要具有的一个显而易见的“状态”是从每个TreeNode到其IHierarchyData的映射。现在我们可以通过将它放在TreeNode的{​​{1}}属性中来解决这个问题,但是我们的目标是让这个组件尽可能无创,并跟踪它自己的状态。因此,我们将使用字典。将此字段添加到类:

Tag

现在,至少,该组件需要知道如何从其相应绑定的private Dictionary<TreeNode, IHierarchyData> nodeDictionary = new Dictionary<TreeNode, IHierarchyData>(); 填充TreeNode类的特定父TreeView,所以让我们接下来编写该代码:

IHierarchyData

这部分应该非常简单。第一种方法使用private void PopulateChildNodes(TreeNodeCollection parentCollection, IHierarchicalEnumerable children) { parentCollection.Clear(); foreach (object child in children) { IHierarchyData childData = children.GetHierarchyData(child); TreeNode childNode = new TreeNode(childData.ToString()); if (childData.HasChildren) { childNode.Nodes.Add("Dummy"); // Make expandable } nodeDictionary.Add(childNode, childData); parentCollection.Add(childNode); } } private void UpdateRootNodes(TreeView tv, IHierarchyData hierarchyData) { if (tv == null) { return; } tv.Nodes.Clear(); if (hierarchyData != null) { IHierarchicalEnumerable roots = hierarchyData.GetChildren(); PopulateChildNodes(tv.Nodes, roots); } } 接口,使用从TreeNodeCollection实例获取的层次结构填充Nodes(即TreeNode的{​​{1}}属性)。这个方法唯一真正有趣的事情是:

  1. IHierarchyData实例有子节点时添加虚节点;这使得“+”在树视图中可见,否则我们将无法进一步扩展;以及

  2. 将新添加的节点添加到与其匹配的IHierarchyEnumerable实例的字典中。

  3. 第二种方法更简单,它执行初始的“绑定工作”,用我们的顶级IHierarchyData实例替换树的 root 中的任何内容。

    我们的组件需要做的下一件事是挂钩IHierarchyData的加载事件来执行延迟加载。这是执行此操作的代码:

    IHierarchyData

    前两个方法应该是不言自明的,第三个方法是实际的延迟加载代码。我们在这里作弊,使用TreeView属性来描述子节点是否已经加载,因此我们不会进行任何不必要的重新加载。当我实现延迟加载的树时,我总是这样做,因为根据我的经验,我几乎从不使用private void RegisterEvents(TreeView tv) { tv.BeforeExpand += TreeViewBeforeExpand; } private void UnregisterEvents(TreeView tv) { tv.BeforeExpand -= TreeViewBeforeExpand; } private void TreeViewBeforeExpand(object sender, TreeViewCancelEventArgs e) { if (e.Node.Checked) { return; } IHierarchyData hierarchyData; if (nodeDictionary.TryGetValue(e.Node, out hierarchyData)) { PopulateChildNodes(e.Node.Nodes, hierarchyData.GetChildren()); e.Node.Checked = true; } } 属性。但是,如果您确实需要将此属性用于其他内容,则可以使用其他属性(如TreeNode.Checked),创建另一个字典以保存展开状态,或修改现有字典以保存复合类(包含TreeNode.Checked以及Tag属性)。我现在保持简单。

    如果您之前在树中实现了延迟加载,其余部分应该已经有意义了,所以让我们跳过。实际上,此时唯一要做的就是实现一些设计师/用户属性,这些属性实际上将连接树和数据:

    IHierarchyData

    容易腻。我们有一个Expanded属性,可以接受根private IHierarchyData dataSource; private TreeView treeView; [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public IHierarchyData DataSource { get { return dataSource; } set { if (value != dataSource) { dataSource = value; nodeDictionary.Clear(); UpdateRootNodes(treeView, value); } } } [Category("Behavior")] [DefaultValue(null)] [Description("Specifies the TreeView that the hierarchy should be bound to.")] public TreeView TreeView { get { return treeView; } set { if (value != treeView) { if (treeView != null) { UnregisterEvents(treeView); } treeView = value; nodeDictionary.Clear(); RegisterEvents(value); UpdateRootNodes(treeView, dataSource); } } } DataSource属性,您可以从设计器中访问该属性。同样,这里简单的东西,当更新IHierarchyData属性时,我们只是重置查找并重新填充根。当TreeView属性更新时,我们需要做更多的工作,注册事件,确保从旧树视图中取消注册事件,并完成我们在数据源更改时所做的所有事情。

    真的就是这一切!打开Windows窗体设计器,删除DataSource,然后删除TreeView并将其TreeView属性设置为刚删除的树视图。最后,在你的代码中(即在TreeViewHierarchyBinding事件中),给它一个数据源:

    TreeView

    (注意 - 这会使用MSDN page for IHierarchyData上的示例Form_Load。示例不是非常强大,它不检查private void Form1_Load(object sender, EventArgs e) { DirectoryInfo dir = new DirectoryInfo("C:\\"); treeViewHierarchyBinding1.DataSource = new FileSystemHierarchyData(dir); } 或其他任何内容,但它足够好证明这一点。)

    就是这样。运行您的应用并观看它绑定。您现在可以在任何地方重复使用FileSystemHierarchyData组件 - 只需将其放在表单上,​​为其分配UnauthorizedAccessException,然后将TreeViewHierarchyBinding实例作为数据源。

    如果你想要一个复制粘贴版本,我已经放了complete code on PasteBin

    玩得开心!

答案 1 :(得分:1)

接口可用,但需要添加对System.Web.UI的引用。 (它可能还需要您使用完整的.NET Framework可再发行组件而不是客户端配置文件,尽管我不确定。)

更大的问题是:WinForms TreeView控件是否自动了解如何使用这些接口?我相信这个问题的答案是“不”,但你需要测试/验证。

答案 2 :(得分:1)

有一篇有趣的文章here向您展示如何构建扩展方法以实现我认为您正在寻找的东西。 System.Windows.Forms.TreeView中没有本机可用性来绑定到我能找到的集合。

您可以在项目中包含System.Web.UI,以使IHierarchyData和IHierarchicalEnumerable接口可用,但如果没有扩展方法,TreeView将无法附加到它们。

来自网站的示例源代码将允许您将任何IDictionary集合绑定到TreeView。