Article Series
(Source Code Available in Article 6 Below – (Added March 2009))
Introduction
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.
| |
| |
| |
| |
| |
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.
1: <?xml version="1.0" encoding="utf-8" ?>
2: <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
3: <siteMapNode url="Default.aspx" title="HOME"
4: description="Silicon Valley CodeCamp 08">
5: <siteMapNode url="Register.aspx" title="REGISTER" description="" />
6: <siteMapNode url="News.aspx" title="NEWS" description="" />
7: <siteMapNode url="About.aspx" title="ABOUT" description="">
8: <siteMapNode url="Contact.aspx" title="Contact" description="" />
9: <siteMapNode url="Sponsors.aspx" title="Sponsors" description="" />
10: <siteMapNode url="Previous.aspx" title="Previous" description="" />
11: </siteMapNode>
12: </siteMapNode>
13: </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
1: <location path="Sponsors.aspx">
2: <system.web>
3: <authorization>
4: <deny users="?"/>
5: </authorization>
6: </system.web>
7: </location>
8: </configuration>
The Second part defines the Site Map Provider and sets securityTrimming to
true to only show pages the user has access to.
1: <system.web>
2: <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">
3: <providers>
4: <add name="XmlSiteMapProvider"
5: description="SiteMap provider which reads in .sitemap XML files."
6: type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0,...
7: siteMapFile="web.sitemap" securityTrimmingEnabled="true"/>
8: </providers>
9: </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.
1: <asp:Menu ID="mainMenu" runat="server" Orientation="Horizontal"
2: DataSourceID="SiteMapMain" CssClass="headLinksBar" CssSelectorClass="SimpleEntertainmentMenu"
3: MaximumDynamicDisplayLevels="0" StaticItemFormatString="// {0} ">
4: </asp:Menu>
5: <asp:SiteMapDataSource ID="SiteMapMain" runat="server" ShowStartingNode="False" />
6:
7:
The Inherited Page (About.aspx For Example)
1: <asp:Content ID="SublinksSessions" ContentPlaceHolderID="Sublinks" runat="server">
2: <asp:Menu ID="subMenu" runat="server" DataSourceID="SiteMapAbout" SkinID="subMenu" CssClass="headLinksBar"
3: CssSelectorClass="SimpleEntertainmentMenu" >
4: </asp:Menu>
5: </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.
Code Snippet
0: <table> 1: <a href="#ctl00_mainMenu_SkipLink"> 2: <img alt="Skip Navigation Links" 3: src="/WebStyleOnly%20-%20Copy/WebResource.axd?d=G5" 4: width="0" height="0" style="border-width: 0px;" /></a><table id="ctl00_mainMenu" 5: class="headLinksBar ctl00_mainMenu_2" 6: cssselectorclass="SimpleEntertainmentMenu" 7: cellpadding="0" cellspacing="0" border="0"> 8: <tr> 9: <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 10: onkeyup="Menu_Key(this)" 11: id="ctl00_mainMenun0"> 12: <table cellpadding="0" cellspacing="0" border="0" width="100%"> 13: <tr> 14: <td style="white-space: nowrap;"> 15: <a class="ctl00_mainMenu_1" 16: href="/WebStyleOnly%20-%20Copy/Register.aspx"> 17: // REGISTER 18: </a> 19: </td> 20: </tr> 21: </table> 22: </td> 23: <td style="width: 3px;"> 24: </td> 25: <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 26: onkeyup="Menu_Key(this)" 27: id="ctl00_mainMenun1"> 28: <table cellpadding="0" cellspacing="0" border="0" width="100%"> 29: <tr> 30: <td style="white-space: nowrap;"> 31: <a class="ctl00_mainMenu_1" 32: href="/WebStyleOnly%20-%20Copy/News.aspx"> 33: // NEWS </a> 34: </td> 35: </tr> 36: </table> 37: </td> 38: <td style="width: 3px;"> 39: </td> 40: <td onmouseover="Menu_HoverStatic(this)" onmouseout="Menu_Unhover(this)" 41: onkeyup="Menu_Key(this)" 42: id="ctl00_mainMenun2"> 43: <table cellpadding="0" cellspacing="0" border="0" width="100%"> 44: <tr> 45: <td style="white-space: nowrap;"> 46: <a class="ctl00_mainMenu_1" 47: href="/WebStyleOnly%20-%20Copy/About.aspx">// ABOUT 48: </a> 49: </td> 50: </tr> 51: </table> 52: </td>< /span> 53: </tr> 54: </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.
Code Snippet
0: <table> 1: <tr> 2: <div class="AspNet-Menu-Horizontal"> 3: <ul class="AspNet-Menu"> 4: <li class="AspNet-Menu-TopLevel-register"> 5: <a href="/WebStyleOnly - Copy/Register.aspx"> 6: REGISTER</a> </li> 7: <li class="AspNet-Menu-TopLevel-news"><a 8: href="/WebStyleOnly - Copy/News.aspx">NEWS</a> 9: </li> 10: <li class="AspNet-Menu-TopLevel-about-Selected"> 11: <a href="/WebStyleOnly - Copy/About.aspx"> 12: ABOUT</a> </li> 13: </ul> 14: </div> 15: </tr> 16: </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.











