So fügen Sie Html.ActionLink in ASP.NET MVC eine "aktive" Klasse hinzu


128

Ich versuche, meiner Bootstrap-Navigationsleiste in MVC eine "aktive" Klasse hinzuzufügen, aber im Folgenden wird die aktive Klasse nicht angezeigt, wenn sie so geschrieben wird:

<ul class="nav navbar-nav">
  <li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Dies wird in eine korrekt formatierte Klasse aufgelöst, funktioniert jedoch nicht:

<a class="active" href="/">Home</a>

In der Bootstrap-Dokumentation heißt es, dass 'a'-Tags nicht in der Navigationsleiste verwendet werden sollten, aber ich glaube, dass dies die richtige Methode ist, um eine Klasse zu einem Html.ActionLink hinzuzufügen. Gibt es eine andere (ordentliche) Möglichkeit, dies zu tun?


3
Der Code, der aufgelöst wird, enthält class = active. Ist es nicht das, was du in deiner Frage sagst? Wie Sie Ihren Code haben, ist, wie ich Klassen hinzufüge
Matt Bodily

du bist nicht zu klar !!! Ich verstehe nicht genau, was das Problem ist, wenn ich es zu nav hinzufüge, obwohl ich das Gefühl habe, dass es in Ordnung sein sollte
JC Lizard

1
Was ist das Problem mit dem gelösten Code? Was erwarten Sie? Können Sie genauer sein als "scheint nicht zu funktionieren"? Ihre Frage ist nicht klar genug, um Ihnen im Moment zu helfen.
Dom

Bearbeitet! Entschuldigung, ich meinte, dass die "aktive" Klasse überhaupt nicht angezeigt wird
Gillespie

2
Ich habe nur einen Blick auf die Dokumente von Bootstrap geworfen und denke, Sie müssen die activeKlasse dem liElement hinzufügen , nicht dem a. Sehen Sie das erste Beispiel hier: getbootstrap.com/components/#navbar
dom

Antworten:


299

In Bootstrap muss die activeKlasse auf das <li>Element und nicht auf das Element angewendet werden <a>. Das erste Beispiel finden Sie hier: http://getbootstrap.com/components/#navbar

Die Art und Weise, wie Sie mit Ihrem UI-Stil umgehen, basierend darauf, was aktiv ist oder nicht, hat nichts mit dem ActionLinkHelfer von ASP.NET MVC zu tun . Dies ist die richtige Lösung, um zu verfolgen, wie das Bootstrap-Framework erstellt wurde.

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

Bearbeiten:

Da Sie Ihr Menü höchstwahrscheinlich auf mehreren Seiten wiederverwenden werden, wäre es klug, diese ausgewählte Klasse automatisch auf der Grundlage der aktuellen Seite anzuwenden, anstatt das Menü mehrmals zu kopieren und manuell auszuführen.

Am einfachsten ist es, einfach die darin enthaltenen Werte zu verwenden ViewContext.RouteData, nämlich die Werte Actionund Controller. Mit so etwas könnten wir auf dem aufbauen, was Sie derzeit haben:

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

Es ist nicht schön im Code, aber es erledigt den Job und ermöglicht es Ihnen, Ihr Menü in eine Teilansicht zu extrahieren, wenn Sie möchten. Es gibt Möglichkeiten, dies viel sauberer zu machen, aber da Sie gerade erst anfangen, lasse ich es dabei. Viel Glück beim Lernen von ASP.NET MVC!


Späte Bearbeitung:

Diese Frage scheint ein wenig Verkehr zu bekommen, also dachte ich mir, ich würde eine elegantere Lösung mit einer HtmlHelperErweiterung einführen.

Bearbeiten 24.03.2015: Diese Methode musste neu geschrieben werden, um mehrere Aktionen und Controller zu ermöglichen, die das ausgewählte Verhalten auslösen, sowie die Behandlung, wenn die Methode aus einer Teilansicht einer untergeordneten Aktion aufgerufen wird. Ich dachte, ich würde das Update freigeben!

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;
}

Funktioniert mit .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;
}

Beispielnutzung:

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

Vielen Dank, wie ich bereits erwähnte, hatte ich es ursprünglich so, aber ich hatte gehofft, in meinem gesamten Code eine Methode zum Ändern der "aktiven" Klasse zwischen ausgewählten Objekten zu haben.
Gillespie

