【问题标题】:TextBoxFor vs EditorFor, and htmlAttributes vs additionalViewDataTextBoxFor 与 EditorFor,以及 htmlAttributes 与 AdditionalViewData
【发布时间】:2011-09-14 22:03:10
【问题描述】:

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

在登录页面,有一行:

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

如果我将其更改为:

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

然后它被渲染为(带有标题属性):

<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" })

然后它被渲染(没有标题属性)为:

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

【问题讨论】:

  • 太棒了,我正要问这个确切的问题。

标签: asp.net-mvc-3


【解决方案1】:

我想我找到了一个更好的解决方案。 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])))));
}

【讨论】:

  • 您能否提供一个使用您发布的代码的完整示例项目?我是 ASP.NET 的新手,不知道该把 MergeHtmlAttributesRenderHtmlAttributes 类放在哪里。
  • @RosdiKasim - 这些是我通常存储在静态类中的扩展方法,该类反映了一组通用 HTML 帮助程序的命名空间或我在视图中的 web.config 中包含的新命名空间文件夹,所以我不必在每一页上继续引用它。所以基本上是项目根目录或基础设施文件夹中的“HtmlHelperExtensions.cs”。
  • 伟大的模式!感谢分享:)
  • 您可以使用 HtmlHelper.AnonymousObjectToHtmlAttributes() 方法来改进它。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    您可以查看following blog post,它说明了如何实现自定义元数据提供程序并在您的视图模型上使用数据注释来定义 html 属性,例如classmaxlengthtitle、 ...这可以与模板化帮助器一起使用。

    【讨论】:

    • 虽然令人印象深刻,但该解决方案是众所周知的核桃大锤。有没有更微妙的解决方案?
    • @G-unit,不,没有。 EditorFor 不支持传递 html 属性。这是没有意义的,因为您甚至不知道模板将如何实现。它可能是一个自定义模板,其中 html 属性没有意义。因此,实现这一目标的唯一方法是编写自定义元数据提供程序。就我个人而言,这就是我使用的方法,我对结果非常满意。
    • 谢谢你,我向你的智慧低头!
    • 人们,投票赞成同意这是一个无聊的限制。 visualstudio.uservoice.com/forums/121579-visual-studio/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    • 1970-01-01
    • 2012-06-04
    相关资源
    最近更新 更多