При использовании следующего кода идентификаторы поля и идентификатор в атрибуте for метки не идентичны.
<%: Html.LabelFor(x => x.Localizations["en"]) %> => Localizations[en]
<%: Html.TextBoxFor(x=> x.Localizations["en"]) %> => Localizations_en_
<%: Html.LabelFor(x => x.Localizations["en"].Property) %>
=> Localizations[en]_Property
<%: Html.TextBoxFor(x=> x.Localizations["en"].Property) %>
=> Localizations_en__Property
Я проследил код в отражателе и увидел, что способы генерирования значений различны. Не используется тот же вспомогательный метод.
LabelFor использует HtmlHelper.GenerateIdFromName
, а TextBoxFor использует TagBuilder#GenerateId
.
Кто-нибудь знает причину этого или обходной путь (кроме написания всего собственного набора помощников ввода / textarea / select)? Или это ошибка?
UPDATE:
Поскольку в любом случае я использую html-помощник для метки со вторым параметром для текста метки, я изменил его, чтобы использовать тот же код генерации идентификатора, что и для помощников поля формы.
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string labelText)
{
// The main part of this code is taken from the internal code for Html.LabelFor<TModel, TValue>(...).
var metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
var fieldName = ExpressionHelper.GetExpressionText(expression);
TagBuilder builder = new TagBuilder("label");
// Generate the id as for the form fields (adds it to self).
builder.GenerateId(fieldName);
// Use the generated id for the 'for' attribute.
builder.Attributes.Add("for", builder.Attributes["id"]);
// Remove the id again.
builder.Attributes.Remove("id");
builder.SetInnerText(labelText);
return MvcHtmlString.Create(builder.ToString());
}
Это решает мою непосредственную проблему, но не отвечает на вопрос, почему реализация выглядит так, как в MVC2. Если есть причина для этого.
Между прочим: нет необходимости фактически изменять атрибут id / for в HTML5, так как совершенно естественно иметь идентификатор, похожий на ^~[]
, если хотите. Все основные браузеры поддерживают это. Это хорошо объясняется Матиасом Биненсом .
ОБНОВЛЕНИЕ 2:
На самом деле это вообще не решает проблему, поскольку DefaultModelBinder все равно не может с ней связаться. Использование вложенных объектов в словарях не поддерживается генератором имен полей в MVC 2, так как он генерирует:
<input type="text" name="Dict[en]" value="(VALUE)">
Вместо того, что хочет связующее для модели:
<input type="hidden" name="Dict[0].Key" value="en">
<input type="text" name="Dict[0].Value" value="(VALUE)">
Странно, что так выходит из коробки.
Я пытался создать для нее привязку пользовательской модели, но я не могу заставить MVC2 использовать его, на чем бы я ни пытался:
ModelBinders.Binders.Add(typeof(IDictionary<string,object>), new DictionaryModelBinder());
ModelBinders.Binders.Add(typeof(IDictionary<string,string>), new DictionaryModelBinder());
ModelBinders.Binders.Add(typeof(IDictionary), new DictionaryModelBinder());
ModelBinders.Binders.Add(typeof(Dictionary), new DictionaryModelBinder());
Итак, сейчас все выглядит так, будто мы вернулись к ручному созданию значений атрибутов имени со скрытыми .Key
полями.