Click here to Skip to main content
15,867,308 members
Articles / Web Development / ASP.NET
Article

Auto Binding a TreeView control from a self referencing table

Rate me:
Please Sign up or sign in to vote.
4.57/5 (15 votes)
16 Apr 2007CPOL2 min read 116.2K   1.4K   65   24
A Custom TreeView Control that supports auto binding from a single self referencing table
Screenshot - AutoBindingTreeView.gif

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:

Self Referencing table

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:

  1. DataTextField: The name of the column holding the Node Text Value
  2. DataFieldID: The name of the Column holding the ID value
  3. DataFieldParentID: The name of the Column holding the ParentID value
VB.NET
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:

VB.NET
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:

VB.NET
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):

XML
<%@ 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):

VB.NET
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Delcan Corporation
United States United States
Bassam Saoud is a software developer with more then 6+ years of experience. He has masters in Computer Science from American University of Technology and is currently doing Masters in Business Administration at Colorado Heights University. He started Programming with C++ and VB and now working with ASP.NET VB.NET/C#, SQL Server 2000/2005.

His interests are mainly politics, Basketball and Traveling.

Comments and Discussions

 
QuestionOnSelectedNodeChanged Pin
kerm795-Apr-11 0:16
kerm795-Apr-11 0:16 
AnswerRe: OnSelectedNodeChanged Pin
ahussiny24-Mar-12 3:05
ahussiny24-Mar-12 3:05 
GeneralIs there any way to save this to xml? [modified] Pin
Kaeghl29-Jan-09 7:25
Kaeghl29-Jan-09 7:25 
GeneralGenerating Treeview from datatable Pin
amitabha200712-Jan-09 22:31
amitabha200712-Jan-09 22:31 
QuestionTreeView From Datatable Pin
amitabha200712-Jan-09 22:29
amitabha200712-Jan-09 22:29 
GeneralYou can achieve this with one line of code Pin
Ralph Varjabedian23-Apr-08 1:15
Ralph Varjabedian23-Apr-08 1:15 
GeneralRe: You can achieve this with one line of code Pin
Bassam Saoud28-Jul-08 4:44
Bassam Saoud28-Jul-08 4:44 
I am looking at the source code of HierarchicalDataSet class. Thats not exactly one line of code now is it Smile | :)

But the solution implemented is cool. Thanks for sharing your code with us.
GeneralRe: You can achieve this with one line of code Pin
Ralph Varjabedian28-Jul-08 5:14
Ralph Varjabedian28-Jul-08 5:14 
GeneralRe: You can achieve this with one line of code Pin
Bassam Saoud28-Jul-08 5:17
Bassam Saoud28-Jul-08 5:17 
GeneralRe: You can achieve this with one line of code Pin
Ralph Varjabedian29-Jul-08 0:02
Ralph Varjabedian29-Jul-08 0:02 
GeneralExcellent stuff Pin
geckex3-Feb-08 13:12
geckex3-Feb-08 13:12 
GeneralRe: Excellent stuff Pin
Bassam Saoud4-Feb-08 3:56
Bassam Saoud4-Feb-08 3:56 
QuestionHow to extend a TreeView Control with this binding and what you've done in your other article? Pin
AnksuNico20-Nov-07 8:24
AnksuNico20-Nov-07 8:24 
AnswerRe: How to extend a TreeView Control with this binding and what you've done in your other article? Pin
Bassam Saoud20-Nov-07 8:33
Bassam Saoud20-Nov-07 8:33 
GeneralI want to set First of all Root elements (ParentID = 0),how edit the code [modified] Pin
maseccc9-Sep-07 23:24
maseccc9-Sep-07 23:24 
GeneralRe: I want to set First of all Root elements (ParentID = 0),who to edit the code Pin
Bassam Saoud10-Sep-07 4:41
Bassam Saoud10-Sep-07 4:41 
GeneralRe: I want to set First of all Root elements (ParentID = 0),who to edit the code [modified] Pin
maseccc10-Sep-07 16:21
maseccc10-Sep-07 16:21 
GeneralRe: I want to set First of all Root elements (ParentID = 0),who to edit the code [modified] Pin
AnksuNico20-Nov-07 6:33
AnksuNico20-Nov-07 6:33 
Questionsource code and database Pin
cedey5-Aug-07 19:14
cedey5-Aug-07 19:14 
AnswerRe: source code and database Pin
Bassam Saoud6-Aug-07 1:13
Bassam Saoud6-Aug-07 1:13 
GeneralCreate Tag "Target" Pin
Godinho Ferreira16-Apr-07 13:08
Godinho Ferreira16-Apr-07 13:08 
GeneralCreat Target Pin
Godinho Ferreira16-Apr-07 13:06
Godinho Ferreira16-Apr-07 13:06 
GeneralRe: Creat Target Pin
Jeff Circeo19-Apr-07 7:56
Jeff Circeo19-Apr-07 7:56 
GeneralRe: Creat Target Pin
tomot15-Oct-07 1:22
tomot15-Oct-07 1:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.