2012-03-30 24 views
7

在我MVC3项目,我已经安装了Maartenba的MvcSiteMapProvider v.3.2.1,我有一个非常简单的,静态的,两级,我已经创建的菜单。以下是概念图结构。MvcSiteMapProvider - 多页需要链接到一个菜单节点

- Home 
- Member Center 
    - Member Listing [SELECTED] 
    - Event Calendar 
    - Documents 
- Administration 

现在,有会员列表下有许多子页面(如详细信息,编辑等),但我希望这些显示为第三级菜单项(主要是因为它们被设置到一个特定的会员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,成员中心(“成员列表”,“事件日历”等)下的子节点消失。因此,这里是我的,我有我当前的代码的两个问题:

  1. 我想指定任何特定的网页是“会员中心”父菜单节点的一部分,这样的子菜单节点“成员中心“将被显示,而不管给定页面是否被定义为菜单结构中的特定节点。

  2. 我想指定(可能在视图或控制器操作中)特定页面应该绑定到特定菜单节点。例如,当用户在Members/Member/Detail/1时,我只想将“成员列表”子节点指定为IsCurrentNode,以便SiteMapNodeModel.cshtml文件使用“selectedMenuItem”类正确装饰它。

有什么建议吗?

回答

6

您可以将第3级节点添加到站点地图XML并指定可见性以从菜单中隐藏它们。这里是节点声明面包屑唯一显示:

<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"); 
} 
+0

最大,非常感谢你!这解决了二级节点消失的基本问题。但是,无论如何,当发生这种情况时,您知道将第二级节点设置为IsCurrentNode?例如,我希望Member Details页面上的Member Listing节点显示为选中状态。如果不是,这不是一个大问题......只是一个美学要求。 – bigmac 2012-04-11 23:42:56

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> 
} 
1

而且马克斯基谢廖夫的答案,如果你想使用该技术,但能够在你的控制器动作中使用的属性,我做了以下内容:

定义一个定制的知名度提供商:

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"); 
} 
相关问题