Auto Binding a TreeView control from a self referencing table






4.57/5 (14 votes)
A Custom TreeView Control that supports auto binding from a single self referencing table

Introduction
This article will show how to implement a custom ASP.NET TreeView
control that supports auto binding from a self referencing table. The control supports binding from a Data Source control or programmatically using the Data Source property.
Background
This article is a continuation to my previous article showing useful functionalities that the TreeView
control lacks. The previous article demonstrated applying CSS and adding custom attributes to tree nodes. In this article, Auto Binding a TreeView
control from a Self Referencing Table is discussed.
What is a Self Referencing Table?
A self referencing table contains a relation where one of its columns references another column in the same table. For example:
In the figure above, Parent ID column references the ID column meaning that the Parent ID is an ID forming hierarchical data.
Auto Binding
ASP.NET TreeView
only supports hierarchical datasource controls. To work around that, we create a data-bound control class AutoBindingTree
that extends the base class DataBoundControl
so that we can override PerformSelect
and PerformDataBinding
events. Click here for more information on creating custom data-bound controls.
The PerformDataBinding
takes an IEnumerable
as a parameter representing the Data retrieved from the Data Source. This parameter is used to create a DataView
since it implements IEnumerable
.The DataView
is then use to create a DataSet
that maintains the Self Reference Relationship and is then used to populate the TreeView
. The DataSet
uses three mandatory properties:
DataTextField
: The name of the column holding the NodeText
ValueDataFieldID
: The name of the Column holding theID
valueDataFieldParentID
: The name of the Column holding theParentID
value
Protected Overrides Sub PerformDataBinding(ByVal oSourceData As IEnumerable)
MyBase.PerformDataBinding(oSourceData)
' Verify data exists.
If Not (oSourceData Is Nothing) Then
Dim oView As DataView = oSourceData
Dim oTable As DataTable = oView.Table
Dim oDS As DataSet = New DataSet()
oDS.Tables.Add(oTable.Copy())
'Create a Relation Between the ID Column and Parent Column
If oDS.Relations.Contains("SelfRefenceRelation") = False Then
oDS.Relations.Add("SelfRefenceRelation", _
oDS.Tables(0).Columns(DataFieldID), _
oDS.Tables(0).Columns(DataFieldParentID))
End If
oTable.Dispose()
oTable = Nothing
ViewState("TreeData") = oDS
LoadTreeView(oDS)
oDS.Dispose()
oDS = Nothing
End If
End Sub
Once the DataSet
is created, LoadTreeView
is called to populate the Treeview
:
Private Sub LoadTreeView(ByVal oDS As DataSet)
Dim oTreeView As TreeView = New TreeView()
Dim oDataRow As DataRow
For Each oDataRow In oDS.Tables(0).Rows
'Find Root Node,A root node has ParentID NULL
If oDataRow.IsNull(DataFieldParentID) Then
'Create Parent Node and add to tree
Dim oNode As New TreeNode()
oNode.Text = oDataRow(DataTextField).ToString()
oNode.Value = oDataRow(DataFieldID).ToString()
oNode.NavigateUrl = oDataRow("NavigateURL").ToString()
oTreeView.Nodes.Add(oNode)
'Recursively Populate From root
RecursivelyLoadTree(oDataRow, oNode)
End If
Next oDataRow
Controls.Add(oTreeView)
oDS.Dispose()
oDS = Nothing
End Sub 'LoadTreeView
First of all Root elements (ParentID = NULL
) are identified, added to the tree and then the function RecursivelyLoadTree
is called to recursively create child elements:
Private Sub RecursivelyLoadTree(ByVal oDataRow As DataRow, _
ByRef oNode As TreeNode)
Dim oChildRow As DataRow
'returns an array of DataRow objects representing the child view
For Each oChildRow In oDataRow.GetChildRows("SelfRefenceRelation")
'Create child node and add to Parent
Dim oChildNode As New TreeNode()
oChildNode.Text = oChildRow(DataTextField).ToString()
oChildNode.Value = oChildRow(DataFieldID).ToString()
oChildNode.NavigateUrl = _
oChildRow("NavigateURL").ToString()
oNode.ChildNodes.Add(oChildNode)
'Repeat for each child
RecursivelyLoadTree(oChildRow, oChildNode)
Next oChildRow
End Sub 'RecursivelyLoadTree
Using the code
The easiest way to use the control is to either bind it to a Data Source control (DataSourceControl.aspx):
<%@ Register TagPrefix="CPArticles" Namespace="CPArticles"%>
<CPArticles:AutoBindingTree runat="server" ID="TestCtrl"
DataTextField="Text"
DataFieldID="ID"
DataFieldParentID="ParentID"
DataSourceID="SqlDataSource1"
/>
<asp:SqlDataSource id="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString %>"
SelectCommand="SELECT * FROM SelfReferenceTable"
SelectCommandType="Text"
/>
or by programmatically setting the DataSource
property(DataBind.aspx):
TestCtrl.DataFieldID = "ID"
TestCtrl.DataFieldParentID = "ParentID"
TestCtrl.DataTextField = "Text"
TestCtrl.DataSource = oDs
TestCtrl.DataBind()
Both samples and the SQL Script are in the demo application.
History
- April 15, 2007: Initial release.