【问题标题】:Using TextBoxFor to set HTML attributes that have a namespace prefix使用 TextBoxFor 设置具有命名空间前缀的 HTML 属性
【发布时间】:2013-08-14 02:35:59
【问题描述】:

我正在转换一些现有的 HTML 以使用 ASP.NET MVC,并且有一些表单包含输入字段,这些字段具有包含命名空间前缀的附加属性(目前我需要保留):

<input type="text" foo:required="true" foo:message="Please enter a username" />

我想使用TextBoxFor 辅助方法重载,它允许使用collection initializer 语法指定htmlAttributes

@Html.TextBoxFor(
    model => model.Username,
    new { foo:required="true", foo:message="Please enter a username" })

但是,由于foo:required 中的冒号(等),此语法无效。

相反,我不得不使用这种更详细的字典初始化语法:

@Html.TextBoxFor(
    model => model.Username,
    new Dictionary<string, object>
    {
        { "foo:required", "true" },
        { "foo:message", "Please enter a username" }
    })

是否可以在第一种语法上使用变体,以某种方式转义(因为需要更好的词)冒号?

或者

在这种情况下,TextBoxFor 辅助方法并没有真正的帮助吗?保留现有的原始 HTML 并将value="@Model.UserName" 添加到 input 元素会更简单吗?

【问题讨论】:

  • 不能简单地转义冒号,因为 foo:required 基本上是一个属性,所以名称需要适合 C# 属性、变量、函数和类型名称的允许字符。

标签: asp.net-mvc attributes collection-initializer


【解决方案1】:

第一种语法是使用匿名对象,同样的规则适用于create identifiers in C#

  • 您可以使用Lu, Ll, Lt, Lm, Lo, or Nl 类的任何 unicode 字符
  • 您可以使用“@”转义 C# 关键字,如 new { @class = "foo" };

由于冒号属于Po unicode class,它不能用于标识符。 (在 C# 中,您可以使用静态方法 char.GetUnicodeCategory 来检查任何字符的类)

另外,并且仅在 MVC 中,当在帮助程序中为 html 属性使用匿名对象时,任何带有下划线的属性名称都将被连字符替换。这是由于方法HtmlHelper.AnonymousObjectToHtmlAttributes

回到您的案例并考虑您的选项,如果这些选项没有被广泛使用(例如在几个视图中),我会考虑使用 TextBoxFor 助手的字典语法。您仍将获得与模型绑定同步的 id\name 属性的自动生成,并且您将从模型元数据中获得任何其他属性,例如不显眼的验证属性。 (虽然查看您想要保留的属性,但似乎您不需要不显眼的验证属性:))

但是,如果 id\name 与属性名称一样简单,并且您不需要使用帮助程序自动生成的任何其他 html 属性,那么使用原始 HTML 是有意义的。 (因为字典语法很丑)

如果您在整个应用程序中广泛使用它,那么在我看来,最明智的方法可能是创建您自己的助手,例如 @Html.LegacyTextBoxFor(...)。该助手将呈现您想要保留的那些遗留属性,并且您可以合并类似于标准助手的附加逻辑来创建 id\name 属性。

类似这样的:

public class FooAttributes
{
    public bool Required { get; set; }
    public string Message { get; set; }
}

public static class FooHelper
{
    public static MvcHtmlString LegacyTextboxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, FooAttributes fooAttributes)
    {
        var fieldName = ExpressionHelper.GetExpressionText(expression);
        var fullBindingName = html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(fieldName);
        var fieldId = TagBuilder.CreateSanitizedId(fullBindingName);

        var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        var value = metadata.Model;

        TagBuilder tag = new TagBuilder("input");
        tag.Attributes.Add("name", fullBindingName);
        tag.Attributes.Add("id", fieldId);
        tag.Attributes.Add("type", "text");
        tag.Attributes.Add("value", value == null ? "" : value.ToString());

        if (fooAttributes != null)
        {
            if (fooAttributes.Required) tag.Attributes.Add("foo:required", "true");
            if (!String.IsNullOrEmpty(fooAttributes.Message)) tag.Attributes.Add("foo:message", fooAttributes.Message);
        }

        return new MvcHtmlString(tag.ToString(TagRenderMode.SelfClosing));
    }
}

这可以用作:

@Html.LegacyTextboxFor(model => model.UserName, new FooAttributes {Required=true, Message="Please enter a value." })

并且会生成这个html:

<input foo:message="Please enter a value." foo:required="true" id="UserName" name="UserName" type="text" value="">

一旦你有了自己的助手,你就可以添加额外的逻辑,例如从模型元数据及其数据注释属性生成这些属性的逻辑......

我的答案超出了预期,但我希望它有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-09
    • 2023-03-11
    • 1970-01-01
    • 2012-05-27
    相关资源
    最近更新 更多