2012-03-30 1 views
7

В моем проекте MVC3, я установил Maartenba в MvcSiteMapProvider v.3.2.1 и у меня есть очень простое, статическое, два уровня меню, которое я создал , Ниже представлена ​​концептуальная структура карты.MvcSiteMapProvider - несколько страниц нужна Ссылка на одно меню Node

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

Теперь, есть много дополнительных страниц под Листингом членов (например, Detail, редактирование и т.д.), но я не хочет, чтобы эти отображаются пункты меню третьего уровня (в основном потому, что они связаны с конкретный идентификатор участника). Тем не менее, я хочу, чтобы все эти страницы третьего уровня были «привязаны» к узлу меню «Список элементов», чтобы он отображался как выбранный на этих страницах.

У меня есть следующий код в моем файле 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. Я хочу, чтобы указать, что любая данная страница является частью родительского узла меню «Центр члена», так что меню дочерних узлы " Member Center ", независимо от того, определена ли данная страница как определенный узел в структуре меню.

  2. Я хочу указать (возможно, в представлении или действии контроллера), что конкретная страница должна быть привязана к определенному узлу меню. Например, когда пользователь находится в Members/Member/Detail/1, я просто хочу, чтобы дочерний узел «Member Listing» был указан как IsCurrentNode, так что файл SiteMapNodeModel.cshtml правильно украшал его классом «selectedMenuItem».

Любые предложения?

ответ

6

Вы можете добавить узлы третьего уровня в XML-карту сайта и указать видимость, чтобы скрыть их из меню. Вот заявление узла, чтобы отобразить его только в сухарях:

<mvcSiteMapNode area="Members" 
       controller="Member" 
       action="Detail" 
       visibility="SiteMapPathHelper,!*" 
       title="Member details" /> 

Edit:

Насколько я знаю, вы не можете установить IsCurrentNode. Но вы можете проверить, если узел меню выбран в настоящее время с помощью следующего кода (я использую его в шаблоне отображения SiteMapNodeModel):

IList<string> classes = new List<string>(); 
if (Model.IsCurrentNode || Model.IsInCurrentPath && !Model.Children.Any()) 
{ 
    classes.Add ("menu-current"); 
} 
+0

Макс, спасибо большое! Это решает основную проблему исчезновения узлов второго уровня. Однако, есть ли в любом случае, что вы знаете, что узел второго уровня установлен в IsCurrentNode, когда это происходит? Например, я хотел бы, чтобы список элементов списка отображался как выбранный на странице сведений о членах. Если нет, это не огромная сделка ... просто эстетический запрос. – bigmac

1

Добавление к ответу Макса, я бы также создать метод расширения для 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"); 
} 
Смежные вопросы