Wie kann ich die Vorlage @ Html.LabelFor überschreiben?

70

Ich habe ein einfaches Feldformular

<div class="field fade-label">
    @Html.LabelFor(model => model.Register.UserName)
    @Html.TextBoxFor(model => model.Register.UserName)
</div>

und dies führt zu:

<div class="field fade-label">
    <label for="Register_UserName">Username (used to identify all services, from 4 to 30 chars)</label>
    <input type="text" value="" name="Register.UserName" id="Register_UserName">
</div>

aber ich möchte, dass dieser LabelForCode ein <span>Inneres anfügt, damit ich am Ende Folgendes habe:

<label for="Register_UserName">
    <span>Username (used to identify all services, from 4 to 30 chars)</span>
</label>

Wie kann ich das machen?

Alle Beispiele verwenden, EditorTemplatesaber dies ist ein LabelFor.

Balexandre
quelle
Dies führt zu einer mehrdeutigen Aufrufausnahme, da die Signatur mit der vorhandenen Erweiterungsmethode identisch ist. Es gibt keine überschreibenden Erweiterungsmethoden.
Nilzor
@Nilzor, es gibt keine Erweiterung mit solchen Parametern, Sie können den Code sicher in meiner Antwort verwenden, denken Sie daran, es ist LabelFornicht EditorFor.
Balexandre
Ja, du hast Recht. Was ich hätte sagen sollen ist, dass Ihre Methoden das Konstrukt @ Html.LabelFor (model => model.Register.UserName) nicht überschreiben. Wenn Sie versuchen, eine Überladung mit dieser Signatur hinzuzufügen, wird eine mehrdeutige Anrufausnahme angezeigt, wie ich getestet habe. Ihre Lösung ist solide, aber Sie müssen den aufrufenden Code (die Ansichten) ändern.
Nilzor
@balexandre Wie überschreiben Sie die "normale" LabelFor-Methode?
Romias
Bitte verschieben Sie Ihre bearbeitete Lösung in eine tatsächliche Antwort unten.
BoltClock

Antworten:

72

Sie tun dies, indem Sie Ihren eigenen HTML-Helfer erstellen.

http://www.asp.net/mvc/tutorials/creating-custom-html-helpers-cs

Sie können den Code für LabelFor <> anzeigen, indem Sie die Quelle für ASP.Net MVC herunterladen und als benutzerdefinierten Helfer ändern.


Antwort von Balexandre hinzugefügt

public static class LabelExtensions
{
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
    {
        return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
    }
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
        string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
        if (String.IsNullOrEmpty(labelText))
        {
            return MvcHtmlString.Empty;
        }

        TagBuilder tag = new TagBuilder("label");
        tag.MergeAttributes(htmlAttributes);
        tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

        TagBuilder span = new TagBuilder("span");
        span.SetInnerText(labelText);

        // assign <span> to <label> inner html
        tag.InnerHtml = span.ToString(TagRenderMode.Normal);

        return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
    }
}
Bryan S.
quelle
2
Verstanden, fügte den endgültigen Code zu meiner Frage hinzu, damit jeder ihn kopieren / einfügen / verwenden kann. Danke für die Warnung.
Balexandre
Ich habe diese Erweiterungsmethode als Start verwendet, aber da sie die LabelFor-Methode nicht mit dem Parameter fieldName überschreibt, habe ich sie ein wenig aktualisiert.
reaper_unique
5
Wie löse ich den Ambigious-Aufruffehler, wenn ich diesen verwende? Jetzt gibt es zwei LabelFor-Methoden, eine aus der Standard-MVC und diese.
Ruchan
@Ruchan hast du das jemals repariert?
HaBo
Musste meinen eigenen Helfer mit einem anderen Namen umbenennen.
Ruchan
5

Ich habe die Antwort von balealexandre erweitert und die Möglichkeit hinzugefügt, HTML anzugeben, das sowohl vor als auch nach Ihrem Etikettentext enthalten sein soll. Ich habe eine Reihe von Methodenüberladungen und Kommentaren hinzugefügt. Ich hoffe das hilft Leuten!

