如何在.NET Core MVC中将表单绑定到父子结构的ViewModel
你现有的cshtml模板核心逻辑是符合ASP.NET MVC的集合绑定规则的,只要配套对应的ViewModel定义和控制器接收逻辑就可以正常运行,以下是完整的最优实现方案:
1 视图模板优化
你当前用for循环带索引渲染子项的写法是正确的,渲染出的input控件name属性会自动生成为PowerCurvePoints[0].Bin的格式,刚好匹配模型绑定的规则,仅需要注意两个点:
- GET请求渲染页面前,必须给父级ViewModel的
PowerCurvePoints集合初始化25-30个空的子ViewModel实例,否则for循环不会执行,不会渲染出子项输入框 - 可以将重复的子项渲染逻辑抽为局部视图,降低代码冗余,方便后续维护
抽局部视图的实现示例
新建_PowerCurvePointItem.cshtml局部视图:
@model PowerCurvePointViewModel @{ // 从视图数据获取当前子项的索引 int index = (int)ViewData["ItemIndex"]; } <div class="form-group"> <label asp-for="Bin" class="control-label"></label> <input asp-for="Bin" name="PowerCurvePoints[@index].Bin" class="form-control" /> <span asp-validation-for="Bin" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="WindSpeed" class="control-label"></label> <input asp-for="WindSpeed" name="PowerCurvePoints[@index].WindSpeed" class="form-control" /> <span asp-validation-for="WindSpeed" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="ActivePower" class="control-label"></label> <input asp-for="ActivePower" name="PowerCurvePoints[@index].ActivePower" class="form-control" /> <span asp-validation-for="ActivePower" class="text-danger"></span> </div>
主页面的循环部分简化为:
@for (var i = 0; i < Model.PowerCurvePoints.Count; i++) { @await Html.PartialAsync("_PowerCurvePointItem", Model.PowerCurvePoints[i], new ViewDataDictionary(ViewData) { {"ItemIndex", i} }) }
2 控制器绑定实现
首先定义和前端字段完全匹配的ViewModel结构:
// 子项ViewModel public class PowerCurvePointViewModel { public int Bin { get; set; } public decimal WindSpeed { get; set; } public decimal ActivePower { get; set; } } // 父级提交ViewModel public class PowerCurveCreateViewModel { public string Description { get; set; } // 必须用可索引的集合类型,比如List<T>,不要用IEnumerable<T> public List<PowerCurvePointViewModel> PowerCurvePoints { get; set; } = new List<PowerCurvePointViewModel>(); }
控制器的Post接收Action直接将父级ViewModel作为参数即可,模型绑定会自动填充所有字段:
[HttpPost] public IActionResult Create(PowerCurveCreateViewModel model) { if (ModelState.IsValid) { // 此处model.Description为提交的描述字段 // model.PowerCurvePoints已经包含所有25-30条提交的子项数据 // 执行业务保存逻辑即可 return RedirectToAction("Index"); } // 校验失败时回显数据 return View(model); }
常见问题排查
- 若提交后
PowerCurvePoints为空,先检查提交的表单字段name是否符合PowerCurvePoints[索引].属性名的格式 - 不要用
foreach循环渲染子项,不会生成带索引的name属性,会导致绑定失败 - 若需要客户端校验,确保页面引入了
jquery.validate.js和jquery.validate.unobtrusive.js两个脚本
内容的提问来源于stack exchange,提问作者Ross Halliday
相关产品推荐
相关产品推荐

