Bagaimana cara menambahkan kelas "aktif" ke Html.ActionLink di ASP.NET MVC

128

Saya mencoba menambahkan kelas "aktif" ke navbar bootstrap saya di MVC, tetapi berikut ini tidak menunjukkan kelas aktif ketika ditulis seperti ini:

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

Ini mengatasi apa yang tampak seperti kelas yang diformat dengan benar, tetapi tidak berfungsi:

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

Dalam dokumentasi Bootstrap itu menyatakan bahwa tag 'a' tidak boleh digunakan di navbar, tetapi di atas adalah bagaimana saya percaya adalah cara yang benar untuk menambahkan kelas ke Html.ActionLink. Apakah ada cara lain (rapi) yang bisa saya lakukan ini?

Gillespie
sumber
3
kode yang menyelesaikan memiliki class = aktif di dalamnya. Bukankah itu yang Anda katakan Anda inginkan dalam pertanyaan Anda? Bagaimana Anda memiliki kode Anda adalah bagaimana saya menambahkan kelas
Matt Bodily
kamu tidak terlalu jelas !!! Saya tidak benar-benar mengerti apa masalahnya menambahkannya ke nav, meskipun saya merasa, cara itu seharusnya baik
JC Lizard
1
Apa masalah dengan kode yang diselesaikan? Apa yang kamu harapkan Bisakah Anda lebih spesifik daripada "sepertinya tidak berhasil"? Pertanyaan Anda tidak cukup jelas untuk membantu Anda saat ini.
dom
Diedit! maaf, yang saya maksudkan adalah bahwa kelas "aktif" tidak muncul sama sekali
Gillespie
2
Hanya melirik dokumen Bootstrap dan saya pikir Anda perlu menambahkan activekelas ke lielemen, bukan a. Lihat contoh pertama di sini: getbootstrap.com/components/#navbar
dom

Jawaban:

300

Di Bootstrap activekelas perlu diterapkan ke <li>elemen dan bukan <a>. Lihat contoh pertama di sini: http://getbootstrap.com/components/#navbar

Cara Anda menangani gaya UI Anda berdasarkan apa yang aktif atau tidak tidak ada hubungannya dengan ActionLinkpembantu ASP.NET MVC . Ini adalah solusi yang tepat untuk mengikuti bagaimana kerangka kerja Bootstrap dibangun.

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

Edit:

Karena Anda kemungkinan besar akan menggunakan kembali menu Anda di beberapa halaman, akan lebih baik untuk memiliki cara untuk menerapkan kelas yang dipilih secara otomatis berdasarkan halaman saat ini daripada menyalin menu beberapa kali dan melakukannya secara manual.

Cara termudah adalah dengan hanya menggunakan nilai yang terkandung di dalamnya ViewContext.RouteData, yaitu nilai Actiondan Controller. Kami dapat mengembangkan apa yang saat ini Anda miliki dengan sesuatu seperti ini:

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

Itu tidak cantik dalam kode, tetapi itu akan menyelesaikan pekerjaan dan memungkinkan Anda untuk mengekstrak menu Anda ke tampilan parsial jika Anda suka. Ada beberapa cara untuk melakukan ini dengan cara yang jauh lebih bersih, tetapi karena Anda baru memulai saya akan membiarkannya begitu saja. Semoga sukses belajar ASP.NET MVC!


Edit terlambat:

Pertanyaan ini tampaknya mendapatkan sedikit lalu lintas jadi saya pikir saya akan memberikan solusi yang lebih elegan menggunakan HtmlHelperekstensi.

Sunting 03-24-2015: Harus menulis ulang metode ini untuk memungkinkan beberapa tindakan dan pengendali memicu perilaku yang dipilih, serta menangani ketika metode ini dipanggil dari tampilan parsial aksi anak, pikir saya akan berbagi pembaruan!

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

Bekerja dengan .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;
}

Penggunaan sampel:

