Ramani Sandeep's Blog

DotNetting – Fast , Easy Way of Developing Applications

Display Hierarchical Data with TreeView in ASP.NET 2.0

Posted by ramanisandeep on April 18, 2009

I’m going to provide a simple example how to display hierarchical data from SQL Server database in the TreeView. A requirement is that the implementation should not be dependant on the hierarchy level in the database. It means that the TreeView implementation should be capable of displaying data from any level, no matter how deep.

Listing #1 : TreeviewEx.aspx

<asp:treeview id="tvCategoryList" runat="server" imageset="BulletedList3" width="100%"

    showexpandcollapse="True" nodewrap="True" ontreenodepopulate="tvCategoryList_TreeNodePopulate"

    expanddepth="2" populatenodesfromclient="False">

    <ParentNodeStyle Font-Bold="True" />

    <RootNodeStyle Font-Bold="True" CssClass="Table_Title_Label_Black12" />

    <HoverNodeStyle Font-Underline="True" ForeColor="#5555DD" />

    <SelectedNodeStyle Font-Underline="True" HorizontalPadding="0px" VerticalPadding="0px" ForeColor="#5555DD" />

    <NodeStyle Font-Names="Verdana" Font-Size="8pt" ForeColor="Black" HorizontalPadding="0px" NodeSpacing="0px" VerticalPadding="0px" />

</asp:treeview>

Next, we start looking at the code in the TreeviewEx.aspx,cs file. We want to populate the root level. Here’s the code.

Listing #2

protected void Page_Load(object sender, EventArgs e) 

{

    if (!IsPostBack) 

    {

        PopulateRootLevel();

    } 

}

This happens by connecting to the database, querying the first set of nodes (having null as the parent id), and creating TreeNode objects with the PopulateNodes routine, which follows next.



Listing #3

private void PopulateRootLevel() 

{ 

    DataTable dt = BAL_Category.GetParentCategory();// Get Parent CategoryList From Database 

    PopulateNodes(dt, tvCategoryList.Nodes); 

}

Next, we want to create the routine to populate the child nodes of a given node. This happens with the PopulateSubLevel method.

Listing #4

private void PopulateSubLevel(int parentid, TreeNode parentNode) 

{ 

    // Get CategoryList by ParentID From Database 

    DataTable dt = BAL_Category.GetChildCategory(parentid);       

    PopulateNodes(dt, parentNode.ChildNodes); 

}

Here, the idea is the same as with the root level, but with the distinction that only child nodes of the given node are queried and populated with the PopulateNodes method (described earlier). The trick to triggering the populating of the child nodes is as follows.



Listing #5

protected void tvCategoryList_TreeNodePopulate(object sender, TreeNodeEventArgs e) 

{ 

    PopulateSubLevel(Int32.Parse(e.Node.Value), e.Node); 

}

TreeNodePopulate is raised for a TreeNode which is expanded by the user for the first time. Due to PopulateNodesFromClient (TreeView) and PopulateOnDemand (TreeNode) settings, this happens with the client-side callback mechanism which is handled by the ASP.NET Page framework. This means that populating does not involve a postback. And, due to better cross-browser support in ASP.NET 2.0, this also works for other browsers such as Firefox. Note that clicking on the node does cause a postback because I haven’t modified the select action of the populated tree nodes from the defaults.

Listing #6

private void PopulateNodes(DataTable dt, TreeNodeCollection nodes) 

{ 

    foreach (DataRow dr in dt.Rows) 

    { 

        TreeNode tn = new TreeNode(); 

        tn.Text = dr["Category"].ToString(); 

        tn.Value = dr["CategoryID"].ToString();

        int NoofChild = Convert.ToInt32(dr["childnodecount"].ToString());

        if (NoofChild != 0 ) 

        { 

            tn.PopulateOnDemand = true; 

            tn.SelectAction = TreeNodeSelectAction.None; 

        } 

        else 

        { 

            tn.PopulateOnDemand = false; 

            if (dr["TotalDoc"].ToString().Equals("0") == false) 

            { 

                tn.NavigateUrl = "~/CategoryWiseProductList.aspx?ID=" + dr["CategoryID"].ToString(); 

                tn.Text = tn.Text + " (" + dr["TotalProduct"].ToString() + ")"; 

            } 

            else 

            { 

                tn.NavigateUrl = "javascript:alert('Product is not Available Under this Category.')"; 

            } 

        }

        nodes.Add(tn);

    } 

}

Hope this will Help you !!!

