超级简单:一个横向ASP.NET Menu控件
几个星期前,开始了一个ASP.NET Web应用程序,需要一个简单的横向的带子菜单的Menu控件。将Menu控件拖拽到一个页面上时,我就决定使用ASP.NET的Menu控件。这个控件很简单,但该控件不提供访问的key和支持菜单窗体的target。我把这些功能放在一起将如何去实现:
1、包含accesskey属性
2、包含target
属性
3、包含Site Map Path
这是项目工程的结构,欢迎你下载这个Demo。
首先,添加一个Site Map 到我们的website工程。打开web.sitemap文件,添加你的导航数据和导航结构。为了强调一个菜单标题的某些特征,我们可以使用HTML下划线记 (<u></u>
)。为了正确地解析XML,我们必须用 & lt;取代小于号(<)。每个siteMapNode包含一个accesskey 和target属性值。
Listing 1:

<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 Pag到我们的website项目中,拖一个SiteMapDataSource控件到页面上,接着拖一个Menu控件,Menu控件包含在一个div里面,menu每个属性都能在这里被找到,
设置 staticdisplaylevels ="2"
和orientation="Horizontal"来横向的显示menu控件。我们可以使用内联样式表或放置在一个外部文件中的CSS样式。在本例中,CSS样式位于style.css文件。
Listing 2:

<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>
拖一个SiteMapPath 控件到页面上。这个控件的目的是显示导航路径和显示用户当前页的位置。请看看Listing 3。
Listing 3:

<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>
在Page_Load事件中包括MenuItemDataBound和SiteMapResolve事件处理程序。前者的目的是插入target的属性值,在Meun呈现或者显示之前,为菜单项创造accesskey。后者是修改的SiteMapPath控件显示的文本。
new MenuEventHandler(NavigationMenu_MenuItemDataBound);
SiteMap.SiteMapResolve +=
new SiteMapResolveEventHandler(SiteMap_SiteMapResolve);
下面显示的是该NavigationMenu_MenuItemDataBound实现的方法。在Menu控件中的菜单项绑定数据时,触发MenuItemDataBound事件发生。话虽如此,这将通过循环SiteMapNode来寻找accesskey
和target
属性。每一个target属性与菜单项关联,我们可以用target属性值来设置目标窗口。

{
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);
}
}
要获得accesskey,将在母版页上添加一个Panel控件和一个重定向到指定的一个网页的JavaScript函数。请看Listing 6
Listing 6:
<script type="text/javascript">
function navigateTo(url) {
window.location = url;
}
</script>
下面是CreateAccessKeyButton方法的实现。动态的创建一个HtmlButton控件,给它添加一个onclick事件。设置style.left样式属性为-255px来隐藏这个控件。

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);
}
当CurrentNode属性被访问时,SiteMap.SiteMapResolve事件被触发。这将调用递归的ReplaceNodeText方法,来替换HTML下划线标记 。请看Listing 8
Listing 8:

{
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;
}
在移动设备上,悬停菜单似乎无法显示。为了解决这个问题,我使用一个TreeView控件并设置其Visible属性为false。默认情况下,这个控件展开它所有的节点的。这将需要对上述问题进行处理。如果请求浏览是一个移动设备,在后台代码中,隐藏的菜单控件和显示TreeView控件。
{
if (Request.Browser.IsMobileDevice)
{
NavigationMenu.Visible = false;
NavigationTreeView.Visible = true;
}
}
当我在IE 8中测试菜单时,悬停菜单也没有正确呈现。为了克服这个问题, 我们设置DynamicMenuStyle z-index 为200。子菜单在谷歌浏览器不能运行。经过一番研究,我找到了解决的办法。见下面。

{
if (Request.UserAgent.IndexOf("AppleWebKit") > 0)
{
Request.Browser.Adapters.Clear();
NavigationMenu.DynamicMenuStyle.Width = Unit.Pixel(120);
}
}
如果您发现任何错误或对内容有不同的意见,请给我留言,我会与你一起加以纠正。
效果:http://download.ysatech.com/ASP-NET-Menu-Control/
代码:/Files/zhuqil/MenuControl.zip
原文:http://www.codeproject.com/KB/webforms/Horizontal-Menu-Control.aspx
(全文完)
以下为广告部分
您部署的HTTPS网站安全吗?
如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!
快速了解HTTPS网站安全情况。
安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。
安装部署SSL证书变得更方便。
SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。
让服务器远离SSL证书漏洞侵扰
TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述