DataBound TreeView






4.64/5 (24投票s)
一个可以绑定到 DataTable 的 TreeView,并且可以跟踪其变化。
在 DataGrid
中对表所做的更改同时显示在 TreeView
中(来自演示项目)。
引言
像许多其他人一样,当我需要使用 TreeView
控件时,我发现自己反复执行一个 Load
方法,将 DataTable
或 DataView
中的数据适配到 TreeView
中。此外,如果值发生变化,我必须在控件中维护相同的数据。
本文的目的是向您展示如何开发一个 TreeView
,该控件可以绑定到数据源,并可以跟踪数据中的更改,从而更新节点。
主要目标
- 将数据加载到树结构中。
- 跟踪数据中的更改,并在控件中显示它们。
- 除了
SelectedNode
之外,公开一个类似SelectedValue
的 get/set 属性,通常您拥有要选择的节点的值(但不是节点本身!)。
类结构
该项目中有两个类,TreeNodeBound
类继承自 TreeNode
并公开两个属性:Value
和 ParentValue
;以及 TreeViewBound
(控件本身)类,它公开 DataSource
、DisplayMember
、ValueMember
和 ParentMember
属性。
加载数据
让我们看一下 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
控件,它可以绑定到任何实现 IList
或 IListSource
的对象,就像其他控件(例如 ComboBox
)一样,但使用这种类型的数据源,控件无法跟踪更改。因此,我削减了一些功能以添加另一个功能,我认为它更有用。我期待您的想法。
历史
- 2005 年 10 月 11 日 - 文章提交。