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 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 object.

private void populateTree(List categories, ref TreeNode tn)
{
    int currentId = int.Parse(tn.Value);
    TreeNode tnAdd = null;
    // Obtain all categories that are children to the parentId
    List 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.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.