TextBoxFor vs EditorFor и htmlAttributes vs addViewData

Я создал проект MVC 3 по умолчанию (используя бритву), чтобы продемонстрировать проблему.

На странице входа в систему есть строка:

@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="" />

Таким образом, атрибут title теряется, когда я использую EditorFor.

Я знаю, что второй параметр для TextBoxFor называется htmlAttributes, а для EditorFor это дополнительныйViewData, однако я видел примеры, где EditorFor может отображать атрибуты, поставляемые с этим параметром.

Может кто-нибудь объяснить, что я делаю неправильно, и как я могу иметь атрибут title при использовании редактора?

Ответ 1

Думаю, я нашел немного более приятное решение. EditorFor принимает в качестве параметра параметр extraViewData. Если вы дадите ему параметр с именем "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. [email protected])" } })

В шаблоне (в этом случае 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])))));
}

Ответ 2

В MVC3 вы можете добавить заголовок (и другие htmlAttributes), используя этот способ обхода, если вы создадите собственный шаблон EditorFor. Этот случай подготовлен для того, чтобы значение было необязательным, 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

Вы можете взглянуть на после сообщения в блоге, в котором показано, как реализовать пользовательский поставщик метаданных и использовать аннотации данных в вашей модели представлений в чтобы определить html-свойства, такие как class, maxlength, title,... Это можно было бы использовать в сочетании с шаблонами-помощниками.