在我的 MVC3 项目中,我安装了Maartenba的 MvcSiteMapProvider v.3.2.1 ,并且我创建了一个非常简单的静态两级菜单。下面是概念图结构。
- Home
- Member Center
- Member Listing [SELECTED]
- Event Calendar
- Documents
- Administration
现在,会员列表下有很多子页面(例如详细信息,编辑等),但我不希望这些显示为第3级菜单项(主要是因为它们被绑定)到特定的会员ID)。但是,我确实希望所有这些第三级页面都与“成员列表”菜单节点“绑定”,以便在这些页面上显示为已选中。
我的Mvc.SiteMap文件中有以下代码:
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Member Center" area="Members" controller="Home" action="Index" roles="Approved Member" >
<mvcSiteMapNode title="Member Listing" area="Members" controller="Member" action="List" />
<mvcSiteMapNode title="Event Calendar" area="Members" controller="Event" action="List" />
<mvcSiteMapNode title="Documents" area="Members" controller="Document" action="List" />
</mvcSiteMapNode>
<mvcSiteMapNode title="Administration" area="Admin" controller="Home" action="Index" roles="Site Administrator" >
</mvcSiteMapNode>
</mvcSiteMapNode>
要渲染菜单,我在_Layout.cshtml文件中使用以下代码:
@Html.MvcSiteMap().Menu(1, true, true, 1, true, true)
最后,我修改了SiteMapNodeModel.cshtml文件,以便它将“selectedMenuItem”类添加到与用户正在查看的页面相关的节点。这是呈现菜单节点的snippit。
@model SiteMapNodeModel
<a href="@Model.Url" class="@(Model.IsCurrentNode ? "selectedMenuItem" : "")">@Model.Title</a>
地图的显示和导航工作正常,直到我进一步导航到成员区域。例如,如果我经过Members/Member/List
(正确显示菜单)和Members/Member/Detail/1
之类的页面,会员中心下的子节点(“会员列表”,“活动日历”等)的消失即可。因此,以下是我对当前代码的两个问题:
我想指定任何给定页面是“成员中心”父菜单节点的一部分,以便显示“成员中心”的子菜单节点,无论给定页面是否定义为菜单结构中的特定节点。
我想指定(可能在视图或控制器操作中)特定页面应绑定到特定菜单节点。例如,当用户位于Members/Member/Detail/1
时,我只想将“Member Listing”子节点指定为IsCurrentNode
,以便SiteMapNodeModel.cshtml文件使用“selectedMenuItem”类正确地修饰它。
有什么建议吗?
答案 0 :(得分:6)
您可以向站点地图XML添加第3级节点,并指定可见性以将其隐藏在菜单中。这是仅在面包屑中显示它的节点声明:
<mvcSiteMapNode area="Members"
controller="Member"
action="Detail"
visibility="SiteMapPathHelper,!*"
title="Member details" />
编辑:
据我所知,您无法设置IsCurrentNode。但您可以使用以下代码检查当前是否选择了菜单节点(我在SiteMapNodeModel显示模板中使用它):
IList<string> classes = new List<string> ();
if (Model.IsCurrentNode || Model.IsInCurrentPath && !Model.Children.Any ())
{
classes.Add ("menu-current");
}
答案 1 :(得分:1)
添加到Max的答案我还会为SiteMapNodeModel创建一个扩展方法。您可以使用它来实现执行此操作所需的所有自定义逻辑:
public static class SiteMapNodeModelExtender
{
public static bool IsRealCurrentNode(this SiteMapNodeModel node)
{
// Logic to determine the "real" current node...
// A naive implementation could be:
var currentPath = HttpContext.Current.Request.Url.AbsolutePath;
return currentPath.StartsWith("Members/Member/") && node.Title.Equals("Member Center")
}
}
并相应地更改显示模板:
/* Also check IsRealCurrentNode, depending on the use case maybe only
IsRealCurrentNode */
@if ((Model.IsCurrentNode || Model.IsRealCurrentNode()) && Model.SourceMetadata["HtmlHelper"].ToString() != "MvcSiteMapProvider.Web.Html.MenuHelper") {
<text>@Model.Title</text>
} else if (Model.IsClickable) {
<a href="@Model.Url ">@Model.Title</a>
} else {
<text>@Model.Title</text>
}
答案 2 :(得分:1)
继Max Kiselev的回答之后,如果您想使用该技术但能够在控制器操作上使用属性,我会做以下事情:
定义自定义可见性提供程序:
public class AlwaysInvisibleVisibilityProvider : ISiteMapNodeVisibilityProvider
{
public bool IsVisible(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata)
{
return false;
}
}
然后继承MvcSiteMapNodeAttribute:
public class InvisibleMvcSiteMapNodeAttribute : MvcSiteMapNodeAttribute
{
public InvisibleMvcSiteMapNodeAttribute(string key, string parentKey)
{
Key = key;
ParentKey = parentKey;
VisibilityProvider = typeof (AlwaysInvisibleVisibilityProvider).AssemblyQualifiedName;
}
}
然后您可以在控制器操作中使用它:
[HttpGet]
[InvisibleMvcSiteMapNodeAttribute("ThisNodeKey", "ParentNodeKey")]
public ViewResult OrderTimeout()
{
return View("Timeout");
}