2
@ Gillespie keine Sorge! Ich habe meine Antwort bearbeitet, um einige Informationen hinzuzufügen, die Ihnen ein bisschen mehr helfen könnten.
Dom

5
In Bezug auf die erste Bearbeitung funktionierte es tatsächlich nur für die Indexseite. Der Grund scheint zu sein, dass der Vergleich fehlgeschlagen ist, da ViewContext.RouteData.Values ​​["Aktion"] kein Objekt vom Typ String zurückgibt (weiß immer noch nicht, wie es für die erste Seite funktioniert hat ....) . Als ich alle ViewContext.RouteData.Values ​​["Aktion"] in ViewContext.RouteData.Values ​​["Aktion"] in toString () geändert habe, funktionierte dies für alle Seiten. Vielleicht möchten Sie dies in Ihre Lösung aufnehmen, falls jemand das gleiche Problem hat.
user3281466

2
@LonelyPixel Vielleicht funktioniert diese Antwort für Sie?
Dom

1
Für VB.NET-Benutzer: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Home "," Index "," Home ") </ li>
Andrea Antonangeli

28

Erweiterung:

public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
    var context = html.ViewContext;
    if (context.Controller.ControllerContext.IsChildAction)
        context = html.ViewContext.ParentActionViewContext;
    var routeValues = context.RouteData.Values;
    var currentAction = routeValues["action"].ToString();
    var currentController = routeValues["controller"].ToString();

    var str = String.Format("<li role=\"presentation\"{0}>{1}</li>",
        currentAction.Equals(action, StringComparison.InvariantCulture) &&
        currentController.Equals(controller, StringComparison.InvariantCulture) ?
        " class=\"active\"" :
        String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
    );
    return new MvcHtmlString(str);
}

Verwendung:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>

1
Dies ist eine sehr effiziente Erweiterung. Funktioniert perfekt und ist sehr elegant. Hut ab vor dir, Prof! Mein einziger Kritikpunkt ist der role="presentation", der für ein primäres Navigationsmenü ( john.foliot.ca/aria-hidden/#pr ) überhaupt nicht geeignet ist . Eine ungeordnete Liste ist ein geeigneter Container für einen verwandten Satz von Links, da sie auf logische Weise zusammengefasst werden.
René Kåbis

@ René Kåbis es für Bootstrap Naigation getbootstrap.com/components/#nav-tabs
Prof

1
Dies funktioniert nicht, wenn der Benutzer die URL manuell in Kleinbuchstaben oder Großbuchstaben eingibt, z. " domain.com/Login " und " domain.com/LOGIN ". Für die Lösung var str = String.Format("<li role=\"presentation\"{0}>{1}</li>", currentAction.toLower().Equals(action.toLower(), StringComparison.InvariantCulture) && currentController.toLower().Equals(controller.toLower(), StringComparison.InvariantCulture) ? " class=\"active\"" : String.Empty, html.ActionLink(text, action, controller).ToHtmlString() );
sky91

20

Ich habe dies durch Hinzufügen eines View-Bag-Parameters in asp.net mvc erreicht. Hier, was habe ich getan

ViewBag.Current = "Scheduler";Like-Parameter auf jeder Seite hinzugefügt

In der Layoutseite

<ul class="nav navbar-nav">
     <li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
 </ul>

Dies löste mein Problem.


Einfache und einfache Lösung.
Japes Sophey

13

Kann etwas spät sein. Aber hoffe das hilft.

public static class Utilities
{
    public static string IsActive(this HtmlHelper html, 
                                  string control,
                                  string action)
    {
        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeControl = (string)routeData.Values["controller"];

        // both must match
        var returnActive = control == routeControl &&
                           action == routeAction;

        return returnActive ? "active" : "";
    }
}

Und Verwendung wie folgt:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li class='@Html.IsActive("Home", "Index")'>
            @Html.ActionLink("Home", "Index", "Home")
        </li>
        <li class='@Html.IsActive("Home", "About")'>
            @Html.ActionLink("About", "About", "Home")
        </li>
        <li class='@Html.IsActive("Home", "Contact")'>
            @Html.ActionLink("Contact", "Contact", "Home")
        </li>
    </ul>
</div>

Referenz von http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html


1
Sehr einfache und elegante Lösung. Ich habe hier einige Verbesserungen vorgenommen: gist.github.com/jean-rakotozafy/… , um ein Menü für alle Controller-Aktionen hervorzuheben.
Zan RAKOTO

5

Ich weiß, dass diese Frage alt ist, aber ich möchte hier nur meine Stimme hinzufügen. Ich halte es für eine gute Idee, das Wissen darüber zu belassen, ob ein Link zum Controller der Ansicht aktiv ist oder nicht.

Ich würde nur einen eindeutigen Wert für jede Ansicht in der Controller-Aktion festlegen. Wenn ich beispielsweise den Link zur Startseite aktivieren möchte, würde ich Folgendes tun:

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}

