En Bootstrap, la active
clase debe aplicarse al <li>
elemento y no al <a>
. Vea el primer ejemplo aquí: http://getbootstrap.com/components/#navbar
La forma en que maneja su estilo de UI en función de lo que está activo o no tiene nada que ver con el ActionLink
asistente de ASP.NET MVC . Esta es la solución adecuada para seguir cómo se creó el marco Bootstrap.
<ul class="nav navbar-nav">
<li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Editar:
Como lo más probable es que reutilice su menú en varias páginas, sería inteligente tener una manera de aplicar esa clase seleccionada automáticamente en función de la página actual en lugar de copiar el menú varias veces y hacerlo manualmente.
La forma más fácil es simplemente usar los valores contenidos ViewContext.RouteData
, es decir, los valores Action
y Controller
. Podríamos construir sobre lo que tiene actualmente con algo como esto:
<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
No es bonito en el código, pero hará el trabajo y le permitirá extraer su menú en una vista parcial si lo desea. Hay maneras de hacer esto de una manera mucho más limpia, pero como recién está comenzando, lo dejaré así. ¡Mucha suerte aprendiendo ASP.NET MVC!
Edición tardía:
Esta pregunta parece estar obteniendo un poco de tráfico, así que pensé que agregaría una solución más elegante usando una HtmlHelper
extensión.
Editar 24/03/2015: Tuve que reescribir este método para permitir que múltiples acciones y controladores desencadenaran el comportamiento seleccionado, así como el manejo cuando se llama al método desde una vista parcial de acción secundaria, ¡pensé que compartiría la actualización!
public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
ViewContext viewContext = html.ViewContext;
bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;
if (isChildAction)
viewContext = html.ViewContext.ParentActionViewContext;
RouteValueDictionary routeValues = viewContext.RouteData.Values;
string currentAction = routeValues["action"].ToString();
string currentController = routeValues["controller"].ToString();
if (String.IsNullOrEmpty(actions))
actions = currentAction;
if (String.IsNullOrEmpty(controllers))
controllers = currentController;
string[] acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
string[] acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();
return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
cssClass : String.Empty;
}
Funciona con .NET Core:
public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;
IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');
return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
cssClass : String.Empty;
}
Uso de la muestra:
<ul>
<li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
<a href="@Url.Action("Home", "Default")">Home</a>
</li>
<li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
<a href="@Url.Action("List", "Default")">List</a>
</li>
</ul>