Practical ASP.NET

Managing Menus

Peter considers two solutions for keeping items in the sitemap off of your Menu or TreeView controls. But he's also wondering if there are more solutions out there.

I was recently asked by one of the participants taking an ASP.NET course with me if there was a way to prevent an item in the sitemap from appearing on the menu but still have it appear on SiteMapPath (the control that gives you a "breadcrumbs-like" description of where a page fits into the site's hierarchy). I never ask why my course participants why they want to do these things... I just assume there's a good reason and try to be helpful as I can. Then I send them my bill.

I could think of at least two solutions to the problem. I'll cover one in this column (working with the menu control) and one in the next column (creating my own menu provider). However, I'm suspicious that there are other, probably simpler, solutions out there that I haven't considered. If you've got one, post it!

A quick review: To add a menu to a page, you first add a Web.sitemap file to your project with an XML description of the menus and submenus you want. Here's the start of a typical sitemap that defines the root for the menu ("Home"), a main menu item ("Management") and the first submenu item on that menu item ("List Customers"):

?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns=
   "http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
 <siteMapNode url="~/Default.aspx" 
              title="Home"  
              description="Northwind CRM home">
    <siteMapNode title="Management" 
                description="Customer Support">
       <siteMapNode url="~/CustomerList.aspx" 
                    title="List Customers"                
                    description="Customers for region"/>

You then drag the control of your choice (a Menu or a TreeView) onto your page and, from its SmartTag, create a SiteMapDataSource that ties your menu control to the sitemap. Typically, you'll put your menu on the Master Page for your site.

To interfere with what goes onto the menu you want to add code to the menu's MenuItemDataBound event. That event's e parameter passes a ton of information that you can use to control what actually gets displayed. The e parameter's Item property, for instance, gives you access to the MenuItem itself which, in term, gives you access to the MenuItem's parent. Once you have a MenuItem's parent, you can remove the item from the parent's ChildItems collection with the collection's Remove method.

To remove each menu item as it's added, for instance, you could use this code which checks to see if a menu item has a parent before trying to remove it:

If e.Item.Parent IsNot Nothing Then
  e.Item.Parent.ChildItems.Remove(e.Item)
End If

This leaves the root menu item ("Home" in my example) still on the screen. So, to complete this process, the final step is to check to see if the menu has any children under its root and set the menu's Visible property to False if it does not. This code, in the Menu's PreRender event will do the job:

If Me.Menu1.Items(0).ChildItems.Count = 0 Then
  Me.Menu1.Visible = False
End If

While a neat trick, this didn't solve my participant's problem: He only wanted some of the items deleted. There are a couple of ways that could be handled. For instance, if we wanted to check an attribute of the SiteMapNode that generated the menu item, I could convert the MenuItem's DataItem property to a SiteMapNode and check its Url property. This example, for instance, eliminates any MenuItem with a URL that contains "Customer":

Dim smn As SiteMapNode
smn = CType(e.Item.DataItem, SiteMapNode)
If smn.Url.Contains("Customer") Then
  e.Item.Parent.ChildItems.Remove(e.Item)
End If

But, for maximum flexibility, I'd like to control this process through some custom attribute that I add to the SiteMapNode in the sitemap. I'd like to be able to add something like this displayInMenu attribute:

<siteMapNode url="~/CustomerList.aspx"
             title="List Customers"
             description="Customers for region"
             displayInMenu="false"/>

Of course, you could also add some security-related attribute or, perhaps, an attribute related to the user's level of expertise (e.g. "novice", "expert").

Fortunately, the SiteMapNode object has an Item collection that is used for nothing else than retrieving custom attributes (you can't use it to retrieve the standard attributes like url, for instance). If the attribute you ask for doesn't exist on the SiteMapNode no error is raised so this code does the job:

Dim smn As SiteMapNode
smn = CType(e.Item.DataItem, SiteMapNode)
If smn.Item("displayInMenu") = "false" Then
  e.Item.Parent.ChildItems.Remove(e.Item)
End If

I only wish I'd thought of this much detail when the question was asked.

Next column: Building your own menu provider.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Microsoft Revamps Fledgling AutoGen Framework for Agentic AI

    Only at v0.4, Microsoft's AutoGen framework for agentic AI -- the hottest new trend in AI development -- has already undergone a complete revamp, going to an asynchronous, event-driven architecture.

  • IDE Irony: Coding Errors Cause 'Critical' Vulnerability in Visual Studio

    In a larger-than-normal Patch Tuesday, Microsoft warned of a "critical" vulnerability in Visual Studio that should be fixed immediately if automatic patching isn't enabled, ironically caused by coding errors.

  • Building Blazor Applications

    A trio of Blazor experts will conduct a full-day workshop for devs to learn everything about the tech a a March developer conference in Las Vegas keynoted by Microsoft execs and featuring many Microsoft devs.

  • Gradient Boosting Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the gradient boosting regression technique, where the goal is to predict a single numeric value. Compared to existing library implementations of gradient boosting regression, a from-scratch implementation allows much easier customization and integration with other .NET systems.

  • Microsoft Execs to Tackle AI and Cloud in Dev Conference Keynotes

    AI unsurprisingly is all over keynotes that Microsoft execs will helm to kick off the Visual Studio Live! developer conference in Las Vegas, March 10-14, which the company described as "a must-attend event."

Subscribe on YouTube