Dann werde ich aus meiner Sicht so etwas schreiben:

<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>

Wenn Sie zu einer anderen Seite navigieren, z. B. Programme, ist ViewBag.Home nicht vorhanden (stattdessen ViewBag.Programs). Daher wird nichts gerendert, nicht einmal class = "". Ich denke, dies ist sowohl aus Gründen der Wartbarkeit als auch der Sauberkeit sauberer. Ich neige dazu, die Logik immer so weit wie möglich aus dem Blickfeld zu lassen.


4

In Anbetracht dessen, was Damith gepostet hat, denke ich, dass Sie sich nur für Viewbag.Title als aktiv qualifizieren können (es wird empfohlen , dies auf Ihren Inhaltsseiten zu platzieren, damit Ihre _Layout.cshtmlSeite Ihre Linkleisten enthält ). Beachten Sie auch, dass bei Verwendung von Untermenüelementen auch Folgendes funktioniert:

<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
    <a href="javascript:;">
        <b class="caret"></b>
        <i class="fa fa-th-large"></i>
        <span>Dashboard</span>
    </a>
    <ul class="sub-menu">
        <li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html">Dashboard v1</a></li>
        <li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html">Dashboard v2</a></li>
    </ul>
</li>

Sauber und effizient!
mggluscevic

3

Ich habe Doms "nicht hübsche" Antwort geändert und sie hässlicher gemacht. Manchmal haben zwei Controller die widersprüchlichen Aktionsnamen (dh Index), also mache ich das:

<ul class="nav navbar-nav">
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

3

Sie können dies versuchen: In meinem Fall lade ich ein Menü aus einer Datenbank basierend auf rollenbasiertem Zugriff. Schreiben Sie den Code in jede Ansicht, welches Menü Sie basierend auf Ihrer Ansicht aktivieren möchten.

<script type="text/javascript">
        $(document).ready(function () {         
            $('li.active active-menu').removeClass('active active-menu');
            $('a[href="https://stackoverflow.com/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
        });
</script>

3

Diese Lösung ist für Asp.net MCV 5 einfach.

  1. Erstellen Sie beispielsweise eine statische Klasse Utilitarios.cs.

  2. Erstellen Sie innerhalb der Klasse eine statische Methode:

    public static string IsLinkActive(this UrlHelper url, string action, string controller)
    {
        if (url.RequestContext.RouteData.Values["controller"].ToString() == controller &&
            url.RequestContext.RouteData.Values["action"].ToString() == action)
        {
            return "active";
        }
    
        return "";
    }
  3. so anrufen

    <ul class="sidebar-menu" data-widget="tree">
        <li class="header">HEADER</li>
        <li class="@Url.IsLinkActive("Index", "Home")">
            <a href="@Url.Action("Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a>
        </li>
        <li class="@Url.IsLinkActive("About", "Home")">
            <a href="@Url.Action("About", "Home")"><i class="fa fa-link"></i><span>About</span></a>
        </li>
    </ul>

3

ASP.NET Core & Bootstrap 4

Die aktuellste Antwort

Ich habe die saubere Lösung von @crush für eine aktualisierte, ASP.NET Core- und Bootstrap 4- kompatible Methode überarbeitet, um dieses Problem basierend auf einer IHtmlHelperErweiterungsmethode zu lösen :

public static class LinkExtensions
{
    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        var routeData = html.ViewContext.RouteData;
        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        using (var writer = new StringWriter())
        {
            writer.WriteLine($"<li class='nav-item {(active ? "active" : "")}'>");
            html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes).WriteTo(writer, HtmlEncoder.Default);
            writer.WriteLine("</li>");
            return new HtmlString(writer.ToString());
        }
    }
}

Verwendung

