Mathias Brandewinder on .NET, F#, VSTO and Excel development, and quantitative analysis / machine learning.
6. November 2009 15:48

When I decided to have a 2-level horizontal menu for my professional webpage in ASP.NET, it came as a surprise to me that this wasn’t completely straightforward. I expected the standard  ASP menu control to support this, but found out that this wasn’t the case.

Fortunately, I came across a post by Peter Kellner, describing how he implemented that for the Silicon Valley Code Camp website, which was pretty much what I envisioned.

The one issue I had with his implementation, however, was that the second level menu uses multiple data sources. The Master Page handles the top-level menu, but each page contains a reference to the specific datasource used to populate the sub-menu. As a result, if you decide to add a page, you need to manually add to that page some code to define what sub-menu should show up, which is cumbersome.

The ideal solution for a lazy developer like me would be to have all the menus handled in the Master Page, so that when you add a new page to your website, you just need to add it to the Sitemap, and the right menu and sub-menu shows up.

After some tinkering about, I figured out how to get this done. The trick is to use the Attribute StartingNodeOffset of the SiteMapDataSource.

I used the CSSFriendlyModified.dll Peter presents in his code sample, but modified the MasterPage, which looks like this:

<div id="Navigation">
<asp:SiteMapDataSource ID="SiteMapMain" runat="server"
showStartingNode="False"/>
MaximumDynamicDisplayLevels="0" Orientation="Horizontal">
</div>

<asp:SiteMapDataSource ID="SiteMapSecondLevel" runat="server"
showStartingNode="False"
StartingNodeOffset="1"/>
DataSourceID="SiteMapSecondLevel"
Orientation="Horizontal" />
</div>
</div>

The first block (SiteMapMain and MainMenu) declare what DataSource to use for the top-level menu (the SiteMap), and is pretty much identical to Peter’s code.

The second block declares a second DataSource (SiteMapSecondLevel), which hooks up to the SiteMap. Note the difference with the first DataSource: StartingNodeOffset is set to 1, which essentially tells the DataSource to look one level down in the nodes hierarchy of the SiteMap. The sub-menu “SecondaryMenu” simply uses that DataSource, regardless of the page.

As a result, now there is no need to add any code for pages to handle the second level menu. As long as a page is listed in the SiteMap, and hooked to the MasterPage, it will automatically populate the second level menu with the nodes that are listed under the top-level node. You can see that in action on this page, for instance. Enjoy!

And, give credit where credit is due - thanks a million for Peter Kellner – his code was a total life-saver.

2/28/2010 1:22:31 AM #

is there an easy way in your example page to highlight the selected page link in the secondary menu? In other words, when I click on "feedback" there is no indication in the menu that I'm on the feedback page.

8/11/2010 1:21:16 AM #

I tried to implement it without using css friendly adapters and it works fine except for the roles.Could you confirm if this method works fine to assign membership roles?

9/4/2010 6:05:00 AM #

Swetha,
I wish I had an answer for you, but ASP.NET isn't quite my strong point, and I honestly don't know. Best of luck!
Mathias

2/9/2012 5:22:27 PM #

Nice!

• Comment
• Preview

#### Need help with F#?

The premier team for
F# training & consulting.