Hierarchical data in tree view in .NET using recursive function

Background

Showing hierarchical data on a page was always a pain. Mostly we use “TreeView” control or “GridView” control to show the hierarchical data. In order to do that we have to write a logic which can go to n level dipper to find the parent child relationship.

Problem

In order to achieve this we can’t use normal control like TreeView or DataGrid. We have to write a logic to achieve this. Even if we try with simple loop logic still it will be for fixed depth and tomorrow if you change the depth limit then logic has to be changed. As a developer we have to write a code which should be generic and will work in almost all cases.

Solution

In order to achieve this we have to use recursive function which can dive dipper and dipper to nth level depth of parent child relationship. Recursive function is nothing but a function which is calling or referencing itself.

Example

To demonstrate the same we are using a custom recursive class which has properties defining who is parent and who is child. In order to do that open Visual Studio 2010/2008 (I am using 2010)

Create a new Windows Form Application project

New project

New project

Drag a tree view control from Toolbox panel on form and set some properties as this

TreeView Properties

TreeView Properties

Then write the following code after MainForm class completes

/// <summary>
/// Custom class for saving node's key-value pair and attributes
/// </summary>
public class NodeClass
{
    public int ID { get; set; }
    public string Value { get; set; }
    public string Name { get; set; }
    public List<NodeClass> Attributes { get; set; }
    public int ParentNodeID { get; set; }
}

This is a custom class named “NodeClass” for binding hierarchical data to tree view control with generic list of itself as one of its property’s data type.

Once this class is created we have to define generic list of this class (lstNodes, lstTemp) for querying and adding nodes to TreeView. Define lstNodes and lstTemp generic list of this custom class in our windows form’s class.

In constructor of MainForm class firstly we have to fill this generic list with some sample data, so calling LoadDataInList() method to do the same. Then as a good practice clearing all tree view items and creating root node. Then querying for child nodes and persisting that data in lstTemp (generic list of custom class). At finally calling our main recursive function with filtered list(lstTemp), tree view node and level as its arguments/parameters.

Following is the code which will clear what I am talking about

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace HierarchicalDataInTreeView
{
    public partial class MainForm : Form
    {
        List<NodeClass> lstNodes = new List<NodeClass>();
        List<NodeClass> lstTemp;

        public MainForm()
        {
            InitializeComponent();
            LoadDataInList();
            treeView1.Nodes.Clear();
            TreeNode tNode = new TreeNode();
            tNode = treeView1.Nodes.Add(lstNodes[0].Name);
            lstTemp = lstNodes.Where(p => p.ParentNodeID == lstNodes[0].ID).ToList();
            AddDataToTreeView(lstTemp, tNode, 0);
            treeView1.ExpandAll();
        }

        private void LoadDataInList()
        {
            lstNodes = new List<NodeClass>()
                           {
                               new NodeClass(){ ID = 0, Name = "Data", ParentNodeID = -1 },
                               new NodeClass(){ ID = 1, Name = "Fruit", ParentNodeID = 0 },
                               new NodeClass(){ ID = 2, Name = "Apple", ParentNodeID = 1 },
                               new NodeClass(){ ID = 3, Name = "Orange", ParentNodeID = 1 },
                               new NodeClass(){ ID = 4, Name = "Grapes", ParentNodeID = 1 },
                               new NodeClass(){ ID = 5, Name = "Banana", ParentNodeID = 1 },
                               new NodeClass(){ ID = 6, Name = "Vegetables", ParentNodeID = 0 },
                               new NodeClass(){ ID = 7, Name = "Cauliflower", ParentNodeID = 6 },
                               new NodeClass(){ ID = 8, Name = "Carrot", ParentNodeID = 6 },
                               new NodeClass(){ ID = 9, Name = "Chili", ParentNodeID = 6 },
                               new NodeClass(){ ID = 10, Name = "Cucumber", ParentNodeID = 6 }
                           };
        }

        private void AddDataToTreeView(List<NodeClass> iEnumerable, TreeNode t, int level)
        {
            foreach (NodeClass c in iEnumerable)
            {
                TreeNode treenode;
                treenode = t.Nodes.Add(c.Name);
                treeView1.Update();
                lstTemp = lstNodes.Where(p => p.ParentNodeID == c.ID).ToList();
                AddDataToTreeView(lstTemp, treenode, level + 1);
            }
        }
    }

    /// <summary>
    /// Custom class for saving node's key-value pair and attributes
    /// </summary>
    public class NodeClass
    {
        public int ID { get; set; }
        public string Value { get; set; }
        public string Name { get; set; }
        public List<NodeClass> Attributes { get; set; }
        public int ParentNodeID { get; set; }
    }
}

And at last our desired output

Output

Output

Also using the same logic you can make more complex parent child relationship to view data. You can also fill this generic list with data from your database or any other source.

Posted in ASP.NET, Programming Language, XML Tagged with: , ,
  • Fazz

    I have good news and bad news, good news is, that the beginning of this article isn’t bad. The bad news is, that damn Twitter bird flying around crap was so annoying that after about 2 minutes of reading I went straight to the bottom to make this comment, and will immediately there after leave this blog to never return.

    Get rid of the damn animated, flying around, twitter bird thing!