【发布时间】:2011-03-31 09:54:40
【问题描述】:
使用以下代码时,字段的id和标签的for属性中的id不相同。
<%: 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。
有谁知道造成这种情况的原因或解决方法(除了编写自己的整套输入/文本区域/选择帮助程序)?还是bug?
更新:
因为无论如何我都为标签使用了一个 html 帮助器,并为标签文本使用了第二个参数,所以我确实修改它以使用与表单字段帮助器相同的 id 生成代码。
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 中的问题。如果有原因的话。
顺便说一句:实际上不需要修改 HTML5 中的 id/for 属性,因为如果你愿意,拥有一个看起来像 ^~[] 的 id 是完全合法的。所有主流浏览器都支持它。 Mathias Bynens 很好地解释了这一点。
更新 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 字段的名称属性值。
【问题讨论】:
-
我也注意到了。虽然我从不在重复结构中使用标签。我用一张桌子。您是否在 foreach 循环中尝试过?看起来怎么样?
-
我实际上确实在 foreach 循环中使用了它,这是一个简化的示例,带有显式键以提高可读性。
标签: asp.net-mvc asp.net-mvc-2 html-helper