在编辑器模板中迭代集合时,NameFor会生成错误的名称
假设我有一个类型为集合的视图,例如List
:
@model List @for(int i = 0; i m[i].Foo) @Html.EditorFor(m => m[i].Bar) }
Foo
和Bar
只是字符串属性。
这将生成[i].Foo
和[i].Bar
forms的HTML名称属性,当然,这些属性是正确的,并且在表单中发布时可以正确绑定。
现在假设上面的视图是一个编辑器模板,它是这样呈现的(其中Model.Items
是List
):
@model WrappingViewModel @Html.EditorFor(m => m.Items)
突然之间,编辑器模板中生成的名称的forms – 例如 – Items.[i].Foo
。 默认模型绑定器不能绑定它,因为它需要表单Items[i].Foo
。
这在第一个场景中运行良好 – 视图不是编辑器模板 – 并且在集合是属性的情况下也可以正常工作,而不是整个模型:
@Html.EditorFor(m => m.Items[i].Foo)
它仅在模型本身是集合且视图是编辑器模板时失败。
有几种方法可以解决这个问题,其中没有一个是理想的:
- 将编辑器模板键入到
ItemViewModel
的单个实例中 – 这不好,因为相关的实际模板包含用于添加到集合中/从集合中删除的附加标记。 我需要能够使用模板中的整个集合。 - 将
List
包装在另一个属性中(例如通过实现ItemListViewModel
)并将其传递给模板 – 这也不是理想的,因为这是一个企业应用程序,我宁愿不会因多余的包装视图模型而混乱。 - 手动生成内部编辑器模板的标记以生成正确的名称 – 这是我目前正在做的但我宁愿避免它,因为我失去了HtmlHelpers的灵活性。
所以,问题是:为什么NameFor
(以及因此EditorFor
)在这种特殊情况下表现出这种行为,当它适用于轻微变化时(即它是有意的,如果是,为什么)? 是否有一种简单的方法来解决这种行为而没有上述任何缺点?
根据要求,完整代码重现:
楷模:
public class WrappingViewModel { [UIHint("_ItemView")] public List Items { get; set; } public WrappingViewModel() { Items = new List(); } } public class ItemViewModel { public string Foo { get; set; } public string Bar { get; set; } }
控制器动作:
public ActionResult Index() { var model = new WrappingViewModel(); model.Items.Add(new ItemViewModel { Foo = "Foo1", Bar = "Bar1" }); model.Items.Add(new ItemViewModel { Foo = "Foo2", Bar = "Bar2" }); return View(model); }
Index.cshtml:
@model WrappingViewModel @using (Html.BeginForm()) { @Html.EditorFor(m => m.Items) }
_ItemView.cshtml(编辑器模板):
@model List @for(int i = 0; i m[i].Foo) @Html.EditorFor(m => m[i].Bar) }
Foo
和Bar
输入的名称属性将采用Model.[i].Property
的forms,并且在发布到具有签名ActionResult Index(WrappingViewModel)
的操作方法时不会绑定回来。 请注意,如上所述,如果您在主视图中迭代Items
, 或者如果您摆脱了WrappingViewModel
,则使顶层模型成为List
并直接迭代Model
可以正常工作。 它只适用于此特定方案。
为什么
NameFor
(以及因此EditorFor
)在这种特殊情况下表现出这种行为,当它适用于轻微变化时(即它是有意的,如果是,为什么)?
这是一个错误( 链接 ),它将通过ASP.NET MVC 5的发布来修复。
是否有一种简单的方法来解决这种行为而没有上述任何缺点?
简单:
-
使用以下代码添加
ItemViewModel.cshtml
编辑器模板:@model ItemViewModel @Html.EditorFor(m => m.Foo) @Html.EditorFor(m => m.Bar)
-
删除
_ItemView.cshtml
编辑器模板。 - 从
[UIHint("_ItemView")]
删除[UIHint("_ItemView")]
属性。
有点难:
-
添加
ItemViewModel.cshtml
编辑器模板(与上面相同)。 -
修改
_ItemView.cshtml
:@model List
@{ string oldPrefix = ViewData.TemplateInfo.HtmlFieldPrefix; try { ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty; for (int i = 0; i < Model.Count; i++) { var item = Model[i]; string itemPrefix = string.Format("{0}[{1}]", oldPrefix, i.ToString(CultureInfo.InvariantCulture)); @Html.EditorFor(m => item, null, itemPrefix) } } finally { ViewData.TemplateInfo.HtmlFieldPrefix = oldPrefix; } }
UPDATE
如果您不想为第二个选项添加ItemViewModel.cshtml
编辑器模板,而不是@Html.EditorFor(m => item, null, itemPrefix)
您必须编写类似的内容:
@Html.EditorFor(m => item.Foo, null, Html.NameFor(m => item.Foo).ToString().Replace("item", itemPrefix)) @Html.EditorFor(m => item.Bar, null, Html.NameFor(m => item.Bar).ToString().Replace("item", itemPrefix))
注意 :最好将该段代码包装为扩展方法
- Sitecore – ControllerRendering抱怨控制器“未找到或未实现IController”。
- 无法加载文件或程序集’EntityFramework,Version = 6.0.0.0,
- 如何在.Net MVC中更改DateTime模型绑定器上的默认输入格式?
- entity framework:在运行时更改连接字符串
- 无法使用FormsAuthentication.SignOut()从ASP.NET MVC应用程序注销
- Unity:当前类型是一个接口,无法构造
- 从Server for ASP.Net MVC Ajax请求重定向到新页面
- 为什么我不能从Controller初始化程序访问HttpContext?
- .NET MVC 6 / vNext UserValidator允许使用字母数字字符