<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>
dom
sumber
Terima kasih, seperti yang saya sebutkan ini adalah bagaimana saya memilikinya pada awalnya, tetapi saya berharap memiliki satu metode di seluruh kode saya untuk mengubah kelas "aktif" antara objek yang dipilih.
Gillespie
2
@Gillespie jangan khawatir! Saya telah mengedit jawaban saya untuk menambahkan beberapa info yang mungkin sedikit membantu Anda.
dom
5
Sehubungan dengan pengeditan pertama, sebenarnya hanya berfungsi untuk halaman Indeks. Tampaknya alasannya adalah bahwa ketika membuat perbandingan, gagal sebagai ViewContext.RouteData.Values ​​["Action"] tidak mengembalikan objek tipe String (masih tidak tahu cara kerjanya untuk halaman pertama ....) . Ketika saya mengubah semua ViewContext.RouteData.Values ​​["Action"] menjadi ViewContext.RouteData.Values ​​["Action"]. ToString (), itu berfungsi untuk semua halaman. Mungkin ingin menambahkan ini dalam solusi Anda kalau-kalau seseorang mengalami masalah yang sama.
user3281466
2
@LonelyPixel mungkin jawaban ini cocok untuk Anda?
dom
1
Untuk pengguna VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Indeks "," active "," "))"> @ Html.ActionLink (" Home "," Index "," Home ") </li>
Andrea Antonangeli
28

Perpanjangan:

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

Pemakaian:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>
Prof.
sumber
1
Ini adalah ekstensi yang sangat efisien. Bekerja dengan sempurna dan cukup elegan. Angkat topi untukmu, Prof! Satu-satunya keluhan saya adalah dengan role="presentation", yang sama sekali tidak sesuai untuk menu navigasi utama ( john.foliot.ca/aria-hidden/#pr ). Daftar yang tidak terurut merupakan wadah yang tepat untuk serangkaian tautan terkait, karena mengelompokkannya bersama secara logis.
René Kåbis
@ René Kåbis untuk bootstrap naigation getbootstrap.com/components/#nav-tabs
Prof
1
Ini tidak berfungsi ketika pengguna secara manual memasukkan url dalam huruf kecil atau huruf besar, mis. " domain.com/Login " dan " domain.com/LOGIN ". Untuk solusinya, 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

Saya mengatur untuk melakukan ini dengan menambahkan parameter view bag di asp.net mvc. Inilah yang telah saya lakukan

Menambahkan ViewBag.Current = "Scheduler";parameter seperti di setiap halaman

Di halaman tata letak

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

Ini menyelesaikan masalah saya.

Damith
sumber
Solusi sederhana dan mudah.
japes Sophey
13

Mungkin sedikit terlambat. Tapi semoga ini membantu.

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

Dan penggunaannya sebagai berikut:

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

Dapatkan referensi dari http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html

Virag Dilip Desai
sumber
1
Solusi yang sangat sederhana dan elegan. Saya melakukan beberapa perbaikan di sini gist.github.com/jean-rakotozafy/... untuk menyorot menu untuk semua tindakan pengontrol.
Zan RAKOTO
5

Saya tahu pertanyaan ini sudah lama, tetapi saya hanya ingin menambahkan suara saya di sini. Saya percaya ini adalah ide yang bagus untuk meninggalkan pengetahuan tentang apakah suatu tautan aktif atau tidak ke pengontrol tampilan.

Saya hanya akan menetapkan nilai unik untuk setiap tampilan dalam aksi controller. Misalnya, jika saya ingin membuat tautan beranda aktif, saya akan melakukan sesuatu seperti ini:

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

Maka dalam pandangan saya, saya akan menulis sesuatu seperti ini:

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

Saat Anda menavigasi ke halaman yang berbeda, katakan Program, ViewBag.Rumah tidak ada (sebaliknya ViewBag.Program tidak); oleh karena itu, tidak ada yang ditampilkan, bahkan class = "". Saya pikir ini lebih bersih baik untuk perawatan dan kebersihan. Saya cenderung selalu ingin meninggalkan logika sejauh mungkin.

mapussah
sumber
4

Mengingat apa yang diposting Damith, saya pikir Anda hanya dapat memenuhi syarat aktif oleh Viewbag.Title (praktik terbaik adalah mengisi ini di halaman konten Anda memungkinkan halaman Anda _Layout.cshtmluntuk memegang bar tautan Anda). Perhatikan juga bahwa jika Anda menggunakan item sub-menu, itu juga berfungsi dengan baik:

<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>
Rafe Smith
sumber
Bersih dan efisien!
mggluscevic
3

Saya memodifikasi jawaban "tidak cantik" dom dan membuatnya lebih jelek. Terkadang dua pengendali memiliki nama tindakan yang saling bertentangan (yaitu Indeks) jadi saya melakukan ini:

<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>
PengembangDan
sumber
3

Anda dapat mencoba ini: Dalam kasus saya saya memuat menu dari basis data berdasarkan akses berbasis peran, Tulis kode pada setiap tampilan Anda yang ingin Anda aktifkan berdasarkan tampilan Anda.

<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>
atik sarker
sumber
3

Solusi ini sederhana untuk Asp.net MCV 5.

  1. Buat kelas statis, misalnya Utilitarios.cs.

  2. Di dalam Kelas buat metode statis:

    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. sebut seperti ini

    <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>
Deyvi Javier Saavedra Garcia
sumber
3

ASP.NET Core & Bootstrap 4

Jawaban terbaru

Saya telah bekerja kembali solusi rapi @crush untuk cara yang kompatibel , ASP.NET Core dan Bootstrap 4 yang diperbarui untuk menyelesaikan masalah ini berdasarkan IHtmlHelpermetode ekstensi:

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

Pemakaian

<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>
WoIIe
sumber
1
Solusi yang sangat bagus Dalam contoh Anda, bagaimana cara menetapkan 'Kontak' sebagai aktif secara default?
Md. Suman Kabir
1
Terima kasih. Hal baiknya adalah Anda tidak perlu mengatur elemen aktif. Segera setelah halaman 'Kontak' dikunjungi, ActiveActionLink()akan menerapkan kelas aktif ke <li>:-)
WoIIe
di mana Anda memeriksa area?
Mohammad
@Mohammad saya tidak mengerti. Bisakah Anda jelaskan pertanyaan Anda?
WoIIe
di kelas LinkExtensions Anda tidak mendapatkan area dari routeData!
Mohammad
3

