2011-03-04 135 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()); 
     } 
    } 
}