How to expand a TreeView to the current page when using a SiteMapProvider

Posted Wednesday, July 25, 2007 8:59 AM by C-Dog's .NET Tip of the Day

Ok, well I started writing this post yesterday and somehow I accidently closed my browser and lost the entire contents of the post, so here I am at it trying it again. Lately, I have been working with a TreeView to handle hierarchical naviagation. Specifically I have been working with SharePoint's SPTreeView control which inherits from the ASP.NET version and functions roughly the same. One of the biggest flaws I have found in both controls is that when used with a SiteMapProvider, it does not expand thte tree to the level of the current page. I found this highly annoying because the user will never know where they are as they are navigating through the site. After much looking and not finding much, I came up with this solution after seeing an MSDN article that showed how to save the state of which nodes were open as a user navigated through the site.

The code for this is actually pretty simple. I created a method called ExpandTreeToCurrentPage that took a TreeNodeCollection as a parameter. This method will be called recusrively in the OnDataBind event handling method as we move through the tree. Then I just iterate through the TreeNodeCollection and compare the NavigateUrl to the AbsolutePath of the page (you may want to compare something else if you want to include query strings, etc.). If it matches I return true, which forces the recursion to stop. One thing I ran into is that ChildNodes will return a count of 0, unless the current node is expanded first. This makes things a little trickier, but not too bad. I just expand the current node before making a recursive call to the same method passing in the ChildNodes as a parameter. After the recursive calll, I make a call to collapse the current node. Here is what the code looks like.

protected bool ExpandTreeViewToCurrentPage(TreeNodeCollection treeNodes)
{
 // iterate through all nodes to find the current page
 foreach (TreeNode treeNode in treeNodes)
 {
   // check to see if the value matches the current url               
   if (string.Compare(treeNode.NavigateUrl, 
         Page.Request.Url.AbsolutePath, true) == 0)
     {
           // a match has been found so stop looking
           return true;
      }

    // must be called in order to see child nodes 
    treeNode.Expand();

    // recursively call this method to check the children
    if ((treeNode.ChildNodes != null) &&
          (treeNode.ChildNodes.Count > 0))
    {
     if (ExpandTreeViewToCurrentNode(treeNode.ChildNodes))
        return true;
     }

  // collapse any nodes that were opened earlier
  treeNode.Collapse();
   }

// false will be returned if the node was never found
return false;
}

This may not be the best solution, but I have yet to find anything better. I think it is rediculous that this behavior isn't apart of the control by default. Since the MSDN article does something fairly similar, I have a feeling this is as good as it gets. If you have any other ideas, feel free to let me know.

Read the complete post at http://www.dotnettipoftheday.com/blog.aspx?id=377

Filed under: