Overview
This article gives a basic overview of how to create dynamic menus for your .net web pages.
There are three important controls to designing your dynamic menu:
- web.sitemap Control
- SiteMapDataSource Control
- Menu Control
The web.sitemap Control
The Sitemap control is an XML file that contains information about your dynamic menu. It stores your menu in a series of nested tag controls. Add this to your project by right-clicking on your project and selecting Add->New Items->Web->Site Map
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" > <siteMapNode> <siteMapNode url="default.aspx" title="Home"> <siteMapNode url="Search.aspx?Type=User&Category=Details" title="User Details" /> </siteMapNode> </siteMap>
These nodes can be nested indefinitely, however there can only be one root SiteMapNode. All other SiteMapNodes must be children of this root node. Also, any characters that you want to include in your URL string need to be escaped using HTML escape codes.
The SiteMapDataSource Control
This control links your SiteMap XML file to your web page. Use the following code to implement it.
<asp:SiteMapDataSource ID="SMDSource_Menu" runat="Server" />
One does not have to specify the sitemap XML file name if the default naming convention is used.
The Menu Control
Now we add the menu control and link it to the style sheet. Note the StaticSubMenuIndent property. By default, this control will enter a 16 pixel spacer between your menu items. This can be disabled using this control. The Orientation and StaticDisplayLevels controls are set so that the menu displays as a single horizontal line.
<asp:Menu ID="menu_contents" runat="server" DataSourceID="SMDSource_Menu" Orientation="Horizontal" StaticDisplayLevels="2" IncludeStyleBlock="False" StaticSubMenuIndent="0px" CssClass="menu_contents"> <StaticMenuItemStyle CssClass="menu_contents_unselected"/> <StaticHoverStyle CssClass="menu_contents_selected" /> <StaticSelectedStyle CssClass="menu_contents_selected" /> </asp:Menu>
Unfortunately, the menu control is broken in a significant way, which is why I am writing this documentation. The problem has to do with the 'Selected' Property. In my case, I wanted the menu to show which page was currently active. However, the menu built from the XML collection is reloaded every time the page is reloaded, and .NET does not run the comparison correctly, so we need to do it ourselves in the code-behind.
Private Sub menu_contents_DataBound(sender As Object, e As System.EventArgs) Handles menu_contents.DataBound '-- Get page name from relative path Dim PageName As String = Page.AppRelativeVirtualPath '-- Since we used the relative path, we have to remove the tilde so we get the page name as it is written in the Menu control. PageName = PageName.Replace("~", "") '-- Select menu item with matching menu_contents property Dim ParentMenu As MenuItem Dim ChildMenu As MenuItem For Each ParentMenu In menu_contents.Items If ParentMenu.NavigateUrl = PageName Then ParentMenu.Selected = True Else For Each ChildMenu In ParentMenu.ChildItems If ChildMenu.NavigateUrl = PageName Then ChildMenu.Selected = True End If Next End If Next End Sub
Now it's time to write up your style sheet. Warning: IE will publish your menu as a table, while other browsers will not. What this means is that your style sheet has to accommodate for both a table-based menu and a span-based menu.
.menu_contents_unselected a:hover { color:Black } .menu_contents_selected a:hover { color:white } .menu_contents_unselected a { height: 37px; padding: 29px 26px 6px 24px; letter-spacing: 0.1em; font: normal 100% 'lucida sans unicode', arial, sans-serif; display: block; float: left; text-align: center; text-transform: uppercase; text-decoration: none; color: #737144; background: transparent; } .menu_contents_selected a { height: 37px; padding: 29px 26px 6px 24px; letter-spacing: 0.1em; font: normal 100% 'lucida sans unicode', arial, sans-serif; display: block; float: left; text-align: center; text-transform: uppercase; text-decoration: none; color: #FFF; background: #1C2C3E url(img/menu_select.png) repeat-x; } .menu_contents tr td { padding: 0; background:transparent; } .menu_contents table { margin:0; padding:0px; background:transparent; height:72px }
Site maps in .NET 4.0
So they changed the way that .NET handles CSS in 4.0. While I can't say I understand it 100%, here is how to "fix" your CSS. Delete the stuff above and replace it with this:
#menu_contents { margin:0; padding:0px; background:transparent; height:72px; } a.level1 { visibility:hidden; } a.level2 { width:100px; } a.level2.selected { width:50px; } #menu_contents a.static { height: 37px; padding: 29px 26px 6px 24px; letter-spacing: .2em; font: normal 100% 'lucida sans unicode', arial, sans-serif; display: block; float: left; text-align: center; text-transform: uppercase; text-decoration: none; color: #737144; background: transparent; } #menu_contents a.static:hover { color:white } #menu_contents a.static.selected:hover { color:black } #menu_contents a.static.selected { height: 37px; padding: 29px 26px 6px 24px; letter-spacing: 0.2em; font: normal 100% 'lucida sans unicode', arial, sans-serif; display: block; float: left; text-align: center; text-transform: uppercase; text-decoration: none; color: #FFF; background: #1C2C3E url(img/menu_select.png) repeat-x; }