ASP.NET MVC'de Html.ActionLink'e "active" sınıfı nasıl eklenir?


128

MVC'de önyükleme gezinme çubuğuma "etkin" bir sınıf eklemeye çalışıyorum, ancak aşağıdaki şekilde yazıldığında etkin sınıfı göstermiyor:

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

Bu, doğru biçimlendirilmiş bir sınıfa benzeyen ancak çalışmayan bir sınıfa çözüm getirir:

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

Bootstrap belgelerinde, 'a' etiketlerinin gezinme çubuğunda kullanılmaması gerektiğini belirtir, ancak yukarıdaki html.ActionLink'e bir sınıf eklemenin doğru yolunun olduğuna inanıyorum. Bunu yapmanın başka (düzenli) bir yolu var mı?


3
çözen kodun içinde class = active vardır. Sorunda istediğini söylediğin bu değil mi? Kodunuzu nasıl aldınız, sınıfları nasıl
ekledim

çok net değilsin !!! Bunu nav'a ekleyen sorunun ne olduğunu tam olarak anlamıyorum, bir hisse kapılsam da, nasıl olduğu gayet iyi olmalı
JC Lizard

1
Çözülen kodla ilgili sorun nedir? Ne bekliyorsun "İşe yaramıyor" dan daha spesifik olabilir misin? Sorunuz şu anda size yardımcı olacak kadar net değil.
dom

Düzenlenen! üzgünüm, demek istediğim "aktif" sınıfın hiç görünmemesiydi
Gillespie

2
Sadece Bootstrap dokümanlarının baktı ve ben eklemek gerekmez düşünüyorum activeiçin sınıf lielemanı değil a. İlk örneğe buradan bakın: getbootstrap.com/components/#navbar
dom

Yanıtlar:


300

Bootstrap olarak activesınıf için uygulanması gereken <li>eleman değil <a>. Buradaki ilk örneğe bakın: http://getbootstrap.com/components/#navbar

Neyin etkin olup olmadığına dayalı olarak kullanıcı arabirimi stilinizi işleme şeklinizin ASP.NET MVC'nin ActionLinkyardımcısıyla hiçbir ilgisi yoktur . Bootstrap çerçevesinin nasıl oluşturulduğunu izlemek için uygun çözüm budur.

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

Düzenle:

Menünüzü büyük olasılıkla birden çok sayfada yeniden kullanacağınız için, menüyü birden çok kez kopyalayıp manuel olarak yapmak yerine, seçilen sınıfı geçerli sayfaya göre otomatik olarak uygulamanın bir yolunu bulmak akıllıca olacaktır.

En kolay yol, içerdiği değerleri ViewContext.RouteData, yani Actionve Controllerdeğerlerini kullanmaktır. Şu anda sahip olduğunuz şeyin üzerine şunun gibi bir şey inşa edebiliriz:

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

Kod olarak güzel değil, ancak işi halledecek ve isterseniz menünüzü kısmi bir görünüme çıkarmanıza izin verecek. Bunu çok daha temiz bir şekilde yapmanın yolları var, ama siz daha yeni başladığınız için, bunu burada bırakacağım. ASP.NET MVC öğrenirken bol şans!


Geç düzenleme:

Bu soru biraz trafik alıyor gibi görünüyor, bu yüzden bir HtmlHelperuzantı kullanarak daha zarif bir çözüm sunacağımı düşündüm .

Düzenleme 03-24-2015: Birden fazla eylem ve denetleyicinin seçilen davranışı tetiklemesine izin vermek için bu yöntemi yeniden yazmak zorunda kaldım ve yöntemin bir çocuk eylemi kısmi görünümünden ne zaman çağrıldığını ele almalıyım, güncellemeyi paylaşacağımı düşündüm!

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

.NET Core ile çalışır:

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

Örnek kullanım:

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

Teşekkürler, daha önce de bahsettiğim gibi, buna sahiptim, ancak kodum boyunca seçilen nesneler arasında "aktif" sınıfı değiştirmek için bir yönteme sahip olmayı umuyordum.
Gillespie

2
@Gillespie endişelenmeyin! Size biraz daha yardımcı olabilecek bazı bilgiler eklemek için cevabımı düzenledim.
dom

