Multi Level ASP.NET Menu with CSS Friendly Control AdaptersBuilding the New Code Camp Web Site (Part 2)

Posted by Peter Kellner on May 19, 2008 · 15 mins read

Article Series

(Source Code Available in Article 6 Below - (Added March 2009))

Article 1: Best Practices for Building an ASP.NET quality web site
Article 2: Multi Level ASP.NET Menu with CSS Friendly Control Adapters
Article 3: Creating a Theme For Each Year of Code Camp Using Skins in ASP.NET
Article 4: Creating a Modal Login Window Using the Telerik Modal RadWindow Component
Article 5: Using LINQ to Merge Mailing Lists and Filter Opt Outs
Article 6: Multi Level ASP.NET Menu with CSS Friendly Control Adapters (The Source Code!)

 

Introduction

If you have complex styling issues involving ASP.NET we are experts and might be able to help. This technique is fairly old however newer methods could be used for similar results. Contact Peter Kellner and his associates here.

It's often the case that brilliant designers will make interfaces that are hard to implement using standard frameworks like ASP.NET.  As Software engineers striving for consistency, we always want to do the best we can with the standard tool kits to take advantage for built in functionality.  ASP.NET 2.0's built in menu system is a perfect example.  If you use that menu system, you get to make very simple declarative site maps by simply using the ASP.NET 2.0 Site Navigation Features.

The requirement faced today has to do with building the web site for our third annual code camp.  We have that brilliant designer I mentioned above, and he has made a design that just seems too perfect to compromise.  Here are some screen shots of how the designer envisions the sight looking and working after it is completed.

css1 

css2 

css3 

css4 

css5 

Notice the interesting behavior of the top menu (REGISTER;PROGRAM;NEWS;ABOUT AND WIKI).  Unselected, the bottom line strip is the same as selected.  When selected, the background of the selection changes to a different shade of the same color as the bottom strip.

Also notice the interesting behavior of the secondary menu. that is, when ABOUT is selected from the top menu, notice that the secondary menu shows: Contact;Venue;Organizers;Sponsors and Previous.  As you can see above (on the bottom of the 5 pictures), when Venu is selected, it is highlighted to in bright white to indicate that you have selected that.  The really cool part here is that the ABOUT on the primary menu stays highlighted when you choose different  secondary menu choices.

Why Go Through The Trouble, why not just do it with HTML and CSS directly

So, a reasonable person might say that since you can't easily get this behavior with the asp:menu control and the site map provider (OK, at least I couldn't figure it out), why not just code this up with simple list items, button clicks and a pile of code to react to those things?  Well, the answer is you can certainly do that.  The problem is the next time you want to do something similar you will find yourself doing a lot of cut and pasting.  Personally, whenever I find myself cutting and pasting a lot I know I should probably think about how to refactor the code to make it more reusable and therefore more reliable.

What Are the Benefits of Using asp:menu and the site map providers

I mentioned that there are benefits to using the asp:menu and site map providers.  What are those benefits you might ask.  Well, let me first show you what you have to do to set up a simple menu system using these, then list the benefits of what comes out.

The Web.SiteMap

First, you need to create a web.sitemap file in your web directory.  Here is what a simple one looks like similar to what will create the pictures above.

<?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="Silicon Valley CodeCamp 08">

 

            <siteMapNode url="Register.aspx" title="REGISTER"  description="" />

 

            <siteMapNode url="News.aspx" title="NEWS"  description="" />

 

            <siteMapNode url="About.aspx" title="ABOUT"  description="">

 

            <siteMapNode url="Contact.aspx" title="Contact"  description="" />

 

            <siteMapNode url="Sponsors.aspx" title="Sponsors"  description="" />

 

            <siteMapNode url="Previous.aspx" title="Previous"  description="" />

 

         </siteMapNode>

 

      </siteMapNode>

 

   </siteMap>

The Web.Config

You need to declare which sitemap provider you are using. In our case, we are simply reading from a file.  Then, you should (do not have to) declare a section for each web page you want to provide role access to.  Here is an example of my web.config. This first part says give access to any logged in user for Sponsors.aspx

<location path="Sponsors.aspx">

 

    <system.web>

 

        <authorization>

 

            <deny users="?"/>

 

        </authorization>

 

    </system.web>

 

</location>

 

</configuration>

The Second part defines the Site Map Provider and sets securityTrimming to true to only show pages the user has access to.

<system.web>

 

    <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">

 

    <providers>

 

        <add name="XmlSiteMapProvider"

 

        description="SiteMap provider which reads in .sitemap XML files."

 

        type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0,... 

 

        siteMapFile="web.sitemap" securityTrimmingEnabled="true"/>

 

    </providers>

 

    </siteMap>

 


The Master Page

