TextBoxFor与EditorFor,以及htmlAttributes与additionalViewData

时间:2011-06-14 17:44:13

标签: asp.net-mvc-3

我创建了一个默认的MVC 3项目(使用razor),以证明问题。

在登录页面上,有一行:

@Html.TextBoxFor(m => m.UserName)

如果我将其更改为:

@Html.TextBoxFor(m => m.UserName, new { title = "ABC" })

然后它呈现为(带有title属性):

<input data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" title="ABC" type="text" value="" />

但是,如果我把它作为EditorFor:

 @Html.EditorFor(m => m.UserName, new { title = "ABC" })

然后它被渲染(没有title属性):

<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属性?

3 个答案:

答案 0 :(得分:14)

我想我找到了一个更好的解决方案。 EditorFor将additionalViewData作为参数。如果你给它一个带有属性的名为“htmlAttributes”的参数,那么我们可以用它做一些有趣的事情:

@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. user@domain.com)" } })

在模板中(在本例中为EmailAddress.cshtml),您可以提供一些默认属性:

@Html.TextBox("",
              ViewData.TemplateInfo.FormattedModelValue,
              Html.MergeHtmlAttributes(new { type = "email" }))

通过这种辅助方法,魔法汇集在一起​​:

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,您可以修改它以呈现属性:

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])))));
}

答案 1 :(得分:12)

在MVC3中,如果您创建自定义EditorFor模板,则可以使用此类解决方法添加标题(和其他htmlAttributes)。这个案例是为值可选而编写的,editorFor调用不需要包含object additionalViewData

@Html.EditorFor(m => m.UserName, "CustomTemplate", new { title = "ABC" })

EditorTemplates / CustomTemplate.cshtml

@{
    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模板中处理每个项目。

答案 2 :(得分:5)

您可以查看following blog post,其中说明了如何实现自定义元数据提供程序并在视图模型上使用数据注释,以便定义html属性,例如class,{{1} },maxlength,...然后可以与模板化助手一起使用。