2012-03-30 9 views
7

Nel mio progetto MVC3, ho installato MvcSiteMapProvider versione 3.2.1 di Maartenba e ho una molto semplice statica del menu,, a due livelli che ho creato . Di seguito è riportata la struttura concettuale della mappa.MvcSiteMapProvider - più pagine necessità di collegare con un nodo Menu

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

Ora, ci sono molti sotto-pagine in elenco Stati (ad esempio Dettaglio, Modifica, ecc), ma Non vogliono questi visualizzate come voci di menu 3 ° livello (soprattutto perché sono legate a un ID membro specifico). Tuttavia, voglio che tutte queste pagine di terzo livello siano "vincolate" al nodo del menu Elenco membri in modo che venga visualizzato come selezionato su queste pagine.

ho il seguente codice nel mio file 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> 

Per rendere il menù, io sto usando il seguente codice nel mio file _Layout.cshtml:

@Html.MvcSiteMap().Menu(1, true, true, 1, true, true) 

Infine, Ho modificato il file SiteMapNodeModel.cshtml in modo che aggiunga una classe "selectedMenuItem" al nodo correlato alla pagina visualizzata dall'utente. Ecco lo snippit che esegue il rendering del nodo del menu.

@model SiteMapNodeModel 
    <a href="@Model.Url" class="@(Model.IsCurrentNode ? "selectedMenuItem" : "")">@Model.Title</a> 

La visualizzazione e la navigazione della mappa funzionano bene, fino a quando non mi muovo ulteriormente nell'area membri. Ad esempio, se si supera lo Members/Member/List (che visualizza correttamente il menu) e in una pagina come Members/Member/Detail/1, i nodi figlio in Member Center ("Elenco membri", "Calendario eventi", ecc.) scompaiono. Pertanto, ecco i miei due problemi che ho con il mio codice corrente:

  1. voglio specificare che una data pagina fa parte del nodo menu principale "Centro del membro", in modo che i nodi del menu figlio di " Centro membri "verrà visualizzato, indipendentemente dal fatto che la pagina specificata sia definita come nodo specifico nella struttura del menu.

  2. Desidero specificare (possibilmente nella vista o nell'azione del controller) che una pagina specifica debba essere collegata a un nodo di menu specifico. Ad esempio, quando l'utente è allo Members/Member/Detail/1, voglio semplicemente che il nodo figlio "Elenco membri" sia specificato come IsCurrentNode in modo che il file SiteMapNodeModel.cshtml lo decori correttamente con la classe "selectedMenuItem".

Qualche suggerimento?

risposta

6

È possibile aggiungere nodi di terzo livello all'XML della sitemap e specificare la visibilità per nasconderli dal menu. Ecco la dichiarazione di nodo per visualizzare soltanto nel pangrattato:

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

Edit:

Per quanto ne so, non è possibile impostare IsCurrentNode. Ma è possibile verificare se il nodo del menu è selezionata con il seguente codice (lo uso in maschera di visualizzazione SiteMapNodeModel):

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

Max, grazie mille! Questo risolve il problema di base dei nodi di secondo livello che scompaiono. Tuttavia, è comunque possibile che il nodo di secondo livello sia impostato su IsCurrentNode quando questo accade? Ad esempio, vorrei che il nodo Elenco membri fosse visualizzato come selezionato nella pagina Dettagli membro. In caso contrario, non è un grosso problema ... solo una richiesta estetica. – bigmac

1

Aggiungendo alla risposta di Max Vorrei anche creare un metodo di estensione per SiteMapNodeModel.Che si potrebbe usare per implementare tutta la logica personalizzata necessaria per fare questo:

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") 
    } 
} 

e modificare il modello di visualizzazione di conseguenza:

/* 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

seguito alla risposta di Max Kiselev, se si desidera utilizzare tale tecnica, ma essere in grado di utilizzare gli attributi sulle azioni di controllo, ho fatto la seguente:

Definire un provider di visibilità personalizzato:

public class AlwaysInvisibleVisibilityProvider : ISiteMapNodeVisibilityProvider 
{ 
    public bool IsVisible(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata) 
    { 
     return false; 
    } 
} 

Poi sottoclasse MvcSiteMapNodeAttribute:

public class InvisibleMvcSiteMapNodeAttribute : MvcSiteMapNodeAttribute 
{ 
    public InvisibleMvcSiteMapNodeAttribute(string key, string parentKey) 
    { 
     Key = key; 
     ParentKey = parentKey; 
     VisibilityProvider = typeof (AlwaysInvisibleVisibilityProvider).AssemblyQualifiedName; 
    } 
} 

E quindi è possibile utilizzarlo su vostre azioni del controller:

[HttpGet] 
[InvisibleMvcSiteMapNodeAttribute("ThisNodeKey", "ParentNodeKey")] 
public ViewResult OrderTimeout() 
{ 
    return View("Timeout"); 
} 
Problemi correlati