Использование TextBoxFor для установки атрибутов HTML, имеющих префикс пространства имен

Я конвертирую некоторый существующий HTML для работы с ASP.NET MVC, и у меня есть некоторые формы, содержащие поля ввода, которые имеют дополнительные атрибуты (которые на данный момент мне нужно сохранить), которые содержат префикс пространства имен:

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

Я хотел бы использовать TextBoxFor перегрузка вспомогательного метода, которая позволяет 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 элемент?

1 ответ

Решение

Первый синтаксис использует анонимный объект, для которого применяются те же правила относительно того, как создавать идентификаторы в C#:

  • Вы можете использовать любой юникодный символ классов Lu, Ll, Lt, Lm, Lo, or Nl
  • Вы можете использовать ключевые слова C#, используя "@", как в new { @class = "foo" };

Так как двоеточие принадлежит классу Unicode Po, его нельзя использовать в идентификаторе. (В C# вы можете использовать статический метод char.GetUnicodeCategory для проверки класса любого символа)

Кроме того, и только в MVC при использовании анонимного объекта для атрибутов html в помощнике любое имя атрибута с подчеркиванием будет заменено дефисами. Это связано с методом HtmlHelper.AnonymousObjectToHtmlAttributes

Возвращаясь к вашему случаю и касаемо ваших вариантов, если они не слишком широко используются (например, в нескольких видах), я бы остановился на синтаксисе Dictionary TextBoxFor помощник. Вы по-прежнему будете автоматически генерировать свойства 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="">

И когда у вас есть свой помощник, вы можете добавить дополнительную логику, например логику, которая будет генерировать эти атрибуты из метаданных модели и ее атрибутов аннотации данных...

Я расширил свой ответ больше, чем предполагалось, но я надеюсь, что это поможет!

Другие вопросы по тегам