5
İlk düzenlemeyle ilgili olarak, aslında yalnızca Dizin sayfası için çalıştı. Görünüşe göre bunun nedeni, karşılaştırma yapılırken ViewContext.RouteData.Values ​​["Action"] bir String türü nesne döndürmediğinden başarısız olmuş (yine de ilk sayfa için nasıl çalıştığını bilmiyor ....) . Tüm ViewContext.RouteData.Values ​​["Action"] ViewContext.RouteData.Values ​​["Action"]. ToString () olarak değiştirildiğinde, tüm sayfalar için çalıştı. Birisinin aynı sorunu yaşaması durumunda bunu çözümünüze eklemek isteyebilirsiniz.
user3281466

2
@LonelyPixel belki bu cevap sizin için çalışıyor?
dom

1
VB.NET kullanıcıları için: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Ana Sayfa "," Dizin "," Ana Sayfa ") </li>
Andrea Antonangeli

28

Uzantı:

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

Kullanımı:

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

1
Bu güzel ve verimli bir eklentidir. Mükemmel çalışıyor ve oldukça zarif. Size şapka çıkartın Prof! Benim tek yakınmamrole="presentation" , birincil bir gezinme menüsü için hiç de uygun olmayan ( john.foliot.ca/aria-hidden/#pr ) ile ilgilidir. Sıralanmamış bir liste, onları mantıksal bir şekilde bir arada gruplandırdığından, ilgili bir dizi bağlantı için çok uygun bir kaptır.
René Kåbis

@ René Kåbis bootstrap naigation için getbootstrap.com/components/#nav-tabs
Prof

1
Bu, kullanıcı url'yi küçük harf veya büyük harf olarak manuel olarak girdiğinde çalışmaz, örn. " domain.com/Login " ve " domain.com/LOGIN ". Çözüm için 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

Bunu, asp.net mvc'ye bir görünüm çantası parametresi ekleyerek yapmayı başardım. İşte ben ne yaptım

ViewBag.Current = "Scheduler";Her sayfaya benzer parametre eklendi

Düzen sayfasında

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

Bu benim sorunumu çözdü.


Basit ve kolay çözüm.
2019'da Sophey

13

Biraz geç olabilir. Ama umarım bu yardımcı olur.

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

Ve aşağıdaki gibi kullanım:

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

Http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html adresinden referans aldım


1
Çok basit ve zarif bir çözüm. Tüm denetleyici eylemleri için bir menüyü vurgulamak için burada gist.github.com/jean-rakotozafy/… bazı iyileştirmeler yaptım .
Zan RAKOTO

5

Bu sorunun eski olduğunu biliyorum, ancak sesimi buraya eklemek isterim. Bir bağlantının aktif olup olmadığı bilgisini görünümün denetleyicisine bırakmanın iyi bir fikir olduğuna inanıyorum.

Denetleyici eylemindeki her görünüm için benzersiz bir değer ayarlardım. Örneğin, ana sayfa bağlantısını aktif hale getirmek istersem, şöyle bir şey yapardım:

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

Sonra bana göre şöyle bir şey yazacağım:

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

Farklı bir sayfaya gittiğinizde, Programlar diyelim, ViewBag.Home mevcut değil (bunun yerine ViewBag.Programs var); bu nedenle, sınıf = "" bile hiçbir şey işlenmez. Bunun hem bakım hem de temizlik açısından daha temiz olduğunu düşünüyorum. Mantığı elimden geldiğince her zaman görüşün dışında bırakma eğilimindeyim.


4

Damith'in gönderdiklerini göz önünde bulundurarak, Viewbag.Title tarafından aktif olarak nitelendirilebileceğinizi düşünüyorum (en iyi uygulama bunu içerik sayfalarınızda doldurarak_Layout.cshtml sayfanızın bağlantı çubuklarınızı tutmasına izin vermektir ). Ayrıca alt menü öğelerini kullanıyorsanız, bunun da iyi çalıştığını unutmayın:

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

Temiz ve verimli!
mggluscevic

3

Ben modifiye Dom'un "Hiç hoş" cevabını ve daha çirkin yaptı. Bazen iki denetleyicinin çakışan eylem adları vardır (örn. Dizin), bu yüzden şunu yapıyorum:

<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

Bunu deneyebilirsiniz: Benim durumumda, rol tabanlı erişime dayalı olarak veritabanından menüyü yüklüyorum, görünümünüze göre hangi menüyü etkinleştirmek istediğinizi her görünümünüze yazın.

<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

Bu çözüm Asp.net MCV 5 için basittir.

  1. Örneğin, statik bir sınıf oluşturun Utilitarios.cs.

  2. Sınıfın içinde statik bir yöntem oluşturun:

    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. böyle ara

    <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 ve Bootstrap 4

En güncel cevap

Bu sorunu bir uzantı yöntemine dayalı olarak çözmek için güncellenmiş, ASP.NET Core ve Bootstrap 4 uyumlu bir yol için @crush'ın temiz çözümünü yeniden çalıştım :IHtmlHelper

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

kullanım

<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
Çok güzel bir çözüm. Örneğinizde, 'Kişi'yi varsayılan olarak nasıl etkin olarak ayarlayabilirim?
Md. Suman Kabir

1
Teşekkür ederim. İşin iyi yanı, aktif bir öğe ayarlamanıza gerek olmamasıdır. 'İletişim' sayfası ziyaret ActiveActionLink()edilir <li>
edilmez

alanı kontrol ediyorsun
Muhammed

@Mohammad anlamıyorum. Lütfen sorunuzu detaylandırır mısınız?
WoIIe

LinkExtensions sınıfında, routeData'dan alan almadınız!
Mohammad

3

Kolay ASP.NET Core 3.0 ve 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");
            }
        }
    }
}

