65.9K
CodeProject 正在变化。 阅读更多。
Home

DataBound TreeView

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.64/5 (24投票s)

2005年10月11日

CPOL

2分钟阅读

viewsIcon

103246

downloadIcon

3136

一个可以绑定到 DataTable 的 TreeView,并且可以跟踪其变化。

Changes made to the table in the Datagrid are shown at the same time at the Treeview (from demo project).

DataGrid 中对表所做的更改同时显示在 TreeView 中(来自演示项目)。

引言

像许多其他人一样,当我需要使用 TreeView 控件时,我发现自己反复执行一个 Load 方法,将 DataTableDataView 中的数据适配到 TreeView 中。此外,如果值发生变化,我必须在控件中维护相同的数据。

本文的目的是向您展示如何开发一个 TreeView,该控件可以绑定到数据源,并可以跟踪数据中的更改,从而更新节点。

主要目标

  • 将数据加载到树结构中。
  • 跟踪数据中的更改,并在控件中显示它们。
  • 除了 SelectedNode 之外,公开一个类似 SelectedValue 的 get/set 属性,通常您拥有要选择的节点的值(但不是节点本身!)。

类结构

该项目中有两个类,TreeNodeBound 类继承自 TreeNode 并公开两个属性:ValueParentValue;以及 TreeViewBound(控件本身)类,它公开 DataSourceDisplayMemberValueMemberParentMember 属性。

加载数据

让我们看一下 TreeViewBound 类中的 LoadTree 函数。我使用 Hashtable 通过 ValueMember 放置节点,这就是诀窍所在。

private void LoadTree()
{
    
    if (this._datasource != null)
    {
        Clear();
        //Iterate throght the DataRow Collection
        foreach (DataRow dr in this._datasource.Rows)
        {
            TreeNodeBound node = 
                new TreeNodeBound(dr[this._displayMember].ToString());
            node.Value = dr[this._valueMember];
            node.ParentValue = dr[this._parentMember];
            //Add it to the HashTable
            _nodesByValueMember.Add(node.Value, node);
        }
        //Iterate throught the nodes Collection
        foreach (TreeNodeBound node in _nodesByValueMember.Values)
        {
            if (node.ParentValue != _rootParentValue)
            {
                //look for the parent node
                TreeNodeBound parent = 
                    (TreeNodeBound) _nodesByValueMember[node.ParentValue];
                //add it to the nodes collection of the parent node
                parent.Nodes.Add(node);
            }
            else
            {
                //the node is a Root, add it to the root collection
                base.Nodes.Add(node);
            }
        }
    }
}

首先,我创建节点并将它们添加到 Hashtable 中。然后,我遍历这些节点,查找节点的父节点(再次通过 ValueMember),并将其添加为父节点的子节点。如果节点没有父节点,则它是一个根节点,我必须将其添加到根集合中。

由于 .NET 中的类是引用类型,因此整个树结构都被加载。通过这样做,我们避免了执行 while (!finish) 类型的算法,这种算法在业务中经常使用。

跟踪数据更改

为此,我订阅了 DataSource 属性中的事件。

//subscribe to datatable events
value.RowDeleting += new DataRowChangeEventHandler(value_RowDeleting);
value.RowChanged += new DataRowChangeEventHandler(value_RowChanged);

有四种可能的更改需要处理

  • 添加
  • Deleting(删除中)
  • 修改节点的 DisplayMember 值。
  • 修改父值(这涉及将其从旧父集合中删除并将其添加到新父集合中)。

获取/设置 SelectedValue

由于使用了 TreeNodeBound 类和 Hashtable,这两种情况都没有问题。

public object SelectedValue
{
    get
    {
        if (this.SelectedNode != null)
        {
            return ((TreeNodeBound)this.SelectedNode).Value;
        }
        else
        {
            return null;
        }
    }
    set
    {
        if (value != null)
        {
            this.SelectedNode = 
                (TreeNodeBound) _nodesByValueMember[value];
        }
    }
}

摘要

起初,我想到一个 TreeView 控件,它可以绑定到任何实现 IListIListSource 的对象,就像其他控件(例如 ComboBox)一样,但使用这种类型的数据源,控件无法跟踪更改。因此,我削减了一些功能以添加另一个功能,我认为它更有用。我期待您的想法。

历史

  • 2005 年 10 月 11 日 - 文章提交。
© . All rights reserved.