TextBoxFor vs EditorFor, and htmlAttributes vs additionalViewData
为了演示一个问题,我创建了一个默认的MVC 3项目(使用剃刀)。
在登录页面上,有一行:
1 | @Html.TextBoxFor(m => m.UserName) |
如果我将其更改为:
1 | @Html.TextBoxFor(m => m.UserName, new { title ="ABC" }) |
然后将其呈现为(具有title属性):
1 | <input data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" title="ABC" type="text" value="" /> |
但是,如果我将其设为EditorFor:
1 | @Html.EditorFor(m => m.UserName, new { title ="ABC" }) |
然后将其呈现为(没有title属性)为:
1 | <input class="text-box single-line" data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" type="text" value="" /> |
因此,总而言之,当我使用EditorFor时,title属性会丢失。
我知道TextBoxFor的第二个参数称为htmlAttributes,EditorFor的第二个参数为AdditionalViewData,但是我已经看到一些示例,其中EditorFor可以呈现此参数提供的属性。
谁能解释我在做什么错,以及在使用EditorFor时如何拥有title属性?
我想我找到了一个更好的解决方案。 EditorFor接受AdditionalViewData作为参数。如果为它提供一个带有属性的名为" htmlAttributes"的参数,那么我们可以使用它来做一些有趣的事情:
1 2 3 4 5 6 | @Html.EditorFor(model => model.EmailAddress, new { htmlAttributes = new { @class ="span4", maxlength = 128, required = true, placeholder ="Email Address", title ="A valid email address is required (i.e. [email protected])" } }) |
然后,您可以在模板(在本例中为EmailAddress.cshtml)中提供一些默认属性:
1 2 3 | @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, Html.MergeHtmlAttributes(new { type ="email" })) |
通过以下辅助方法将魔术结合在一起:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public static IDictionary<string, object> MergeHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes) { var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes") ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"]) : new RouteValueDictionary(); if (htmlAttributes != null) { foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) { var key = property.Name.Replace('_', '-'); if (!attributes.ContainsKey(key)) { attributes.Add(key, property.GetValue(htmlAttributes)); } } } return attributes; } |
当然,如果您正在处理原始HTML,则可以对其进行修改以呈现属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public static MvcHtmlString RenderHtmlAttributes<TModel>(this HtmlHelper<TModel> htmlHelper, object htmlAttributes) { var attributes = htmlHelper.ViewData.ContainsKey("htmlAttributes") ? HtmlHelper.AnonymousObjectToHtmlAttributes(htmlHelper.ViewData["htmlAttributes"]) : new RouteValueDictionary(); if (htmlAttributes != null) { foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) { var key = property.Name.Replace('_', '-'); if (!attributes.ContainsKey(key)) { attributes.Add(key, property.GetValue(htmlAttributes)); } } } return MvcHtmlString.Create(String.Join("", attributes.Keys.Select(key => String.Format("{0}=\"{1}\"", key, htmlHelper.Encode(attributes[key]))))); } |
如果创建自定义EditorFor模板,则可以使用这种解决方法在MVC3中添加标题(和其他htmlAttributes)。这种情况下,该值是可选的,并准备编辑器不要求调用包含
1 | @Html.EditorFor(m => m.UserName,"CustomTemplate", new { title ="ABC" }) |
EditorTemplates / CustomTemplate.cshtml
1 2 3 4 5 6 7 8 9 | @{ string s =""; if (ViewData["title"] != null) { // The ViewData["name"] is the name of the property in the addtionalViewData... s = ViewData["title"].ToString(); } } @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { title = s }) |
我做了非常相似的事情,在EditorTemplate中包含了一个可选类。您可以根据需要将任意多个项目添加到addtionalViewData中,但需要在EditorFor模板中进行处理。
您可以看以下博客文章,该文章说明了如何实现自定义元数据提供程序并在视图模型上使用数据批注以定义html属性,例如