wake-up-neo.net

Besserer Weg, um einen aktiven Seitenlink in MVC 3 Razor zu erhalten

Wenn ich möchte, dass ein bestimmter Menülink auf einer bestimmten Seite aktiv ist, verwende ich diesen Ansatz in Razor:

Auf dem Master-Layout habe ich folgende Prüfungen:

var active = ViewBag.Active;
const string ACTIVE_CLASS = "current";

if (active == "home")
{
    ViewBag.ActiveHome = ACTIVE_CLASS;
}
if (active == "products")
{
    ViewBag.ActiveProducts = ACTIVE_CLASS;
}

usw.

Das HTML-Menü im Master-Layout:

<ul>
<li class="@ViewBag.ActiveHome"><a href="/">Home</a></li>
<li class="@ViewBag.ActiveProducts"><a href="@Url.Action("index", "products")">Products</a></li>
</ul>

Wenn Sie angeben, welche Layoutseite in einer anderen Ansicht verwendet werden soll:

@{
    ViewBag.Active = "home";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Gibt es einen besseren Ansatz, aktive Links zu trennen, als den, den ich gerade verwende?

54
Jens

Ein besserer Ansatz ist die Verwendung eines HTML-Helpers:

using System.Web.Mvc; 
using System.Web.Mvc.Html;

public static class MenuExtensions
{
    public static MvcHtmlString MenuItem(
        this HtmlHelper htmlHelper, 
        string text,
        string action, 
        string controller
    )
    {
        var li = new TagBuilder("li");
        var routeData = htmlHelper.ViewContext.RouteData;
        var currentAction = routeData.GetRequiredString("action");
        var currentController = routeData.GetRequiredString("controller");
        if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
        {
            li.AddCssClass("active");
        }
        li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
        return MvcHtmlString.Create(li.ToString());
    }
}

und dann:

<ul>
    @Html.MenuItem("Home", "Home", "Home")
    @Html.MenuItem("Products", "Index", "Products")
</ul>

Um die oben genannten Schritte auszuführen, benötigen Sie Ihre Ansichten, um Ihre Erweiterung zu erkennen: Fügen Sie in Web.config im Ordner Views den Code <add namespace="yourNamespacehere.Helpers" /> im Namespaces-Tag hinzu. Dann erstellen Sie Ihr Projekt und schließen und öffnen Sie die Ansicht, der Sie dies hinzufügen.

basierend auf der aktuellen Aktion und dem Controller fügt der Helfer beim Generieren des Ankers die active-Klasse hinzu oder nicht.

126
Darin Dimitrov

In Darins Beispiel wird hier die vollständige Klasse erläutert, die zusätzliche optionale Parameter für RouteValues ​​und HtmlAttributes im Helper hinzufügt. Tatsächlich verhält es sich genauso wie der Basis-ActionLink.

using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace MYNAMESPACE.Helpers {
    public static class MenuExtensions {
        public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper,
                                             string text, string action,
                                             string controller,
                                             object routeValues = null,
                                             object htmlAttributes = null) {
            var li = new TagBuilder("li");
            var routeData = htmlHelper.ViewContext.RouteData;
            var currentAction = routeData.GetRequiredString("action");
            var currentController = routeData.GetRequiredString("controller");
            if (string.Equals(currentAction,
                              action,
                              StringComparison.OrdinalIgnoreCase) &&
                string.Equals(currentController,
                              controller,
                              StringComparison.OrdinalIgnoreCase)) {
                li.AddCssClass("active");
            }
            if (routeValues != null) {
                li.InnerHtml = (htmlAttributes != null)
                    ? htmlHelper.ActionLink(text,
                                            action,
                                            controller,
                                            routeValues,
                                            htmlAttributes).ToHtmlString()
                    : htmlHelper.ActionLink(text, 
                                            action, 
                                            controller, 
                                            routeValues).ToHtmlString();
            }
            else {
                li.InnerHtml = htmlHelper.ActionLink(text, 
                                                     action, 
                                                     controller).ToHtmlString();
            }
            return MvcHtmlString.Create(li.ToString());
        }
    }
}

