Mathias Brandewinder on .NET, F#, VSTO and Excel development, and quantitative analysis / machine learning.
by Mathias 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"/>
    <div class="MainMenuSection">
        <asp:Menu ID="MainMenu" runat="server" DataSourceID="SiteMapMain"
        MaximumDynamicDisplayLevels="0" Orientation="Horizontal">
        </asp:Menu>
    </div>
               
    <asp:SiteMapDataSource ID="SiteMapSecondLevel" runat="server" 
    showStartingNode="False" 
    StartingNodeOffset="1"/>
    <div class="SecondaryMenuSection">
        <asp:Menu ID="SecondaryMenu" runat="server" 
        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.

Comments

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

terry

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.

terry Costa Rica | Reply

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

swetha

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?

swetha United States | Reply

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

Mathias

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

Mathias United States | Reply

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

Ana

Nice!

Ana United States | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



Comments

Comment RSS