ASP.NET Core 3.0 dan TagHelpers yang mudah

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

Sertakan dalam _ViewImports.cs Anda:

@addTagHelper *, YourAssemblyName

Pemakaian:

 <li active-when="/Home/Index">
Guilherme V.
sumber
2

Tambahkan '.ToString' untuk meningkatkan perbandingan pada ASP.NET MVC

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

-


sumber
Ini tidak akan berfungsi jika ada nama tindakan yang sama di dua pengontrol yang berbeda. Uji dengan Home dan About controller dengan tindakan Indeks.
Hyde
Anda dapat menentukan fungsi server pada pisau cukur seperti: @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); } }dan penggunaan: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung
2

Kita juga bisa membuat UrlHelperdari RequestContext yang bisa kita dapatkan dari MvcHandler itu sendiri. Karena itu saya percaya pada seseorang yang ingin menyimpan logika ini dalam template Razor dengan cara berikut ini akan sangat membantu:

  1. Di root proyek buat folder bernama AppCode.
  2. Buat file di sana bernama HtmlHelpers.cshtml
  3. Buat pembantu di sana:

    @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. Maka kita dapat menggunakan pandangan kita seperti ini:

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

Semoga bermanfaat bagi seseorang.

Oleksii Aza
sumber
Ini sangat keren. Apakah ada kekurangan kinerja di sini?
naksir
@ Crush, saya belum mengukurnya, tapi saya berharap itu memiliki dampak kinerja yang rendah karena saya pikir kerangka kerja menggunakan logika yang sama untuk membuat UrlHelperyang Anda miliki Controller.Url. Satu-satunya hal adalah bahwa kami mungkin tidak ingin mengeksekusi pembuatan UrlHelperuntuk setiap panggilan, MenuItemjadi kami dapat menerapkan tanda centang untuk menyimpannya ke dalam HttpContext Items setelah panggilan pertama ke helper sehingga kami melakukannya hanya sekali per permintaan.
Oleksii Aza
2

dimungkinkan dengan fungsi lambda

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

lalu penggunaan

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

Saya membuat HtmlHelperekstensi yang menambahkan ActiveActionLinkmetode bagi Anda yang ingin menambahkan kelas "aktif" ke tautan itu sendiri daripada <li>mengelilingi tautan.


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

Penggunaannya adalah sebagai berikut:

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

jawaban oleh @dombenoit berfungsi. Meskipun itu memperkenalkan beberapa kode untuk dipelihara. Lihat sintaks ini:

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

Perhatikan penggunaan .SetLinksActiveByControllerAndAction()metode.

Jika Anda bertanya-tanya apa yang membuat sintaks ini mungkin, lihat TwitterBootstrapMVC

Dmitry Efimenko
sumber
Terima kasih atas jawabannya Dmitry, saya menguji TwitterBootstrapMVC
Gillespie
1