<nav class="navbar">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav">
            @Html.ActiveActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("About", "About", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("Contact", "Contact", "TimeTracking", null, new { @class = "nav-link" })
        </ul>
    </div>
</nav>

1
Sehr gute Lösung. Wie kann ich in Ihrem Beispiel "Kontakt" standardmäßig als aktiv festlegen?
Md. Suman Kabir

1
Danke dir. Das Gute ist, dass Sie kein aktives Element festlegen müssen. Sobald die Seite 'Kontakt' besucht wird, ActiveActionLink()wird die aktive Klasse auf die <li>:-)
WoIIe

Wo überprüfen Sie den Bereich?
Mohammad

@Mohammad verstehe ich nicht. Könnten Sie bitte Ihre Frage näher erläutern?
WoIIe

In der LinkExtensions-Klasse haben Sie keinen Bereich von routeData erhalten!
Mohammad

3

Einfache ASP.NET Core 3.0 und TagHelpers

[HtmlTargetElement("li", Attributes = "active-when")]
public class LiTagHelper : TagHelper
{
    public string ActiveWhen { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (ActiveWhen == null)
            return;

        var targetController = ActiveWhen.Split("/")[1];
        var targetAction = ActiveWhen.Split("/")[2];

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

In Ihre _ViewImports.cs aufnehmen:

@addTagHelper *, YourAssemblyName

Verwendung:

 <li active-when="/Home/Index">

2

Fügen Sie '.ToString' hinzu, um den Vergleich unter ASP.NET MVC zu verbessern

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

- -


Dies funktioniert nicht, wenn in zwei verschiedenen Controllern dieselben Aktionsnamen vorhanden sind. Testen Sie es mit Home- und About-Controllern mit Index-Aktion.
Hyde

Sie könnten Funktionsserver auf Rasiermesser wie: @functions { public bool IsActive(string action, string controller) { var actionRoute = ViewContext.RouteData.Values["Action"].ToString(); var controlRoute = ViewContext.RouteData.Values["Controller"].ToString(); return controller.Equals(controlRoute)&& actionRoute.Equals(actionRoute); } }und Verwendung definieren: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung

2

Wir können auch UrlHelperaus RequestContext erstellen, das wir von MvcHandler selbst erhalten können. Daher glaube ich, dass jemand, der diese Logik in Razor-Vorlagen wie folgt beibehalten möchte, hilfreich wäre:

  1. Erstellen Sie im Projektstamm einen Ordner mit dem Namen AppCode.
  2. Erstellen Sie dort eine Datei mit dem Namen HtmlHelpers.cshtml
  3. Erstellen Sie dort einen Helfer:

    @helper MenuItem(string action, string controller)
    {
         var mvcHandler = Context.CurrentHandler as MvcHandler;
         if (mvcHandler != null)
         {
             var url = new UrlHelper(mvcHandler.RequestContext);
             var routeData = mvcHandler.RequestContext.RouteData;
             var currentAction = routeData.Values["action"].ToString();
             var currentController = routeData.Values["controller"].ToString();
             var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) &&
                             string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase);
    
            <div class="@(isCurrent ? "active" : "")">
                <div>@url.Action(action, controller)</div>
            </div>
         }   
    }
  4. Dann können wir unsere Ansichten wie folgt verwenden:

    @HtmlHelpers.MenuItem("Default", "Home")

Hoffe, dass es jemandem hilft.


Das ist wirklich cool. Gibt es hier Leistungsnachteile?
Crush

@crush, ich habe es nicht gemessen, aber ich würde erwarten, dass es nur geringe Auswirkungen auf die Leistung hat, da ich denke, dass das Framework eine ähnliche Logik verwendet, um UrlHelperdas zu erstellen , in dem Sie sich befinden Controller.Url. Das Einzige ist, dass wir wahrscheinlich nicht UrlHelperfür jeden Aufruf das Erstellen ausführen möchten, MenuItemsodass wir nach dem ersten Aufruf des Helfers möglicherweise ein Häkchen beim Speichern in HttpContext-Elementen anwenden, sodass wir dies nur einmal pro Anforderung tun.
Oleksii Aza

2

ist mit einer Lambda-Funktion möglich

@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
    Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}

dann Verwendung

 @Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})

2

