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

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube