
Changes made to the table in the DataGrid are shown at the same time at the TreeView (from demo project).
Like so many others, when I needed to use the TreeView control, I found myself doing a Load method adapting the data from a DataTable or a DataView into the TreeView, over and over again. Furthermore, I had to maintain the same data in the control if the values changed.
The purpose of this article is to show you how to develop a TreeView that can be bound to a datasource and can keep track of the changes made in the data, updating the nodes.
SelectedValue besides SelectedNode, generally you have the value of the node you want to select (but not the node itself!!!). There are two classes in the project, the TreeNodeBound class that inherits from TreeNode and exposes two properties: Value and ParentValue; and the TreeViewBound (the control itself) class that exposes the DataSource, DisplayMember, ValueMember, and ParentMember properties.
Let's have a look at the LoadTree function in the TreeViewBound class. I used a Hashtable to place the nodes by ValueMember, that's where the trick is.
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);
}
}
}
}
First, I create the nodes and add it to the Hashtable. Then, I iterate through the nodes, look for the parent node of the node (by the ValueMember again) and add it as a child of the parent. If the node has no parent, it's a root node and I have to add it to the root collection.
Because classes in .NET are reference types, the whole tree structure is loaded. By doing this, we avoid doing a while (!finish) type algorithm, very frequently used in biz.
For that, I subscribe to the events in the DataSource property.
//subscribe to datatable events
value.RowDeleting += new DataRowChangeEventHandler(value_RowDeleting);
value.RowChanged += new DataRowChangeEventHandler(value_RowChanged);
There are four possible changes that are taken care of:
DisplayMember value of a node.
Both cases are trouble-free because of the use of the TreeNodeBound class and the 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];
}
}
}
At first, I came with the idea of a TreeView control that could be bound to any object that implements IList or IListSource like in other controls such as the ComboBox, but with this type of data sources the control couldn't keep track of changes. So, I cut back some functionality to add another one, which I think, is more useful. I look forward to your thoughts.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||