Ich habe eine HtmlHelperErweiterung erstellt, die eine ActiveActionLinkMethode für diejenigen unter Ihnen hinzufügt, die die "aktive" Klasse eher zum Link selbst als zur <li>Umgebung des Links hinzufügen möchten .


public static class LinkExtensions
{
    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        const string activeClassName = "active";

        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        if (active)
        {
            var @class = (string)htmlAttributes["class"];

            htmlAttributes["class"] = string.IsNullOrEmpty(@class)
                ? activeClassName
                : @class + " active";
        }

        var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        return link;
    }
}

Die Verwendung ist wie folgt:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })

1

Die Antwort von @dombenoit funktioniert. Es wird jedoch Code eingeführt, der gewartet werden muss. Überprüfen Sie diese Syntax:

using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
    @nav.ActionLink("Link 1", "action1")
    @nav.ActionLink("Link 2", "action2")
    @nav.Link("External Link", "#")
}

Beachten Sie die Verwendung der .SetLinksActiveByControllerAndAction()Methode.

Wenn Sie sich fragen, was diese Syntax ermöglicht, lesen Sie TwitterBootstrapMVC


Vielen Dank für die Antwort Dmitry, ich teste TwitterBootstrapMVC
Gillespie

1

Ich suchte auch nach einer Lösung und jQuery half ziemlich viel. Zuerst müssen Sie Ihren <li>Elementen IDs geben .

<li id="listguides"><a href='/Guides/List'>List Guides</a></li>

Nachdem Sie dies auf Ihrer Layoutseite getan haben, können Sie jQuery mitteilen, welches <li>Element in Ihrer Ansicht ausgewählt werden soll.

@section Scripts{
    <script type="text/javascript">
        $('#listguides').addClass('selected');
    </script>
}

Hinweis: Sie müssen @RenderSection("scripts", required: false)Ihre Layoutseite direkt vor dem </body>Tag haben, um diesen Abschnitt hinzuzufügen.


1

Ich möchte diese Lösung vorschlagen, die auf dem ersten Teil von Doms Antwort basiert.

Wir definieren zunächst zwei Variablen, "action" und "controller", und verwenden sie, um die aktive Verbindung zu bestimmen:

{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}

Und dann:

<ul class="nav navbar-nav">
    <li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Jetzt sieht es besser aus und es sind keine komplexeren Lösungen erforderlich.


0

Wenn es überhaupt nicht angezeigt wird, ist der Grund, dass Sie zwei @ -Zeichen benötigen:

@@class

ABER ich glaube, Sie müssen möglicherweise die aktive Klasse auf dem "li" -Tag haben, nicht auf dem "a" -Tag. laut Bootstrap-Dokumenten ( http://getbootstrap.com/components/#navbar-default ):

<ul class="nav navbar-nav">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#">Profile</a></li>
  <li><a href="#">Messages</a></li>
</ul>

Daher lautet Ihr Code:

<ul class="nav navbar-nav">
  <li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Die Klasse @@ gibt einen Fehler aus. Ich hatte ursprünglich Ihr Codebeispiel oben, das funktioniert, aber nicht genau so ist, wie Actionlinks "sein sollten".
Gillespie

bearbeitet. Das @@ ist nicht erforderlich. Sie müssen die Klasse auf die EA
JC Lizard

0

Hoffe das hilft, unten ist, wie Ihr Menü sein kann:

 <ul class="nav navbar-nav">
   <li><a href="@Url.Action("Index", "Home")" class="@IsMenuSelected("Index","Home", "active")">Home</a></li>
   <li><a href="@Url.Action("About", "Home")" class="@IsMenuSelected("About", "Home", "active")">About</a></li>
   <li><a href="@Url.Action("Contact", "Home")" class="@IsMenuSelected("Contact", "Home", "active")">Contact</a></li>
 </ul>

Und fügen Sie unterhalb der MVC-Hilfsfunktion unterhalb des HTML-Tags hinzu.

 @helper IsMenuSelected(string actionName, string controllerName, string className)
    {
            var conname = ViewContext.RouteData.Values["controller"].ToString().ToLower();
            var actname = ViewContext.RouteData.Values["action"].ToString().ToLower();

            if (conname == controllerName.ToLower() && actname == actionName.ToLower())
        {
            @className;
        }
    }

Ich habe die Antwort von http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/ weitergeleitet.


0

Ich erkannte, dass dieses Problem für einige von uns ein häufiges Problem war, und veröffentlichte meine eigene Lösung mit dem Nuget-Paket. Unten sehen Sie, wie es funktioniert. Ich hoffe das wird nützlich sein.

Hinweis: Dieses Nuget-Paket ist mein erstes Paket. Wenn Sie also einen Fehler sehen, geben Sie bitte Feedback. Danke dir.

  1. Installieren Sie das Paket oder laden Sie den Quellcode herunter und fügen Sie Ihr Projekt hinzu

    -Install-Package Betalgo.MvcMenuNavigator
  2. Fügen Sie Ihre Seiten einer Aufzählung hinzu

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Setzen Sie Filter oben auf Ihren Controller oder Ihre Aktion

    [MenuNavigator(HeaderTop.Product, HeaderSub.Index)]
    public class ProductsController : Controller
    {
        public async Task<ActionResult> Index()
        {
            return View();
        }
    
        [MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)]
        public async Task<ActionResult> Dashboard()
        {
            return View();
        }
    }
  4. Und verwenden Sie es in Ihrem Header-Layout so

    @{
    var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop;
    var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub;
    }
    <div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse">
    <ul class="nav navbar-nav">
        <li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")">
            <a href="@Url.Action("Index","Home")">Dashboard</a>
        </li>
        <li class="@(headerTop==HeaderTop.Product?"active selected open":"")">
            <a href="@Url.Action("Index", "Products")">Products</a>
        </li>
    </ul>