_ViewImports.cs dosyanıza ekleyin:

@addTagHelper *, YourAssemblyName

Kullanımı:

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

2

ASP.NET MVC üzerinde karşılaştırmayı iyileştirmek için ".ToString" ekleyin

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

-


İki farklı denetleyicide aynı eylem adları varsa bu işe yaramaz. Dizin işlemine sahip Ev ve Hakkında denetleyicileriyle test edin.
hyde

u ustura gibi işlev sunucusunu tanımlayabilirsiniz: @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); } }ve kullanım: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung

2

UrlHelperMvcHandler'in kendisinden alabileceğimiz RequestContext'ten de oluşturabiliriz . Bu nedenle, bu mantığı Razor şablonlarında aşağıdaki şekilde tutmak isteyen birinin yardımcı olacağına inanıyorum:

  1. Proje kökünde adlı bir klasör oluşturun AppCode.
  2. Orada adlı bir dosya oluşturun HtmlHelpers.cshtml
  3. Orada bir yardımcı oluşturun:

    @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. O zaman şu şekilde görüşlerimizde kullanabiliriz:

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

Umarım birine yardımcı olur.


Bu gerçekten havalı. Burada herhangi bir performans sakıncası var mı?
crush

@crush, bunu ölçmedim, ancak performans etkisinin düşük olmasını bekliyorum çünkü çerçevenin, UrlHelpersahip olduğunuz şeyi oluşturmak için benzer bir mantık kullandığını düşünüyorum Controller.Url. Tek şey, muhtemelen UrlHelperher çağrı için oluşturmayı yürütmek istemediğimizdir, MenuItembu nedenle, yardımcıyı ilk aramadan sonra HttpContext Öğelerine kaydetme işaretini uygulayabiliriz, böylece bunu istek başına yalnızca bir kez yaparız.
Oleksii Aza

2

lambda işlevi ile mümkündür

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

sonra kullanım

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

2

Bağlantıyı çevrelemek yerine bağlantının kendisine "aktif" sınıfı eklemek isteyenler için HtmlHelperbir ActiveActionLinkyöntem ekleyen bir uzantı oluşturdum <li>.


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

Kullanım şekli aşağıdaki gibidir:

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

1

@dombenoit tarafından verilen cevap işe yarıyor. Bakımı yapılacak bazı kodlar sunsa da. Bu sözdizimini kontrol edin:

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

Kullanımına dikkat edin .SetLinksActiveByControllerAndAction()Yöntemin .

Bu sözdizimini neyin mümkün kıldığını merak ediyorsanız, TwitterBootstrapMVC'ye bakın.


Cevap için teşekkürler Dmitry, TwitterBootstrapMVC'yi test ediyorum
Gillespie

1