In your master page, you need to define your primary menu.  In our case, it is the one that displays: REGISTER;NEWS and ABOUT.  Here is all you need for that.

    <asp:Menu ID="mainMenu" runat="server" Orientation="Horizontal"

 

        DataSourceID="SiteMapMain" CssClass="headLinksBar"  CssSelectorClass="SimpleEntertainmentMenu"

 

        MaximumDynamicDisplayLevels="0" StaticItemFormatString="// {0} &nbsp;&nbsp;&nbsp; ">

 

    </asp:Menu>

 

<asp:SiteMapDataSource ID="SiteMapMain" runat="server" ShowStartingNode="False" />

The Inherited Page (About.aspx For Example)

<asp:Content ID="SublinksSessions" ContentPlaceHolderID="Sublinks" runat="server">

 

    <asp:Menu ID="subMenu" runat="server" DataSourceID="SiteMapAbout" SkinID="subMenu"  CssClass="headLinksBar"

 

    CssSelectorClass="SimpleEntertainmentMenu"     >

 

    </asp:Menu>

 

</asp:Content>

 


And the Benefits...

  • You have no .net code to write!
  • Adding new menu items as Primary or Secondary is easy
  • Security is completely taken care of
  • Menu Entries Automatically come and go based on User Permission

Not Using the CSS Friendly Adapters

 

If you do not use the CSS Friendly Adapter library, the menu render using tables.
Below is what the actual HTML looks like of the main menu if I remove the

CSS Friendly Adapters.

<table>

 

    <a href="#ctl00_mainMenu_SkipLink">

 

        <img alt="Skip Navigation Links" src="/WebStyleOnly%20-%20Copy/WebResource.axd?d=G5" width="0" height="0" style="border-width: 0px;" />

 

    </a>

 

    <table id="ctl00_mainMenu" class="headLinksBar ctl00_mainMenu_2" cssselectorclass="SimpleEntertainmentMenu" cellpadding="0" cellspacing="0" border="0">

 

        <tr>

 

            <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ctl00_mainMenun0">

 

                <table cellpadding="0" cellspacing="0" border="0" width="100%">

 

                    <tr>

 

                        <td style="white-space: nowrap;">

 

                            <a class="ctl00_mainMenu_1" href="/WebStyleOnly%20-%20Copy/Register.aspx">

 

                                // REGISTER

 

                            </a>

 

                        </td>

 

                    </tr>

 

                </table>

 

            </td>

 

            <td style="width: 3px;">

 

            </td>

 

            <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ctl00_mainMenun1">

 

                <table cellpadding="0" cellspacing="0" border="0" width="100%">

 

                <tr>

 

                    <td style="white-space: nowrap;">

 

                        <a class="ctl00_mainMenu_1" href="/WebStyleOnly%20-%20Copy/News.aspx">

 

                            // NEWS

 

                        </a>

 

                    </td>

 

                </tr>

 

                </table>

 

            </td>

 

            <td style="width: 3px;">

 

            </td>

 

            <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" onkeyup="Menu_Key(this)" id="ctl00_mainMenun2">

 

                <table cellpadding="0" cellspacing="0" border="0" width="100%">

 

                    <tr>

 

                        <td style="white-space: nowrap;">

 

                            <a class="ctl00_mainMenu_1" href="/WebStyleOnly%20-%20Copy/About.aspx">

 

                                // ABOUT

 

                            </a>

 

                        </td>

 

                    </tr>

 

                </table>

 

            </td>

 

            </span>

 

        </tr>

 

</table>

The same code, when using the CSS Friendly adapters, plus some clever additions that will be discussed later, has the html code looking like the following.

<table>

 

    <tr>

 

        <div class="AspNet-Menu-Horizontal">

 

            <ul class="AspNet-Menu">

 

                <li class="AspNet-Menu-TopLevel-register">

 

                    <a href="/WebStyleOnly - Copy/Register.aspx">

 

                      REGISTER

 

                     </a>

 

                </li>

 

                 <li class="AspNet-Menu-TopLevel-news">

 

                    <a href="/WebStyleOnly - Copy/News.aspx">NEWS</a>

 

                </li>

 

                <li class="AspNet-Menu-TopLevel-about-Selected">

 

                    <a href="/WebStyleOnly - Copy/About.aspx">

 

                      ABOUT</a>

 

                </li>

 

            </ul>

 

         </div>

 

     </tr>

 

 </table>

You can see that the CSS adapter code is not only much smaller, but easier to read and because of the inserted class names, much easier to customize.

Conclusions

We have not made clear yet how the CSS Friendly Adapters will make the menu's work the way we want it to. We have shown css classes created (AspNet-Menu-TopLevel-about-Selected for example) are create by the custom code written by us in the CSS Friendly Adapter Project.  We have however talked about the menu control and showed an example of how the html is actually rendered, and what is rendered based on.  That is, the web.sitemap defines the menu and we have shown that.  In the next article, we will show details of the custom code we have in the CSS Friendly Adapter that solves the problem of how to highlight the menu choices based on what is clicked.