Saya juga sedang mencari solusi dan jQuery cukup membantu. Pertama, Anda harus memberikan id ke <li>elemen Anda .

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

Setelah melakukan ini di halaman tata letak Anda, Anda dapat memberi tahu jQuery <li>elemen mana yang harus 'dipilih' dalam tampilan Anda.

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

Catatan: Anda harus memiliki @RenderSection("scripts", required: false)di halaman tata letak Anda, tepat sebelum </body>tag untuk menambahkan bagian itu.

Doğa Gençer
sumber
1

Saya ingin mengusulkan solusi ini yang didasarkan pada bagian pertama dari jawaban Dom.

Kami pertama-tama mendefinisikan dua variabel, "action" dan "controller" dan menggunakannya untuk menentukan tautan aktif:

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

Lalu:

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

Sekarang terlihat lebih bagus dan tidak perlu solusi yang lebih kompleks.

Osama
sumber
0

jika tidak ditampilkan sama sekali, alasannya adalah Anda perlu dua tanda @:

@@class

TETAPI, saya percaya Anda mungkin perlu memiliki kelas aktif pada tag "li" bukan pada tag "a". menurut juga bootstrap docs ( 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>

oleh karena itu kode Anda akan:

<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>
Kadal JC
sumber
Kelas @@ melempar kesalahan, saya awalnya memiliki contoh kode Anda di atas, yang berfungsi, tetapi tidak persis seperti Actionlinks "seharusnya"?
Gillespie
diedit. @@ tidak diperlukan. Anda harus meletakkan kelas pada EA
JC Lizard
0

Semoga ini bisa membantu, di bawah ini adalah bagaimana menu Anda dapat:

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

Dan tambahkan fungsi pembantu MVC di bawah ini di bawah tag html.

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

Saya merujuk jawaban dari http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/

Ganesh Todkar
sumber
0

Saya menyadari bahwa masalah ini adalah masalah umum bagi sebagian dari kita, jadi saya menerbitkan solusi saya sendiri menggunakan paket nuget. Di bawah ini Anda dapat melihat cara kerjanya. Semoga bermanfaat.

Catatan: Paket nuget ini adalah paket pertama saya. Jadi, jika Anda melihat kesalahan, tolong beri umpan balik. Terima kasih.

  1. Instal Paket atau unduh kode sumber dan tambahkan Proyek Anda

    -Install-Package Betalgo.MvcMenuNavigator
  2. Tambahkan halaman Anda ke enum

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Letakkan Filter di atas Controllor atau Action Anda

    [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. Dan gunakan di tata letak tajuk Anda seperti ini

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

Info Lebih Lanjut: https://github.com/betalgo/MvcMenuNavigator

Tolga Kayhan
sumber
0

Saya percaya di sini adalah kode yang lebih bersih dan lebih kecil untuk mendapatkan menu yang dipilih "aktif":

 <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"
                            : "";
        }
Gabriel Marius Popescu
sumber
Bagus, meskipun mungkin perlu diperluas untuk controller & area dalam beberapa kasus
planetClaire
-1

Saya telah membuat kombinasi jawaban di atas dan membuat solusi saya.

Begitu..

Pertama di blok silet, buat satu variabel string yang akan berisi nilai nama pengontrol dan tindakan yang dipanggil oleh pengguna.

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

Kemudian gunakan kombinasi kode HTML dan Razor:

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

Saya pikir, ini bagus karena Anda tidak perlu mengakses "ViewContext.RouteData.Values" setiap kali mendapatkan nama pengontrol dan nama tindakan.

Nihad Delic
sumber
-1

Solusi saya untuk masalah ini adalah

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

Cara yang lebih baik mungkin menambahkan metode ekstensi Html untuk mengembalikan jalur saat ini untuk dibandingkan dengan tautan

Mudasar Rauf
sumber
-1

Saya melakukan ini:

Membuat pembantu dalam tampilan sebagian menu

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

Kemudian menggunakannya di jangkar tag seperti ini:

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

Aplikasi saya tidak memiliki area tetapi juga dapat dimasukkan sebagai variabel lain dalam fungsi helper. Dan saya harus melewati kelas aktif ke jangkar tag dalam pandangan saya. Tetapi libisa juga dikonfigurasi seperti ini.

Anup Sharma
sumber
1
Soalnya, downvote tidak terlalu membantu jika Anda tidak menyebutkan alasannya.
Anup Sharma