2011-03-04 10 views
59

que tienen una forma simple campo¿Cómo puedo sobrescribir la plantilla @ Html.LabelFor?

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

y esto se traduce en:

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

pero quiero que LabelFor código de anexar un <span> el interior para que pueda llegar a tener:

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

¿Cómo puedo hacer esto?

Todos examples usan EditorTemplates pero esto es LabelFor.

+0

Esto provocará una excepción llamada ambigua ya que la firma es idéntico al método de extensión existente. No hay métodos de extensión superiores. – Nilzor

+0

@Nilzor, no hay extensión con esos parámetros, puede usar el código en mi respuesta, recuerde, es 'LabelFor' no' EditorFor'. – balexandre

+0

Sí, tienes razón. Lo que debería haber dicho es que sus métodos no anulan el constructo @ Html.LabelFor (model => model.Register.UserName). Si intenta agregar una sobrecarga con esta firma, obtendrá una excepción de llamada ambigua, como lo he probado. Su solución es sólida, pero requiere que cambie el código de invocación (las vistas). – Nilzor

Respuesta

65

Para ello, crea tu propia ayuda HTML.

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

Puede ver el código de LabelFor <> mediante la descarga de la fuente de ASP.Net MVC y modificar que como ayudante personalizado.


respuesta añadida por 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)); 
    } 
} 
+2

Entendido, agregué el código final a mi pregunta para que cualquiera pueda copiar/pegar/usar. Gracias por el aviso. – balexandre

+0

Utilicé este método de extensión como inicio, pero como no reemplaza el método LabelFor con el parámetro fieldName lo actualicé un poco. –

+4

¿Cómo resuelvo el error de invocación de Ambigious cuando uso esto? ahora hay dos métodos LabelFor uno del MVC predeterminado y esto. – Ruchan

2

LabelFor es un método de extensión (estática) y por lo tanto no se puede anular. Debería crear su propio método de extensión Html Helper para lograr lo que necesita.

+2

Las plantillas del editor PUEDEN ser "anuladas", aunque TAMBIÉN son métodos estáticos. – Linkgoron

+1

No estamos hablando de plantillas de Editor aquí. Una plantilla de Editor es una vista parcial descubierta por convención.No tiene nada que ver con las anulaciones o la declaración estática de un método de extensión. –

+11

Sí, pero cuando alguien ve LabelFor, y luego ve que es similar al Editor, PUEDE pensar que también puede ser eliminado por convención. Eso es exactamente lo que pidió el OP. Esto no tiene nada que ver con sobrecarga de método y métodos estáticos. – Linkgoron

2

Expandí sobre la respuesta de balealexandre y agregué la capacidad de especificar HTML para incluir tanto antes como después del texto de la etiqueta. Agregué un montón de sobrecargas de métodos y comentarios. Espero que esto ayude a la gente!

También se enganchó información desde aquí: Html inside label using Html helper

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