2011-03-04 138 views
59

我有一个简单的现场形式如何覆盖@ 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> 

我该怎么做?

全部examples使用EditorTemplates但这是一个LabelFor

+0

这将导致一个呼叫ambigous例外由于签名是相同的现有的扩展方法。没有压倒一切的扩展方法。 – Nilzor 2011-03-08 16:00:57

+0

@Nilzor,没有扩展名,这样的参数,你就可以放心使用的代码在我的答案,记住,这是'LabelFor'不'EditorFor'。 – balexandre 2011-03-08 19:41:38

+0

是的,你是对的。我应该说的是你的方法不会覆盖@ Html.LabelFor(model => model.Register.UserName)构造。如果您尝试使用此签名添加重载,您将收到一个ambigous呼叫例外,就像我测试的那样。您的解决方案很完善,但它需要您更改调用代码(视图)。 – Nilzor 2011-03-18 09:41:28

回答

65

你会通过创建自己的HTML帮助做到这一点。

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

您可以通过下载ASP.Net MVC源查看LabelFor <>的代码,修改为自定义的帮手。通过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

明白了,将最终代码添加到我的问题中供任何人复制/粘贴/使用。感谢您的高举。 – balexandre 2011-03-04 16:34:51

+0

我用这个扩展方法作为开始,但是因为它没有用参数fieldName重写LabelFor方法,所以我更新了一下。 – 2014-05-30 13:56:59

+4

如何解决使用此问题时的Ambigious调用错误。现在有两个来自默认MVC和这个的LabelFor方法。 – Ruchan 2014-12-02 06:57:48

2

LabelFor加入


回答是一个扩展方法(静态),并且因此不能被重写。你需要创建自己的Html Helper Extension方法来实现你所需要的。

+2

编辑器模板可以被“覆盖”,尽管它们是静态方法。 – Linkgoron 2011-03-04 16:34:56

+1

我们不是在这里讨论编辑器模板。编辑器模板是通过约定发现的局部视图。它与覆盖或扩展方法的静态声明无关。 – 2011-03-04 19:23:37

+11

是的,但是当有人看到LabelFor,然后看到它与Editor相似时,他可能会认为它也可以按照惯例被超越。这正是OP所要求的。这与方法重载和静态方法无关。 – Linkgoron 2011-03-04 19:31:00

2

我扩大在balealexandre的答案,并在指定的HTML之前和您的标签文本之后,包括的能力增加。我添加了一堆方法重载和注释。我希望这可以帮助人们!

另外钩住从这里信息: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()); 
     } 
    } 
}