Как переопределить шаблон @Html.LabelFor?

У меня есть простая форма поля

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

и это приводит к:

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

но я хочу, чтобы код LabelFor добавлял внутрь <span>, чтобы в итоге я мог получить:

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

Как это сделать?

Во всех примерах используется EditorTemplates, но это LabelFor .


person balexandre    schedule 04.03.2011    source источник
comment
Это вызовет исключение неоднозначного вызова, поскольку подпись идентична существующему методу расширения. Нет переопределяющих методов расширения.   -  person Nilzor    schedule 08.03.2011
comment
@Nilzor, расширения с такими параметрами нет, можете смело использовать код в моем ответе, помните, это LabelFor, а не EditorFor.   -  person balexandre    schedule 08.03.2011
comment
Да, ты прав. Я должен был сказать, что ваши методы не переопределяют конструкцию @Html.LabelFor(model => model.Register.UserName). Если вы попытаетесь добавить перегрузку с этой сигнатурой, вы получите исключение неоднозначного вызова, как я тестировал. Ваше решение правильное, но требует изменения вызывающего кода (представления).   -  person Nilzor    schedule 18.03.2011
comment
@balexandre Как вы переопределяете обычный метод LabelFor?   -  person Romias    schedule 27.11.2011
comment
Пожалуйста, переместите отредактированное решение в фактический ответ ниже.   -  person BoltClock    schedule 27.02.2012


Ответы (3)


Вы бы сделали это, создав свой собственный помощник HTML.

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

Вы можете просмотреть код для LabelFor‹>, загрузив исходный код для ASP.Net MVC и изменив его как пользовательский помощник.


Ответ добавлен balexandre

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));
    }
}
person Bryan S.    schedule 04.03.2011
comment
Понял, добавил окончательный код к моему вопросу, чтобы кто-нибудь мог скопировать/вставить/использовать. Спасибо за внимание. - person balexandre; 04.03.2011
comment
Я использовал этот метод расширения в качестве начала, но, поскольку он не переопределяет метод LabelFor с параметром fieldName, я немного обновил его. - person reaper_unique; 30.05.2014
comment
Как решить ошибку неоднозначного вызова при использовании этого. теперь есть два метода LabelFor: один из MVC по умолчанию и этот. - person Ruchan; 02.12.2014
comment
@Ruchan, ты когда-нибудь исправлял это? - person HaBo; 13.02.2018
comment
Пришлось переименовать моего собственного помощника с другим именем. - person Ruchan; 14.02.2018

Я расширил ответ balealexandre и добавил возможность указать HTML для включения как до, так и после текста вашей метки. Я добавил кучу перегруженных методов и комментариев. Надеюсь, это поможет людям!

Также получена информация отсюда: Html внутри метки с использованием помощника Html

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());
        }
    }
}
person Setarcos    schedule 10.05.2014

LabelFor — это метод расширения (статический), поэтому его нельзя переопределить. Вам нужно будет создать свой собственный метод Html Helper Extension, чтобы добиться того, что вам нужно.

person Darren Lewis    schedule 04.03.2011
comment
Шаблоны редактора МОГУТ быть переопределены, хотя они СЛИШКОМ являются статическими методами. - person Linkgoron; 04.03.2011
comment
Мы не говорим здесь о шаблонах редактора. Шаблон редактора — это частичное представление, обнаруженное по соглашению. Это не имеет ничего общего с переопределениями или статическим объявлением метода расширения. - person Darren Lewis; 04.03.2011
comment
Да, но когда кто-то видит LabelFor, а затем видит, что он похож на EditorFor, он МОЖЕТ подумать, что его тоже можно переопределить по соглашению. Это именно то, что спросил ОП. Это не имеет ничего общего с перегрузкой методов и статическими методами. - person Linkgoron; 04.03.2011