June 13th, 2008 at 11:52 am
Hi Peter,
Come across your article today and found out this is exactly what I’m trying to do at the moment. I’m using the CSS Friendly Menu with two Menu controls and two SiteMapDatasouce on Master, Content pages.
I’m looking around the MenuAdapter.cs and not sure where to start of, will you possible give me some suggestions? Is you next article will be publishing soon?
Best Regards,
Chris
August 15th, 2008 at 4:49 pm
Hello Peter,
I’m interested in finding out how to customize the menu adapter to include the name of the specific menu item in the class. For example ‘class=”AspNet-Menu-TopLevel-about-Selected”>’. How do you get it to add the ‘about’ part? Is there another part to this article that explains that?
Thanks for your help,
Nancy
August 15th, 2008 at 9:22 pm
Nancy,
I do plan a follow up post. Just have been busy lately.
August 23rd, 2008 at 3:24 am
Hi, Peter
This is just what I need to implement to my site.
I was wondering.. if You can post the code for Venue.aspx and the codebehind.
That’ll help me.
Thanks
Harry
September 23rd, 2008 at 4:07 pm
Hi Peter,
I have the same question Nancy has. Any idea on when you’ll be able to post a solution for adding custom class names to the li elements?
Thanks,
Jason
October 5th, 2008 at 1:22 am
Thank you Peter.
October 13th, 2008 at 1:04 pm
Very interesting article, so many useful informations,
really good work!
thx for nice reading
October 22nd, 2008 at 1:55 pm
Very good article, Although I’m still struggling to fully implement this, feel I’m missing the next step on how to customise the CSS classes. Sorry I’m not very experienced with ASP.NET. Could you give me any pointers.
Thanks again
Ian
October 27th, 2008 at 2:55 am
I don’t understand why and tags are used in the css menu in the second code snippet. What’s up with that?
October 27th, 2008 at 2:56 am
Oops!
What I meant to say is:
I don’t understand why table and tr tags are used in the css menu in the second code snippet. What’s up with that?
October 29th, 2008 at 12:04 pm
> I don’t understand why table and tr tags are used in the css menu in the second code snippet. What’s up with that?
Hi Yoyo,
I’m not a browser/css wizard, but the guy who helped me with the css said that using table solved some browser issues. I think it may have been an ie6 issue.
November 15th, 2008 at 1:10 pm
I will refer people to your ITEMS. Effective use of Wordpress had some exceptional.This looks good! Really good tutorial include so many helpful informations!
November 19th, 2008 at 11:54 pm
Hi Pete,
It would be gr8 to post the helpful information on “Dynamic menu creation in Asp.net”. The menu items which i am using in my application is role specific; My question is ” storing the menu Items in database is good idea”.
waiting for your reply.
Thanks,
Subhas
November 26th, 2008 at 9:45 am
I appreciate your example, but I cannot get the sub menu styles working. Can you provide a download of the working app?
November 26th, 2008 at 9:55 am
I don’t have a full working stand alone example yet. I’m hoping to make another post that will include that but have been pretty busy lately. Sorry. Maybe someone else has a working example of this.
December 28th, 2008 at 3:30 am
Wow a fantastic site, I loved it when I landed on it. I could never do anything like this, maybe I should open a competition for someone to redesin mine.
January 2nd, 2009 at 12:28 am
Hi,
I m new to this control.
I tried to implement but i cant get.
Can you pleaz provide me Zip folder from which i download whole code.
Thanks in advance.
January 7th, 2009 at 10:43 am
Hi,
I dont’t know how to set the SiteMapDataSource for SiteMapAbout.
Thx.
January 29th, 2009 at 2:29 pm
I’ve installed and used CSSF. I set set propertied to display horizontally. But code created by CSSF is a list. UL. Which displays as a tree view. How do i display horizontally? Do I need to recode the menu by hand?
February 19th, 2009 at 1:24 am
Hi,
I did try but failed to acheive any result, being new to asp.net. Please post a running code.
Thanks
March 27th, 2009 at 12:47 pm
I just published the source code for these at this location: http://peterkellner.net/2009/03/27/codecampwebsiteseries6-cssfriendly-adapters-aspnet-menu/ -Peter
May 8th, 2009 at 1:03 pm
So – the DataSource for SiteMapAbout, for example, is internally mapped by ASP.NET to the sitemap control’s “ABOUT” title’d node?
Is the name of the data source derived from the node title?
August 11th, 2009 at 1:22 pm
Hi Peter
Great work. On headLinksBar I am unable to have a menu made up of a name with a space ie Customer Admin. You have shown it working in the sub menu.
Is there a solution?
cheers
November 6th, 2009 at 8:32 am
[...] with the ASP.NET Menu control and the CSS Friendly Control Adapters, it can be used to automatically generate navigation for your [...]
December 17th, 2009 at 11:39 pm
Hi Peter
It’s Great work.
I am unable to have a menu item in two line on one page only.
Is there a solution.
plz reply on my id
Thanks.
February 11th, 2010 at 3:03 am
Great work with the coding indeed. I have not come across any components yet that can match this. So it’s quite an awesome coding. Thanks for sharing with us. I will surely send this around to my pals. Cheers
February 18th, 2010 at 10:41 pm
Love the coding. I’ve been having trouble with some of my coding and this article really helped me out figure out the problem. Thank you very much.