【问题标题】:MvcSiteMapProvider - Multiple Pages Need To Link to One Menu NodeMvcSiteMapProvider - 多个页面需要链接到一个菜单节点
【发布时间】:2012-03-30 15:09:27
【问题描述】:

在我的 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”类添加到与用户正在查看的页面相关的节点。这是呈现菜单节点的代码片段。

@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”类正确装饰它。

有什么建议吗?

【问题讨论】:

    标签: asp.net-mvc mvcsitemapprovider


    【解决方案1】:

    您可以将 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");
    }
    

    【讨论】:

    • 马克斯,非常感谢!这就解决了二级节点消失的基本问题。但是,您是否知道在发生这种情况时将二级节点设置为 IsCurrentNode?例如,我希望在成员详细信息页面上显示为选中的成员列表节点。如果不是,这不是什么大不了的事……只是审美要求。
    【解决方案2】:

    除了 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>
    }
    

    【讨论】:

      【解决方案3】:

      对于 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");
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-03-20
        • 1970-01-01
        • 2015-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多