Weitere Informationen: https://github.com/betalgo/MvcMenuNavigator


0

Ich glaube, hier ist ein sauberer und kleinerer Code, um das ausgewählte Menü "aktiv" zu machen:

 <ul class="navbar-nav mr-auto">
                <li class="nav-item @Html.IfSelected("Index")">
                    <a class="nav-link" href="@Url.Action("Index", "Home")">Home</a>
                </li>
                <li class="nav-item @Html.IfSelected("Controls")">
                    <a class="nav-link" href="@Url.Action("Controls", "Home")">MVC Controls</a>
                </li>
                <li class="nav-item @Html.IfSelected("About")">
                    <a class="nav-link" href="@Url.Action("About", "Home")">About</a>
                </li>
</ul>

 public static string IfSelected(this HtmlHelper html, string action)
        {
            return html
                       .ViewContext
                       .RouteData
                       .Values["action"]
                       .ToString() == action
                            ? " active"
                            : "";
        }

Schön, obwohl wahrscheinlich in einigen Fällen für Controller & Bereich erweitert werden muss
planetClaire

-1

Ich habe oben eine Kombination von Antworten gemacht und meine Lösung gefunden.

So..

Erstellen Sie zuerst im Rasiermesserblock eine Zeichenfolgenvariable, die den Namenswert des Controllers und die vom Benutzer aufgerufene Aktion enthält.

    @{
        string controllerAction =  ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString(); 
    }

Verwenden Sie dann eine Kombination aus HTML- und Razor-Code:

    <ul class="nav navbar-nav">
        <li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
        <li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
        <li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
    </ul>

Ich denke, das ist gut, weil Sie nicht jedes Mal auf "ViewContext.RouteData.Values" zugreifen müssen, um den Controller-Namen und den Aktionsnamen zu erhalten.


-1

Meine Lösung für dieses Problem ist

<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
                <a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
            </li>

Ein besserer Weg könnte darin bestehen, eine HTML-Erweiterungsmethode hinzuzufügen, um den aktuellen Pfad zurückzugeben, der mit dem Link verglichen werden soll


-1

Ich war das:

Einen Helfer in der Menü-Teilansicht gemacht

 @helper RouterLink(string action, string controller)
{
    var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
    <text>href="@Url.Action(action, controller)"</text>if (IsActive){ <text>class="active"</text>}
}

Verwenden Sie es dann im Ankertag wie folgt:

<li><a @RouterLink("Index","Home")>Home</a></li>

Meine Anwendung hatte keine Bereiche, kann aber auch als weitere Variable in die Hilfsfunktion aufgenommen werden. Und ich musste die aktive Klasse aus meiner Sicht an das Ankertag übergeben. Aber likann auch so konfiguriert werden.


1
Sie sehen, Downvote hilft nicht wirklich, wenn Sie den Grund nicht erwähnen.
Anup Sharma
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.