Recursively populating a TreeView controls TreeNode collection

Every now and then you come across a scenario where a Treeview control is the best solution for presenting a hierarchical view of data.  How do you populate the tree?  A recursive routine is what you are looking for perhaps (at least, I haven't run into any other tree scenario where a recursive routine was not used). 

A recursive routine is a routine that will call itself over and over, until the end of whatever

// Create a top-level node to start things off
TreeNode tn = new TreeNode("Content Categories","0");
// Pass the new node by reference, nodes will be added as children
populateTree(cats, ref tn);
// Add the nodes to the tree
this.tvCategories.Nodes.Add(tn);
this.tvCategories.DataBind();

We start off by creating a TreeNode object.  This node will be the root of the tree, and all other nodes will be under this node. The above code will then call the routine populateTree routine and provide a List<T> of custom category objects.  Don't be disturbed by the 'cats', they are just simple model objects, and we pass the new TreeNode object in as a reference object.

When the populateTree routine ends, our tn variable will contain all the children it found in the generic cats List<T> object.

private void populateTree(List<Category> categories, ref TreeNode tn)
{
    int currentId = int.Parse(tn.Value);
    TreeNode tnAdd = null;
    // Obtain all categories that are children to the parentId
    List<Category> childCats = categories.FindAll(
    delegate(Category cat)
    {
        return cat.ParentId == currentId;
    });
    // Iterate through our subset of nodes that are children
    // of the provided tn node
    foreach (Category c in childCats)
    {
        // Create a new node to add
        tnAdd = new TreeNode(c.Name, c.CategoryId.ToString());
        tnAdd.ToolTip = c.Description;
        // Check for children of the new node
        populateTree(categories, ref tnAdd);
        if (tnAdd != null)
            // Add the child to the node collection
            tn.ChildNodes.Add(tnAdd);
    }
}



The populateTree routine begins by grabbing the current id value off the provided node.  Keeping in mind that this routine calls itself, grabbing the id tells us the node to apply the children nodes we are about to create.  The code continues by defining a null TreeNode object as well.

The first thing we are going to do is find any children within our data source.  I chose to use an anonymous delegate to make that determination in conjunction with the Generic List<T>.FindAll method.  This basically says that I want to find all categories in my datasource whose parentId matches the currentId I'm currently trying to populate with child nodes.  Every true match made adds the category object into the childCats variable.

Now that we have a collection of child objects that we need to create node object from, we begin an interation through each of these identified category objects.  We can now create a TreeNode object for the category, give it a tooltip if we want or whatever other properties we want to assign, but before we add it to the tree, or to its parent node, we are going to call the populateTree routine once again, but this time we will pass in the newly created TreeNode object.  By calling the routine recursively like this, we allow the application to provide a tree with unlimited node levels (should we actually want that, performance and usability will negate the use of unlimited node levels though, so add proper controls to that effect where necessary).

When the recursive call returns from the populateTree call, the tnAdd variable will or will not contain any child nodes.  We really don't care, becuase we know we have at least one node to add to the tree, right?  Ensure we don't have a null object, and if not, add the node to the childnodes collection of the original tree node.

Here's an alternative version that populates the tree with folders under a defined starting folder.

private void loadTree()
{
    // Create a top-level node to start things off
    TreeNode tn = new TreeNode("Downloads", "0");

    // Pass the new node by reference, nodes will be added as children
    populateTree(Server.MapPath(@"~/secure/Downloads"), ref tn);

    // Add the nodes to the tree
    this.tvFolders.Nodes.Add(tn);
    this.tvFolders.DataBind();

}
private void populateTree(string startingPath, ref TreeNode tn)
{
    TreeNode tnAdd = null;

    // Obtain all subfolders
    DirectoryInfo di = new DirectoryInfo(startingPath);
    DirectoryInfo[] dirs = di.GetDirectories("*", SearchOption.TopDirectoryOnly);

    foreach (DirectoryInfo dis in dirs)
    {
        // Create a new node to add
        tnAdd = new TreeNode(dis.Name, dis.Name);

        // Check for children of the new node
        populateTree(dis.FullName, ref tnAdd);

        if (tnAdd != null)
            // Add the child to the node collection
            tn.ChildNodes.Add(tnAdd);
    }
}

The recursive routine is powerful, and this format makes it easy to adapt to various scenarios.  For instance, this folder recursion routine was simply copied from the above snippet and redone to work with a folder structure.  If I have the need at some point to include files in the tree, then I'll update this post with it.  Or, if someone needs that, I'd be happy to work it up and provide it.

permalink Permalink or Trackback Comment Comments (1) Cat C#
Technorati: No reaction yet!
Tags: , , , ,
Actions: E-mail

Was this helpful?

If you liked this or found it helpful, please digg it, stumble it, buzz it, whatever it, to say thank you.





Add to Technorati Favorites

 
 If you would like to receive these posts as they happen, you can subscribe to my feed or receive my posts in your email.

Related Posts

Comments

  1. pingback
    successpart2.com Says:


    Pingback from successpart2.com

    a make money blogging carnival - November 21, 2008 : SuccessPart2.Com

Add comment



(Will show your Gravatar icon)  

biuquote
  • Comment
  • Preview
Loading



Check it out mango: Any links must be entered as http://www.somewhere.com with nothing touching it. Anything else will be mangled. This is to help combat spam and to also ensure the masses know of this little tidbit before they click Save comment below. :) I have this down to remind me to do something with it, but I take things slow and easy on the old horse.

Keeps her regular don't ya know, and I wouldn't want to disturb that.



CSS Template by RamblingSoul | Illinois Wine. Adapted to BlogEngine by Wayne John
EatonWeb Blog Directory  Blog Directory Blogger Forum: About Blogging for Bloggers DaniWeb - IT Professionals' Lounge Community