9 Responses to “Display Hierarchical Data with TreeView in ASP.NET 2.0”

  1. Aneesh said

    hi , can you post the sample code here please?

    • ramanisandeep said

      hi aneesh, i have already explained the example with code & i have also stated all the things that are required but still if u need any clarification than please specify at which area you got problem so that i can give solution regarding that.

      • Aneesh said

        Thanks Sandeep.

        Let me explain you mu issue. I have a project where users can subscribe to specific subjects so that the application can send newsletters to them on that specific subject.

        So I have to make an userinterface as simple as possible but displaying all the categories and its n level subcategories.

        After some R&D i believe Tree view is the only way ahead.[Please guide me If i am wrong].

        I asked you the entire sample because

        1) I wanted to know how the styles and skins will work Treeview which needed the CSS you have used.

        2) I wantd to know the definition for

        BAL_Category.GetChildCategory(parentid); and
        BAL_Category.GetChildCategory(parentid);

        since I would like to see the SQL queries used .

        3) I am interested to see how the database table is designed and how the relation is set.

        Thanks for your Time!

      • ramanisandeep said

        Hi Aneesh ,

        1 ) Css :

        .Table_Title_Label_Black12
        {
        font-size: 10pt;
        font-family: ‘Verdana’;
        color: Black;
        font-weight: bold;

        text-decoration: none;
        }

        2 )

        BAL_LegalDocList.GetParentCategory() & BAL_Category.GetChildCategory(parentid)
        ——————————————————————————-

        using System;
        using System.Data.Common;
        using System.Data;

        public class BAL_LegalDocList
        {
        public BAL_LegalDocList()
        {

        }

        public static DataTable GetParentCategory()
        {
        // get a configured DbCommand object
        GenericDataAccess gda = new GenericDataAccess();

        DbCommand comm = gda.CreateCommand();

        // set the stored procedure name
        comm.CommandText = “GetParentCategory”;

        // return the result table
        DataTable table = gda.ExecuteSelectCommand(comm);
        return table;
        }
        public static DataTable GetChildCategory(int ParentID)
        {
        // get a configured DbCommand object
        GenericDataAccess gda = new GenericDataAccess();

        DbCommand comm = gda.CreateCommand();

        // set the stored procedure name
        comm.CommandText = “GetChildCategory”;

        // create a new parameter
        DbParameter param = comm.CreateParameter();
        param.ParameterName = “@ParentID”;
        param.Value = ParentID;
        param.DbType = DbType.Int32;
        comm.Parameters.Add(param);

        // return the result table
        DataTable table = gda.ExecuteSelectCommand(comm);
        return table;
        }

        }

        3 ) Database :
        ———————-

        Stored Procedure 1:
        ——————-

        CREATE PROCEDURE [dbo].[GetParentCategory]

        AS
        BEGIN
        SELECT
        CategoryID,
        Category,
        (SELECT count(*) FROM Category WHERE ParentID=C.CategoryID AND SoftStatus=1) as childnodecount ,
        (SELECT count(*) FROM LegalDocument WHERE CategoryID = C.CategoryID AND Status=0) as TotalDoc
        FROM
        Category C
        WHERE
        ParentID =0 AND
        SoftStatus = 1
        ORDER BY Category
        END

        Stored Procedure 2:
        ——————–

        CREATE PROCEDURE [dbo].[GetChildCategory]
        @ParentID int
        AS
        BEGIN
        SELECT
        CategoryID,
        Category,
        (SELECT count(*) FROM Category WHERE ParentID=C.CategoryID AND SoftStatus=1) as childnodecount ,
        (SELECT count(*) FROM LegalDocument WHERE CategoryID = C.CategoryID AND Status=0) as TotalDoc
        FROM
        Category C
        WHERE
        ParentID = @ParentID AND
        SoftStatus=1
        ORDER BY Category
        END

        Table :
        ————

        CREATE TABLE [dbo].[Category](
        [CategoryID] [int] IDENTITY(1,1) NOT NULL,
        [Category] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
        [ParentID] [int] NULL,
        [SoftStatus] [bit] NULL,
        CONSTRAINT [PK_Category_1] PRIMARY KEY CLUSTERED
        (
        [CategoryID] ASC
        )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
        ) ON [PRIMARY]

        Hope this will help you

  2. Aneesh said

    Hi , Sandeep

    Thank you very much for your help.
    I really appreciate your gesture and the time you spent to do this.

    Thank you very much !

  3. Aneesh said

    Hi ,

    I could successfully populate treeview from database. i have added checkboxes to all the nodes so that user can select and unselect.Those values is updated on the DB , using

    TreeNodeCollection checkedNodes = TreeView1.CheckedNodes;

    This make sure the DB is updated with the values selected by users.
    But when I repopulate the tree view for the second time how can we show the checkboxes with CHECKED state those have selected by the user already?

  4. Aneesh said

    Well , I could solve it.
    The code used to given below.Hope this helps someone who reaches Mr.Sandeep`s post till this end.

    We need to call this function twice.
    First) after populating the Main categories Second) After populating the Sublevels.

    private void DisplaySelected(TreeNodeCollection treeNodeCollection)
    {
    if (treeNodeCollection == null)
    return;

    foreach (TreeNode tn in treeNodeCollection)
    {
    // Assumes that you have the Userselection as a Arraylist here which was stored in a / //ViewState during PageLoad.

    ArrayList categoryList=(ArrayList) ViewState["categories"];
    if (categoryList.Contains(tn.Text))
    {
    tn.Checked=true;

    }

    }
    }

    THAnks again Sandeep…

  5. wiki said

    was very helpful!

    Thanks!

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>