A tree structure is a way of representing the hierarchical nature of a structure in a graphical form. ASP.NET provides tree control to represent hierarchy structure,
but this is very basic control and do not have capability to show in graphical manner. It’s very easy to understand the relationships between nodes at one glance.
This article provides detail on how to create tree structure. I have created sample code that you can either use as-is or customized as per your need.
The tree structure is created with basic HTML Table and Div controls with basic styles, hence supported by all the browsers. HTML table cells hold the node name and the lines
to show node relationship. These lines are basically created with DIV tags. Line width is calculated on the bases of its child node.
My data reside in SQL server and used SQL queries to fetch the data. Below table has sample data to create tree structure. In this example column ID has unique values and column
PID (Parent ID ) has relationship with ID column. Column Name is self explanatory that is node name in tree.
Below is table structure used to create Hierarchical structure.
ID |
Name |
PID |
1 |
Commissioner |
0 |
2 |
Chief Account Officer |
1 |
4 |
Additional Commissioner |
1 |
6 |
Administrative Officer |
1 |
7 |
Estate Officer |
1 |
8 |
Account Officer |
2 |
9 |
Account Head |
2 |
10 |
Deputy Commissioner1 |
4 |
11 |
Deputy Commissioner 2 |
4 |
12 |
Drug Division |
10 |
13 |
Project Division |
10 |
14 |
Capital Project |
10 |
16 |
Korba project |
11 |
17 |
Admin project |
11 |
18 |
Officer1 |
9 |
19 |
Officer 2 |
9 |
Column Descriptions:
ID: Represent unique id for each node in tree.
Name: Name of the node
PID: Parent ID of Node ( This is relation with ID column).
Every Tree has only one parent node and in my example parent node has PID value as zero.
Code Detail
How to Use
Step 1: Add below style and DIV tag you aspx page . These style are used while rendering the tree in browser.
Style used for hierarchy structure in ASPX page
<style type="text/css">
.vertical
{ position:relative;
width: 2px;
height: 25px;
left:50%;
background-color: #000000;
}
table
{
vertical-align:top;
text-align:center;
border-collapse: collapse;
}
table td { border:0; vertical-align:top; text-align:center; word-wrap: break-word;
}
</
ASPX page code - Div will hold the tree structure.
//
<body>
<form id="form1" runat="server">
<div id="abc" runat="server"></div>
</form>
</body>
Step 2: Add below code in ASPX page cs file. The first line of
Page_load
function create the instance of the “OrgTree” class and the second line
of the code call the “CreateTreeHtml()
” function to generate the application.
protected void Page_Load(object sender, EventArgs e)
{
OrgTree orgTree = new OrgTree();
//Assing output of the CreateTreeHtml function to Div
abc.InnerHtml = orgTree.CreateTreeHtml();
}
Step 3: Add Class “OrgTree” in your project and modify the connection string to point it to your database. Change the table name if required.
You will find more detail about this class in next section.
Run your application and you will find the tree structure on your screen.
How it works Core Functionality
The class “OrgTree” contains the core logic to create a tree structure.
This class contain create two mail function and rest four function are helper to create tree. I will explain each function in detail in subsequent sections.
1. CreateTreeHtml: This is public function and expose to outer world to create tree structure. This function internally calls another function
CreateLevelNode
which take the input as ID of parent node in tree. In this example I have passes value as 1 because in my example parent node id is one.
public string CreateTreeHtml()
{
return CreateLevelNode(1);
}
2. CreateLevelNode : This is core function that return the HTML string of hierarchy structure. This function is called recursively to create entire tree structure.
In the first step it create parent node and then create child node. Each child node again calls this function to create its child node. This process goes continuously until
all the leaf nodes are get created. Basic logic is creating table with number of columns equal to child nodes. One extra table row is created in each table to draw horizontal line.
This horizontal line is nothing but a DIV tag in HTML having height as 1 pixel, when this DIV is rendered in the browser it appears just as a single line.
Same way for each node creates a vertical line down to each parent node and again this vertical line is DIV tag having width 1 pixel.
private string CreateLevelNode(int PID)
{
string finalHdiv;
StringBuilder sbmainTbl = new StringBuilder();
DataTable dtparent = GetParentNodeDetails(PID);
int leafNodeCount = GetLeafNodeCount(PID);
if (leafNodeCount == 0)
leafNodeCount = 1; int tdWidth = 100 / leafNodeCount;
int tdWidthDiff = 100 - leafNodeCount * tdWidth;
sbmainTbl.AppendFormat("{0}", tabletag);
sbmainTbl.AppendFormat("<tr><td>{0}</td></tr>",
CellText(dtparent.Rows[0]["Name"].ToString()));
DataTable dt = GetChildNodeDetails(int.Parse(dtparent.Rows[0]["ID"].ToString()));
int childNodecount = dt.Rows.Count;
if (childNodecount > 1)
{
if (childNodecount > 0)
sbmainTbl.AppendFormat("<tr><td>{0}</td></tr>", VDiv);
if (childNodecount == 0)
finalHdiv = string.Format(HDiv, 0, 0);
else
finalHdiv = HLineWidth(PID); childNodecount, 100 / (2 * childNodecount));
sbmainTbl.AppendFormat("<tr><td>{0}</td></tr>", finalHdiv);
}
sbmainTbl.AppendFormat("<tr><td>");
sbmainTbl.AppendFormat("{0}<tr>", tabletag);
for (int i = 0; i < childNodecount; i++)
{
int leafNodeCountchild = GetLeafNodeCount(int.Parse(dt.Rows[i]["ID"].ToString()));
if (leafNodeCountchild > 0)
sbmainTbl.AppendFormat("<td style=\"width:{0}%\" >{1}</td>",
leafNodeCountchild * tdWidth, VDiv);
else
sbmainTbl.AppendFormat("<td>{1}</td>", VDiv);
}
if (tdWidthDiff > 0)
{
sbmainTbl.AppendFormat("<td style=\"width:{0}%\" ></td>", tdWidthDiff);
}
sbmainTbl.Append("</tr>");
sbmainTbl.Append("<tr>");
for (int i = 0; i < childNodecount; i++)
{
sbmainTbl.AppendFormat("<td>{0}</td>",
CreateLevelNode(int.Parse(dt.Rows[i]["ID"].ToString())));
}
if (tdWidthDiff > 0)
{
sbmainTbl.AppendFormat("<td style=\"width:{0}%\" ></td>", tdWidthDiff);
}
sbmainTbl.Append("</tr></table>");
sbmainTbl.AppendFormat("</td></tr></table>", tabletag);
return sbmainTbl.ToString();
}
3. HLineWidth: This function calculate the width of horizontal line and set the left offset point to draw this line. As number of child node in tree are
not fixed so width of line is calculated based upon the number of child nodes. If child node is one than no need to draw horizontal line and if Node do not have any child then
do nothing. Let’s consider child nodes are three than horizontal line width would be half width of first node + width of second node + half width of last node.
Offset point would be half width of first child node.
private string HLineWidth(int PID)
{
float HlineWidth = 0;
int leafNodeCount = GetLeafNodeCount(PID);
if (leafNodeCount == 0)
leafNodeCount = 1; float tdWidth = 100 / leafNodeCount;
float tdWidthDiff = 100 - tdWidth * leafNodeCount;
DataTable dt = GetChildNodeDetails(PID);
int childNodecount = dt.Rows.Count;
float offset = 0;
for (int i = 0; i < childNodecount; i++)
{
int leafNodeCountchild = GetLeafNodeCount(
int.Parse(dt.Rows[i]["ID"].ToString()));
if (i == 0)
{
offset = leafNodeCountchild * tdWidth / 2;
HlineWidth = HlineWidth + offset;
}
else if (i == (childNodecount - 1))
{
HlineWidth = HlineWidth + leafNodeCountchild * tdWidth / 2;
}
else
{
HlineWidth = HlineWidth + leafNodeCountchild * tdWidth;
}
}
return string.Format(HDiv, HlineWidth , offset);
}
4. CellText : This is very simple function and just add the parent node name inside the DIV tag.This function is intentionally created to provide colors and background
color to node. You can also customize this to create hyperlink or add custom functionality on this node.
private string CellText(string Celltxt)
{
return string.Format("<div style=\"display:block; " +
"word-wrap: break-word; width: 99%;\">{0}</div>", Celltxt);
}
5. GetChildNodeDetails : This function just connect to data base and get the child nodes detail for next level only. You must change the connection string to point
to your DB to get the required data.
private DataTable GetChildNodeDetails(int parentId)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = ConnectionString;
SqlCommand cmd = new SqlCommand(
"select * from tree where pid= " + parentId.ToString(), con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
return ds.Tables[0];
}
6. GetParentNodeDetails : This function just get the current node name and its ID. This ID would be used to get their child node in further calls.
This function return the HTML Hierarchy table.
private DataTable GetParentNodeDetails(int ID)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = ConnectionString;
SqlCommand cmd = new SqlCommand("select * from tree where id= " + ID.ToString(), con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
return ds.Tables[0];
}
7. GetLeafNodeCount: This is last function and just return the leaf level nodes count for parent node.
private int GetLeafNodeCount(int ID)
{
string query = string.Format(@"WITH Node (ID, name,PID)
AS (
SELECT tree.ID, tree.name , tree.PID
FROM tree
WHERE ID ={0}
UNION ALL
SELECT tree.ID, tree.name, tree.PID
FROM tree
INNER JOIN Node
ON tree.PID = Node.ID
)
SELECT ID, name,PID FROM Node
where ID not in (SELECT PID FROM Node)
", ID);
SqlConnection con = new SqlConnection();
con.ConnectionString = ConnectionString;
SqlCommand cmd = new SqlCommand(query, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
return ds.Tables[0].Rows.Count;
}
Class level variables: Below are variables used by above functions:
string tabletag = "<table class =\"tbl\" border=\"0\" " +
"cellpadding=\"0\" cellspacing=\"0\" style=\" " +
"table-layout: fixed; width:100% ;vertical-align:top; text-align:center\" >";
string HDiv = " <div style=\"position:relative; background-color:" +
" #000000;width: {0}%; left:{1}%; height: 2px;\"></div>";
string VDiv = " <div class=\"vertical\"></div>";
String ConnectionString = @"Data Source=.\;Initial Catalog=TestDB;Integrated Security=True";