当使用Razor为具有子模型的复杂模型渲染窗体时,我们通常会使用局部视图来渲染子模型。
简单示例模型:
public class BlogPost
{
public string Content { get; set; }
public List<Comment> Comments { get; set; }
}
public class Comment
{
public string Content { get; set; }
}
BlogPost.cshtml:
@model BlogPost
@Html.TextAreaFor(x => x.Content)
@for (int i = 0; i < Model.Comments.Count; i++)
{
@Html.Partial('Comment', Model.Comments[i])
}
Comment.cshtml:
@model Comment
@Html.TextAreaFor(x => x.Content)
现在讨论这个问题:
假设我们要将所有字段的值发送到以BlogPost
为参数的控制器操作。字段将被张贴回控制器,如下所示:
Content=+内容+的+博客文章&内容=+第一个+注释&内容=+秒+评论
但是,我们需要MVC将它们正确映射到BlogPost
视图模型,我们需要这样的命名约定:
Content=+内容+的+博客文章&Comments[0].Content=+第一个+Comment&Comments[1].Content=第+秒+Comment
如何以干净的方式实现这一点?我们只能想到两种似乎都会影响设计的方法:
- 要么我们将
BlogPost
作为模型传递给局部视图,这样我们就可以定义如下的文本区域:@Html.TextAreaFor(x => x.Comments[i].Content)
。但这意味着我们将用于注释的局部视图与父视图模型相耦合——您可以考虑在不同的上下文中使用相同的局部视图的场景,如果局部视图依赖于父视图模型,则这是不可能的。此外,i
必须以某种方式传递到局部视图 - 或者我们回到用字符串明确定义每个字段的名称:
@Html.TextArea(ViewBag.Prefix + ".Content")
有什么方法可以告诉局部视图将某个前缀应用于所有字段名吗?
chiccodoro,
如果您创建类型为Comment
的EditorFor模板,mvc将为您完美地处理所有这些。然而,只有在DB中已经存在行的情况下,这种方法才能很好地工作。SO的Exampel:
提交父级&儿童在剃须刀
如果您需要动态创建新行,那么您必须使用一些技巧来允许字段按需操作。我使用了steven sandersons网站上的一篇文章,该文章允许您在运行时添加收藏项目,并且仍然保留不引人注目的验证等。请参阅此SO问题和相关文章参考:
使用表编辑可变长度列表,ASP.NET MVC 3样式