Drill down Organization Chart Control

Hi Guys,

This time I made a ASP.NET Control to generate a Drill down Organization Chart. Hope you like it.

This is the initial view of the Organization Chart.


















Once you click on any of the sub nodes it will drill down and show the hierarchy.





1) OrgnizationChartControl.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

/// <summary>
/// Summary description for OrganizationChartControl
/// </summary>
public class OrganizationChartControl<T> : Control 
{
    private List<TreeNode> Nodes {get;set;}

    public OrganizationChartControl()
    { }

    public List<T> Items {
        get
        {
            if (ViewState["Items"] == null)
                ViewState["Items"] = new List<object>();
            return (List<T>)ViewState["Items"];
                }
        set { ViewState["Items"] = value; }
    }

    public string ParentColumnID {
        get
        {
           
            return (string)ViewState["ParentColumnID"];
                }
        set { ViewState["ParentColumnID"] = value; }
    }

    public string ValueMember {
        get
        {
           
            return (string)ViewState["ValueMember"];
                }
        set { ViewState["ValueMember"] = value; }
    }

    public string DisplayMember {
        get
        {
           
            return (string)ViewState["DisplayMember"];
                }
        set { ViewState["DisplayMember"] = value; }
    }

    public int TrimCharacter
    {
        get
        {

            return (int)ViewState["TrimCharacter"];
        }
        set { ViewState["TrimCharacter"] = value; }
    }

    private Type type;
    private PropertyInfo parentColumn, valueColumn, displayColumn;
    int p, v , i = 1;
    string text,url;


    protected override void Render(HtmlTextWriter writer)
    {
        if(this.Nodes == null)
            this.Nodes = new List<TreeNode>();

        url = HttpContext.Current.Request.Url.AbsoluteUri;
        if (url.Contains("?"))
        url = url.Substring(0, url.IndexOf("?"));

        try
        {
            if (Items.Count > 0)
            {
               if(Items.Count > 1)
                writer.RenderBeginTag(HtmlTextWriterTag.Ul);

                foreach (T listItem in Items)
                {
                    type = typeof(T);
                    
                        parentColumn = type.GetProperties().Where(r => r.Name == ParentColumnID).FirstOrDefault();
                    
                        valueColumn = type.GetProperties().Where(r => r.Name == ValueMember).FirstOrDefault();
                    
                        displayColumn = type.GetProperties().Where(r => r.Name == DisplayMember).FirstOrDefault();

                    CreateNode(Convert.ToInt32(valueColumn.GetValue(listItem)),
                        Convert.ToInt32(parentColumn.GetValue(listItem)),
                        displayColumn.GetValue(listItem).ToString(),
                        writer);



                }
                if (Items.Count > 1)
                    writer.RenderEndTag();

                              

                writer.RenderEndTag();

                if (HttpContext.Current.Request.Url.AbsoluteUri.Contains("?"))
                {
                    if (Items.Count > 1)
                        writer.RenderEndTag();
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "spanBack");
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.AddAttribute(HtmlTextWriterAttribute.Href, "javascript:window.history.back();");
                   
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    writer.Write("Back");
                    writer.RenderEndTag();
                    writer.RenderEndTag();
                }
                
            }
        }
        catch (Exception ex)
        {
            
            
        }

        base.Render(writer);

       
    }

     private void CreateNode(int id, int parentID, string text,HtmlTextWriter writer)
    {
         if (this.Nodes.Count == 0)
         {
             TreeNode _Node = new TreeNode(text, id.ToString());
             this.Nodes.Add(_Node);
             writer.RenderBeginTag(HtmlTextWriterTag.Li);
             
             writer.RenderBeginTag(HtmlTextWriterTag.A);
             writer.RenderBeginTag(HtmlTextWriterTag.Span);
             writer.Write(text);
             writer.RenderEndTag();
             writer.RenderEndTag();
             writer.RenderBeginTag(HtmlTextWriterTag.Ul);
         }

        

        if (parentID != -1)
        {
            
           foreach (TreeNode _Node in this.Nodes)
            {
                if (_Node.Value == parentID.ToString())
                {
            
                    
                    writer.RenderBeginTag(HtmlTextWriterTag.Li);
                    writer.AddAttribute(HtmlTextWriterAttribute.Href, url + "?pId=" + id);
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.Write(text);
                    writer.RenderEndTag();
                    writer.RenderEndTag();
                    TreeNode childNode = new TreeNode(text, id.ToString());
                    //_Node.ChildNodes.Add(childNode);
                    GetChildNodes(id,parentID, childNode, writer);
                    
                   
                   
                    writer.RenderEndTag();
                    
                    
               }
            }
            
        }
        
    }

     private void GetChildNodes(int id, int parentID, TreeNode node, HtmlTextWriter writer)
    {
       

        try
        {
           
            var filter = Filter<T>(Items, ParentColumnID, id.ToString());
            if (filter.Count > 0)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Ul);
                foreach (T listItem in filter)
                {
                    type = typeof(T);

                    //if (i == 10) break;

                    parentColumn = type.GetProperties().Where(r => r.Name == ParentColumnID).FirstOrDefault();

                    valueColumn = type.GetProperties().Where(r => r.Name == ValueMember).FirstOrDefault();

                    displayColumn = type.GetProperties().Where(r => r.Name == DisplayMember).FirstOrDefault();

                    v = Convert.ToInt32(valueColumn.GetValue(listItem));


                    p = Convert.ToInt32(parentColumn.GetValue(listItem));

                    text = displayColumn.GetValue(listItem).ToString();

                   
                    writer.RenderBeginTag(HtmlTextWriterTag.Li);
                    writer.AddAttribute(HtmlTextWriterAttribute.Href, url + "?pId=" + id);
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.Write(text);
                    writer.RenderEndTag();
                    writer.RenderEndTag();
                    //writer.RenderBeginTag(HtmlTextWriterTag.Ul);
                    TreeNode child = new TreeNode(v.ToString(), p.ToString());
                    
                    node.ChildNodes.Add(child);
                    GetChildNodes(v, id, child, writer);

                    //writer.RenderEndTag();
                    writer.RenderEndTag();
                   


                }
                writer.RenderEndTag();
               
            }
            

        }
        catch (Exception ex)
        {
            
            
        }

        
    }

     private List<T> Filter<T>(
     List<T> collection,
     string property,
     string filterValue)
     {
         var filteredCollection = new List<T>();
         foreach (var item in collection)
         {
             // To check multiple properties use,
             // item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)

             var propertyInfo =
                 item.GetType()
                     .GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
             if (propertyInfo == null)
                 throw new NotSupportedException("property given does not exists");

             string propertyValue = propertyInfo.GetValue(item, null).ToString();
             if (propertyValue == filterValue)
                 filteredCollection.Add(item);
         }

         return filteredCollection;
     }
}

