Ant*_*t P 9 c# asp.net-mvc asp.net-mvc-4
假设我有一个类型为集合的视图,例如List<ItemViewModel>:
@model List<ItemViewModel>
@for(int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(m => m[i].Foo)
@Html.EditorFor(m => m[i].Bar)
}
Run Code Online (Sandbox Code Playgroud)
Foo并且Bar只是字符串属性.
这产生以下形式的HTML名称属性[i].Foo并且[i].Bar,其中,当然,是正确的,在一个形式发布时正确地结合.
现在假设,上面的视图是一个编辑器模板,它是这样渲染的(其中Model.Items是a List<ItemViewModel>):
@model WrappingViewModel
@Html.EditorFor(m => m.Items)
Run Code Online (Sandbox Code Playgroud)
突然之间,编辑器模板中生成的名称的形式就是 - 例如 - Items.[i].Foo.默认的模型绑定器不能像预期的那样绑定它Items[i].Foo.
这在第一个场景中运行良好 - 视图不是编辑器模板 - 并且在集合是属性的情况下工作正常,而不是整个模型:
@Html.EditorFor(m => m.Items[i].Foo)
Run Code Online (Sandbox Code Playgroud)
它仅在模型本身是集合且视图是编辑器模板时失败.
有几种方法可以解决这个问题,其中没有一个是理想的:
ItemViewModel- 这不是好事,因为相关的实际模板包含用于添加到集合中/从集合中删除的附加标记.我需要能够使用模板中的整个集合.List<ItemViewModel>在另一个属性中(例如通过实现ItemListViewModel)并将其传递给模板 - 这也不是理想的,因为这是一个企业应用程序,我宁愿不用多余的包装视图模型混乱.所以,问题是:为什么NameFor(并因此EditorFor)在这种特殊情况下表现出这种行为,当它适用于轻微变化时(即它是有意的,如果是,为什么)?是否有一种简单的方法来解决这种行为而没有上述任何缺点?
根据要求,完整代码重现:
楷模:
public class WrappingViewModel
{
[UIHint("_ItemView")]
public List<ItemViewModel> Items { get; set; }
public WrappingViewModel()
{
Items = new List<ItemViewModel>();
}
}
public class ItemViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
控制器动作:
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);
}
Run Code Online (Sandbox Code Playgroud)
Index.cshtml:
@model WrappingViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(m => m.Items)
<input type="submit" value="Submit" />
}
Run Code Online (Sandbox Code Playgroud)
_ItemView.cshtml(编辑器模板):
@model List<ItemViewModel>
@for(int i = 0; i < Model.Count; i++)
{
@Html.EditorFor(m => m[i].Foo)
@Html.EditorFor(m => m[i].Bar)
}
Run Code Online (Sandbox Code Playgroud)
名称属性Foo和Bar输入将是表单的形式,Model.[i].Property并且在发布到具有签名的操作方法时不会绑定回来ActionResult Index(WrappingViewModel).请注意,如上所述,如果您Items在主视图中进行迭代,或者如果您将其删除WrappingViewModel,请将顶级模型设置为a List<ItemViewModel>并Model直接迭代,这样可以正常工作.它仅针对此特定方案失败.
为什么
NameFor(并因此EditorFor)在这种特殊情况下表现出这种行为,当它适用于轻微变化时(即它是有意的,如果是,为什么)?
这是一个错误(链接),它将通过ASP.NET MVC 5的发布来修复.
是否有一种简单的方法来解决这种行为而没有上述任何缺点?
简单:
ItemViewModel.cshtml使用以下代码添加编辑器模板:
@model ItemViewModel
@Html.EditorFor(m => m.Foo)
@Html.EditorFor(m => m.Bar)
Run Code Online (Sandbox Code Playgroud)删除_ItemView.cshtml编辑器模板.
[UIHint("_ItemView")]从中删除属性WrappingViewModel.有点难:
添加ItemViewModel.cshtml编辑器模板(与上面相同).
修改_ItemView.cshtml:
@model List<ItemViewModel>
@{
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;
}
}
Run Code Online (Sandbox Code Playgroud)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))
Run Code Online (Sandbox Code Playgroud)
注意:最好将该段代码包装为扩展方法
| 归档时间: |
|
| 查看次数: |
819 次 |
| 最近记录: |