Ayrıca bir çözüm arıyordum ve jQuery oldukça yardımcı oldu. Öncelikle, <li>öğelerinize 'id'ler vermeniz gerekir .

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

Bunu düzen sayfanızda yaptıktan sonra, jQuery'ye görünümünüzde hangi <li>öğenin 'seçilmesi' gerektiğini söyleyebilirsiniz .

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

Not: @RenderSection("scripts", required: false)Düzen sayfanızda, </body>o bölümü eklemek için etiketinden hemen önce olması gerekir .


1

Dom'un cevabının ilk kısmına dayanan bu çözümü önermek istiyorum.

Önce "eylem" ve "denetleyici" olmak üzere iki değişken tanımlıyoruz ve bunları aktif bağlantıyı belirlemek için kullanıyoruz:

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

Ve sonra:

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

Artık daha güzel görünüyor ve daha karmaşık çözümlere gerek yok.


0

hiç görünmüyorsa, bunun nedeni iki @ işaretine ihtiyacınız olmasıdır:

@@class

ANCAK, aktif sınıfın "a" etiketinde değil "li" etiketinde olması gerekebileceğine inanıyorum. çok bootstrap belgelerine göre ( 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>

bu nedenle kodunuz şöyle olacaktır:

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

@@ sınıfı bir hata veriyor, başlangıçta kod örneğiniz yukarıda vardı, bu işe yarıyor, ancak tam olarak Actionlinks "olması gerektiği" gibi değil mi?
Gillespie

düzenlendi. @@ gerekli değildir. sınıfı EA
JC Lizard

0

Umarım bu yardımcı olur, aşağıda menünüz nasıl olabilir:

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

Ve html etiketinin altına MVC yardımcı işlevini ekleyin.

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

Ben cevabını sevk http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/


0

Bu sorunun bazılarımız için ortak bir sorun olduğunu fark ettim ve nuget paketini kullanarak kendi çözümümü yayınladım. Aşağıda nasıl çalıştığını görebilirsiniz. Umarım faydalı olur.

Not: Bu nuget paketi benim ilk paketim. Dolayısıyla, bir hata görürseniz lütfen geri bildirimde bulunun. Teşekkür ederim.

  1. Paketi yükleyin veya kaynak kodunu indirin ve Projenizi ekleyin

    -Install-Package Betalgo.MvcMenuNavigator
  2. Sayfalarınızı bir numaralandırmaya ekleyin

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Filtreyi Kontrolörünüzün veya Eyleminizin üstüne yerleştirin

    [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. Ve bunu başlık düzeninizde şu şekilde kullanın

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

Daha Fazla Bilgi: https://github.com/betalgo/MvcMenuNavigator


0

Sanırım burada, seçilen menüyü "aktif" hale getirmek için daha temiz ve daha küçük bir kod:

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

Güzel, ancak bazı durumlarda muhtemelen denetleyici ve alan için genişletilmesi gerekmesine rağmen
planetClaire

-1

Yukarıdaki cevapları bir araya getirdim ve çözümümü yaptım.

Yani..

İlk olarak tıraş bıçağı bloğunda denetleyicinin ad değerini ve kullanıcı tarafından çağrılan eylemi içerecek bir dizi değişkeni oluşturun.

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

Ardından HTML ve Razor kodunun kombinasyonunu kullanın:

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

Bunun iyi olduğunu düşünüyorum çünkü denetleyici adını ve eylem adını almak için her seferinde "ViewContext.RouteData.Values" e erişmenize gerek yok.


-1

Bu soruna çözümüm

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

Bağlantıyla karşılaştırılacak geçerli yolu döndürmek için bir Html uzantısı yöntemi eklemek daha iyi bir yol olabilir


-1

Bunu ben yaptım:

Menü kısmi görünümünde bir yardımcı yaptı

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

Sonra bunu bağlantı etiketinde şu şekilde kullandı:

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

Uygulamamın hiçbir alanı yoktu, ancak yardımcı işlevde başka bir değişken olarak da eklenebilir. Ve aktif sınıfı benim görüşümdeki bağlantı etiketine geçirmem gerekiyordu. Ancak libu şekilde de yapılandırılabilir.


1
Gördüğünüz gibi, nedenini belirtmezseniz olumsuz oy gerçekten yardımcı olmaz.
Anup Sharma
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.