2) OrganizationChartControl.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="OrganizationChartControl.ascx.cs" Inherits="OrganizationChart_OrganizationChartControl" %>


        <div id="dvChart" runat="server" class="tree">
</div>
   





<style>
    /*Now the CSS*/
* {margin: 0; padding: 0;}

    .spanBack {
        position:absolute; bottom:0;  margin-bottom:7px; left: 0;
    }

.tree ul {
padding-top: 20px; position: relative;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

.tree li {
float: left; text-align: center;
list-style-type: none;
position: relative;
padding: 20px 1px 0 1px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;
}

/*We will use ::before and ::after to draw the connectors*/

.tree li::before, .tree li::after{
content: '';
position: absolute; top: 0; right: 50%;
border-top: 1px solid #ccc;
width: 50%; height: 20px;
}
.tree li::after{
right: auto; left: 50%;
border-left: 1px solid #ccc;
}

/*We need to remove left-right connectors from elements without 
any siblings*/
.tree li:only-child::after, .tree li:only-child::before {
display: none;
}

/*Remove space from the top of single children*/
.tree li:only-child{ padding-top: 0;}

/*Remove left connector from first child and 
right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
border: 0 none;
}
/*Adding back the vertical connector to the last nodes*/
.tree li:last-child::before{
border-right: 1px solid #ccc;
border-radius: 0 5px 0 0;
-webkit-border-radius: 0 5px 0 0;
-moz-border-radius: 0 5px 0 0;
}
.tree li:first-child::after{
border-radius: 5px 0 0 0;
-webkit-border-radius: 5px 0 0 0;
-moz-border-radius: 5px 0 0 0;
}

/*Time to add downward connectors from parents*/
.tree ul ul::before{
content: '';
position: absolute; top: 0; left: 50%;
border-left: 1px solid #ccc;
width: 0; height: 20px;
}

.tree li a{
/*border: 1px solid #ccc;
padding: 0px 5px;
text-decoration: none;
color: #666;
font-family: arial, verdana, tahoma;
font-size: 12px;
display: inline-block;
width:50px;
    height:50px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
transition: all 0.5s;
-webkit-transition: all 0.5s;
-moz-transition: all 0.5s;*/
   
}

.tree li a span { width:50px;
    height:30px;  overflow: hidden; left:-5px ;
     color: #666;
    border: 1px solid #ccc;
padding: 0px;
vertical-align:middle;
    text-align: center;
    border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
    font-weight: bold;
    font-family: arial, verdana, tahoma;
font-size: 12px;
display: inline-block;
  width: 100px;
  height: 51px;
  background-repeat: no-repeat;
  background-image:url('/Images/Node.png')

}



</style>

3) OrganizationChartControl.ascx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Data;

public partial class OrganizationChart_OrganizationChartControl : System.Web.UI.UserControl
{
    int parentId = -1;
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            BindData();
        }
    }

    private void BindData()
    {
       

        if(Request.QueryString["pID"] != null)
        {
           parentId = int.Parse(Request.QueryString["pID"]);
        }     

        OrganizationChartControl<OrginationStructure> listcontrol = new OrganizationChartControl<OrginationStructure>();
        listcontrol.Items = parentId == -1 ? LocationDataHelper.GetAllDataAsList() : LocationDataHelper.GetDataAsList(parentId);
        listcontrol.ValueMember = "ID";
        listcontrol.DisplayMember = "Name";
        listcontrol.ParentColumnID = "ParentID";
        

        dvChart.Controls.Add(listcontrol);
    }    
}

4) Data