2012-03-30 9 views
7

En mi proyecto MVC3, he instalado V.3.2.1 MvcSiteMapProvider de Maartenba y tengo un menú muy sencillo, estática, de dos niveles que he creado . A continuación se muestra la estructura del mapa conceptual.MvcSiteMapProvider - Páginas múltiple necesidad de vincular a un nodo Menú

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

Ahora, hay muchos sub-páginas bajo Listado de miembros (por ejemplo, información, Editar, etc.), pero No desea que estos muestran como elementos del menú nivel 3 (sobre todo porque están atados a una identificación de miembro específica). Sin embargo, sí quiero que todas estas páginas de tercer nivel estén "vinculadas" al nodo de menú Lista de miembros para que se muestren como seleccionadas cuando estén en estas páginas.

tengo el siguiente código en mi archivo 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> 

Para hacer que el menú, estoy usando el siguiente código en mi archivo _Layout.cshtml:

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

Por último, he modificado el archivo SiteMapNodeModel.cshtml por lo que añade una clase "selectedMenuItem" al nodo que se correlaciona con la página el usuario está viendo. Aquí está el snippit que representa el nodo del menú.

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

La visualización y navegación del mapa funciona bien, hasta que navego más hacia el área de miembros. Por ejemplo, si voy allá Members/Member/List (que muestra el menú correctamente) y a una página como Members/Member/Detail/1, los nodos hijos menores de Centro de usuarios ("Listado Miembro", "Calendario de Eventos", etc.) desaparecen. Por lo tanto, aquí están mis dos problemas que tengo con mi código actual:

  1. quiero especificar que una determinada página es parte del nodo del menú principal "Centro de usuarios", de manera que los nodos del menú infantil de " Centro de miembros "se mostrará, independientemente de si la página dada se define como un nodo específico en la estructura del menú.

  2. que desea especificar (posiblemente en la vista o controlador de acción) que una página específica debe estar atado a un nodo de menú específico. Por ejemplo, cuando el usuario está en Members/Member/Detail/1, simplemente quiero el nodo hijo "Listado Miembro" que se especifica como IsCurrentNode de manera que el archivo SiteMapNodeModel.cshtml adecuadamente decora con la clase "selectedMenuItem".

¿Alguna sugerencia?

Respuesta

6

Puede añadir nodos 3er nivel con el mapa de sitio XML y especificar la visibilidad de ocultarlos en el menú. Aquí está la declaración de nodo para mostrar que sólo en el pan rallado:

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

Editar:

Por lo que yo sé, no se puede establecer IsCurrentNode. Sin embargo, se puede comprobar si el nodo de menú está seleccionado actualmente con el siguiente código (lo uso en la plantilla de visualización SiteMapNodeModel):

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

Max, muchas gracias! Eso resuelve el problema básico de la desaparición de los nodos de segundo nivel. Sin embargo, ¿hay alguna forma de que sepa que el nodo del segundo nivel está configurado en IsCurrentNode cuando esto sucede? Por ejemplo, me gustaría que el nodo Listado de miembros se muestre como seleccionado cuando se encuentre en la página Detalles del miembro. Si no, no es un gran problema ... solo una solicitud estética. – bigmac

1

Agregando a la respuesta de Max también me gustaría crear un método de extensión para SiteMapNodeModel.Que se podría utilizar para implementar toda la lógica personalizada necesaria para hacer esto:

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

y cambiar la plantilla de visualización en consecuencia:

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

con la respuesta de Max Kiselev, si desea utilizar esa técnica, pero ser capaz de utilizar los atributos de sus acciones del controlador, hice lo siguiente:

definir un proveedor de visibilidad personalizada:

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

Entonces subclase MvcSiteMapNodeAttribute:

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

Y a continuación, puede usarlo en sus acciones del controlador:

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