Here is the structure of my project. You are welcome to
download this demo.
Figure 2
Putting Everything Together
First, add a Site Map to the website project. Open the
web.sitemap file and populate it with your navigation data and structures. To
underline certain character of the menu title, we can use the HTML underline
tag (<u></u>). In order to parse the XML flawlessly we must replace
the less than sign (<) with & lt; (no spaces). Then, include an accesskey
and target attribute with a value to each siteMapNode. See below for example.
Site Map
Listing 1
<siteMapNode>
<siteMapNode url="Default.aspx" title="& lt;u>H& lt;/u>ome" description="Home"
accesskey="H" />
<siteMapNode url="~/Views/Menu1.aspx" title="& lt;u>M& lt;/u>enu1"
description="Menu1" accesskey="M" />
<siteMapNode url="~/Views/Menu2.aspx" title="M<u>e</u>nu2"
description="Menu2" accesskey="E" />
<siteMapNode url="~/Views/Menu3.aspx" title="Me<u>n</u>u3"
description="Menu3" accesskey="N" target="_blank" />
<siteMapNode url="~/Views/Menu4.aspx" title="Men<u>u</u>4"
description="Menu4" accesskey="U">
<siteMapNode url="~/Views/Menu4Sub1.aspx" title="Menu4<u>S</u>ub1"
description="Menu4Sub1"
accesskey="S" />
<siteMapNode url="~/Views/Menu4Sub2.aspx" title="Menu4Su<u>b</u>2"
description="Menu4Sub2"
target="_blank" accesskey="B" />
</siteMapNode>
……
….
</siteMapNode>
</siteMap>
Master Page
Add a Master Page to the website
project. Drag a SiteMapDataSource control on to the page and then the menu
control and wrap the menu control inside a div tag. The details description of each
menu property can be found on Menu Properties. Set the staticdisplaylevels
="2" and orientation="Horizontal" to display the menu
control in horizontal mode. We can use an inline style sheets or place the CSS
style in an external file. In this tutorial, the CSS style is located in
style.css file. See listing 2.
Listing 2
<asp:SiteMapDataSource id="MenuSource" runat="server" />
<div class="background">
<asp:menu id="NavigationMenu" CssClass="NavigationMenu"
staticdisplaylevels="2" DynamicHorizontalOffset="1"
staticsubmenuindent="1px" MaximumDynamicDisplayLevels="4"
orientation="Horizontal"
DynamicPopOutImageUrl="~/Images/right-arrow.gif"
StaticPopOutImageUrl="~/Images/drop-arrow.gif"
datasourceid="MenuSource"
runat="server" Height="30px">
<staticmenuitemstyle ItemSpacing="10" CssClass="staticMenuItemStyle"/>
<statichoverstyle CssClass="staticHoverStyle" />
<StaticSelectedStyle CssClass="staticMenuItemSelectedStyle"/>
<DynamicMenuItemStyle CssClass="dynamicMenuItemStyle" />
<dynamichoverstyle CssClass="menuItemMouseOver" />
<DynamicMenuStyle CssClass="menuItem" />
<DynamicSelectedStyle CssClass="menuItemSelected" />
<DataBindings>
<asp:MenuItemBinding DataMember="siteMapNode"
NavigateUrlField="url" TextField="title"
ToolTipField="description" />
</DataBindings>
</asp:menu>
</div>
Drag a SiteMapPath control on to the page. The purpose of
this control is to display navigation path that shows the user the current page
location. See listing 3.
Listing 3
<div id="e">
<asp:SiteMapPath ID="SiteMapPath1" runat="server"
RenderCurrentNodeAsLink="true"
CssClass="currentNodeStyle"
PathSeparator=" >> ">
<PathSeparatorStyle ForeColor="#5D7B9D" CssClass="currentNodeStyle" />
<CurrentNodeStyle ForeColor="#333333" CssClass="currentNodeStyle" />
<NodeStyle ForeColor="#7C6F57" CssClass="currentNodeStyle" />
<RootNodeStyle ForeColor="#5D7B9D" CssClass="currentNodeStyle" />
</asp:SiteMapPath>
</div>
Master Page code behind
Include a MenuItemDataBound and SiteMapResolve event
handlers on to the Page_Load event. The purpose of the former event is to
insert the target attribute value and create access key for the menu item
before it is rendered or displayed in a Menu control. The latter event is to modify
the text displayed by the SiteMapPath control.
Listing 4
NavigationMenu.MenuItemDataBound += new
MenuEventHandler(NavigationMenu_MenuItemDataBound);
SiteMap.SiteMapResolve +=
new SiteMapResolveEventHandler(SiteMap_SiteMapResolve);
Below is the implementation of the NavigationMenu_MenuItemDataBound
method. The MenuItemDataBound event occurs when a menu item in a Menu control
is bound to data. That being said, it will loop through each siteMapNode and
look for the accesskey and target attribute. There is a target property
associated with the menu item and we can set its target window with the target
attribute value. See listing 5.
Listing 5
void NavigationMenu_MenuItemDataBound(object sender, MenuEventArgs e)
{
SiteMapNode node = (SiteMapNode)e.Item.DataItem;
//set the target of the navigation menu item (blank, self, etc...)
if (node["target"] != null)
{
e.Item.Target = node["target"];
}
//create access key button
if (node["accesskey"] != null)
{
CreateAccessKeyButton(node["accesskey"] as string, node.Url);
}
}
To get the access key to work, add a Panel control on to the
master page and a JavaScript function to redirect the webpage to the one that
is specified. See below.
Listing 6
<asp:Panel ID="AccessKeyPanel" runat="server" />
<script type="text/javascript">
function navigateTo(url) {
window.location = url;
}
</script>
Below is the implementation of the CreateAccessKeyButton
method. Create an HtmlButton control dynamically and attach an onclick event
to it. Set the style.left property to -2555px to hide the control. A complete
list of access key in different browsers is available here.
Listing 7
//create access key button
void CreateAccessKeyButton(string ak, string url)
{
HtmlButton inputBtn = new HtmlButton();
inputBtn.Style.Add("width", "1px");
inputBtn.Style.Add("height", "1px");
inputBtn.Style.Add("position", "absolute");
inputBtn.Style.Add("left", "-2555px");
inputBtn.Style.Add("z-index", "-1");
inputBtn.Attributes.Add("type", "button");
inputBtn.Attributes.Add("value", "");
inputBtn.Attributes.Add("accesskey", ak);
inputBtn.Attributes.Add("onclick", "navigateTo('" + url + "');");
AccessKeyPanel.Controls.Add(inputBtn);
}
The SiteMap.SiteMapResolve event get trigger when the
CurrentNode property is accessed. It will call the ReplaceNodeText method recursively
and replace the HTML underline tag. See listing 8.
Listing 8
SiteMapNode SiteMap_SiteMapResolve(object sender, SiteMapResolveEventArgs e)
{
SiteMapNode currentNode = SiteMap.CurrentNode.Clone(true);
SiteMapNode tempNode = currentNode;
tempNode = ReplaceNodeText(tempNode);
return currentNode;
}
//remove <u></u> tag recursively
internal SiteMapNode ReplaceNodeText(SiteMapNode smn)
{
//current node
if (smn != null && smn.Title.Contains("<u>"))
{
smn.Title = smn.Title.Replace("<u>", "").Replace("</u>", "");
}
//parent node
if (smn.ParentNode != null)
{
if (smn.ParentNode.Title.Contains("<u>"))
{
SiteMapNode gpn = smn.ParentNode;
smn.ParentNode.Title = smn.ParentNode.Title
.Replace("<u>", "").Replace("</u>", "");
smn = ReplaceNodeText(gpn);
}
}
return smn;
}
Using the Code
Since the menu is in the master page, right click the
website project, add new item, Web Form and check the Select Master Page
checkbox.