Und in der web.config des View-Ordners:

<system.web.webPages.razor>
  <Host ... />
  <pages ... >
    <namespaces>
      ...

      ...
      <add namespace="MYNAMESPACE.Helpers" />
    </namespaces>
  </pages>
</system.web.webPages.razor>
6
dperish

Für RC2 aktualisiert - Für diejenigen, die sich fragen, wie man dies in MVC6/Asp.Net 5 macht - ähnlich, aber subtil anders. Es gibt jetzt keine MvcHtmlString und die RouteData arbeitet völlig anders. Das Kontextobjekt sollte jetzt IHtmlContent und nicht HtmlHelper..__ sein.

using System;
using Microsoft.AspNet.Mvc.Rendering;

public static class MenuExtensions
{
    public static IHtmlContent MenuItem(
        this IHtmlHelper htmlHelper,
        string text,
        string action,
        string controller
    )
    {

        var li = new TagBuilder("li") { TagRenderMode = TagRenderMode.Normal };
        var routeData = htmlHelper.ViewContext.RouteData;
        var currentAction = routeData.Values["action"].ToString();
        var currentController = routeData.Values["controller"].ToString();

        if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
        {
            li.AddCssClass("active");
        }


        li.InnerHtml.AppendHtml(htmlHelper.ActionLink(text, action, controller));

        return li;


    }
}
2
Party Ark

Verwenden Sie dieses InnerHtml, wenn Sie HTML-Formatierungen in Ihren Text einfügen möchten.

li.InnerHtml = "<a href=\"" + new UrlHelper(htmlHelper.ViewContext.RequestContext).Action(action, controller).ToString() + "\">" + text + "</a>";

text könnte "<b> Fett </ b> Normal" sein;

2
edocetirwi

Dieser Code hat für mich selbst bei einem neuen Visual Studio 2013 MVC5/Bootstrap-Projekt gut funktioniert. Beachten Sie auch, dass Sie die li.AddCssClass ("active") ändern können. Zeile, die auf eine benutzerdefinierte Klasse verweist, wenn Sie die "aktive" Klasse von Bootstrap in Ruhe lassen möchten. Ich fügte in der Site.css-Datei des Projekts eine mit dem Namen "activemenu" hinzu und nahm alle spezifischen Änderungen an der Navigationsleiste vor, die ich dort wollte.

Die Zeile im obigen Code wurde einfach so geändert, dass alles funktioniert:

li.AddCssClass("activemenu");

In Site.css habe ich eine einfache Klasse für meine Zwecke hinzugefügt:

.activemenu {
    text-decoration: underline;
}

Alternativ können Sie die Hintergrundfarbe und/oder den Rand usw. ändern.

0
ggoodro

hier ist eine Erweiterung der Klasse von Darin, um HTML-Code anstelle eines einfachen Textes in den Linktext einzufügen

using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace YourNameSpaceHere
{
    public static class MenuExtensions
    {
        public static MvcHtmlString MenuItem(
            this HtmlHelper htmlHelper,
            string html,
            string action,
            string controller
        )
        {
            var li = new TagBuilder("li");
            var routeData = htmlHelper.ViewContext.RouteData;
            var currentAction = routeData.GetRequiredString("action");
            var currentController = routeData.GetRequiredString("controller");
            if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
                string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
            {
                li.AddCssClass("active");
            }
            //generate a unique id for the holder and convert it to string
            string holder = Guid.NewGuid().ToString();
            string anchor = htmlHelper.ActionLink(holder, action, controller).ToHtmlString();
            //replace the holder string with the html
            li.InnerHtml = anchor.Replace(holder, html);
            return MvcHtmlString.Create(li.ToString());
        }
    }
}

und benutze es so:

<ul>
    @Html.MenuItem("<span class'ClassName'>Home</span>", "Home", "Home")
</ul>
0
MAK5