Hier finden Sie auch Informationen: HTML im Etikett mit dem HTML-Helfer

namespace System.Web.Mvc.Html
{
    public static class LabelExtensions
    {
        /// <summary>Creates a Label with custom Html before the label text.  Only starting Html is provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml)
        {
            return LabelFor(html, expression, startHtml, null, new RouteValueDictionary("new {}"));
        }

        /// <summary>Creates a Label with custom Html before the label text.  Starting Html and a single Html attribute is provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="htmlAttributes">A single Html attribute to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, object htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, null, new RouteValueDictionary(htmlAttributes));
        }

        /// <summary>Creates a Label with custom Html before the label text.  Starting Html and a collection of Html attributes are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="htmlAttributes">A collection of Html attributes to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, Func<object, HelperResult> startHtml, IDictionary<string, object> htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, null, htmlAttributes);
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html and ending Html are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml)
        {
            return LabelFor(html, expression, startHtml, endHtml, new RouteValueDictionary("new {}"));
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html, ending Html, and a single Html attribute are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <param name="htmlAttributes">A single Html attribute to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml, object htmlAttributes)
        {
            return LabelFor(html, expression, startHtml, endHtml, new RouteValueDictionary(htmlAttributes));
        }

        /// <summary>Creates a Label with custom Html before and after the label text.  Starting Html, ending Html, and a collection of Html attributes are provided.</summary>
        /// <param name="startHtml">Html to preempt the label text.</param>
        /// <param name="endHtml">Html to follow the label text.</param>
        /// <param name="htmlAttributes">A collection of Html attributes to include.</param>
        /// <returns>MVC Html for the Label</returns>
        public static MvcHtmlString LabelFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, Func<object, HelperResult> startHtml, Func<object, HelperResult> endHtml, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);

            //Use the DisplayName or PropertyName for the metadata if available.  Otherwise default to the htmlFieldName provided by the user.
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            //Create the new label.
            TagBuilder tag = new TagBuilder("label");

            //Add the specified Html attributes
            tag.MergeAttributes(htmlAttributes);

            //Specify what property the label is tied to.
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

            //Run through the various iterations of null starting or ending Html text.
            if (startHtml == null && endHtml == null) tag.InnerHtml = labelText;
            else if (startHtml != null && endHtml == null) tag.InnerHtml = string.Format("{0}{1}", startHtml(null).ToHtmlString(), labelText);
            else if (startHtml == null && endHtml != null) tag.InnerHtml = string.Format("{0}{1}", labelText, endHtml(null).ToHtmlString());
            else tag.InnerHtml = string.Format("{0}{1}{2}", startHtml(null).ToHtmlString(), labelText, endHtml(null).ToHtmlString());

            return MvcHtmlString.Create(tag.ToString());
        }
    }
}
Setarcos
quelle
3

LabelFor ist eine Erweiterungsmethode (statisch) und kann daher nicht überschrieben werden. Sie müssen Ihre eigene HTML-Hilfserweiterungsmethode erstellen, um das zu erreichen, was Sie benötigen.

Darren Lewis
quelle
2
Editor-Vorlagen können "überschrieben" werden, obwohl sie AUCH statische Methoden sind.
Linkgoron
1
Wir sprechen hier nicht über Editor-Vorlagen. Eine Editor-Vorlage ist eine Teilansicht, die durch Konventionen ermittelt wurde. Es hat nichts mit Überschreibungen oder statischen Deklarationen einer Erweiterungsmethode zu tun.
Darren Lewis
12
Ja, aber wenn jemand LabelFor sieht und dann sieht, dass es EditorFor ähnlich ist, könnte er denken, dass es auch durch Konventionen überschrieben werden kann. Genau das hat das OP gefragt. Dies hat nichts mit Methodenüberladung und statischen Methoden zu tun.
Linkgoron