You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Razor MVC如何实现嵌套列表与HTML元素递归绑定编辑及回传修复

问题解决方法

核心原因

ASP.NET MVC默认模型绑定要求嵌套集合的表单元素name属性必须携带完整层级路径和索引,比如:

  • 第一层子元素:ListaMateriales[0].Material
  • 第二层子元素:ListaMateriales[0].ListaMateriales[0].Cantidad
    你当前递归用foreach生成的所有输入框name都为material.xxx,没有索引和层级路径,所以绑定器只能识别到第一个同name的元素。

改造方案

  1. 修改递归Helper的参数,新增前缀参数用于拼接层级路径,改用for循环遍历集合获取索引
  2. 手动拼接或通过TemplateInfo设置字段前缀,保证所有表单元素的name符合绑定规则

改造后的核心代码示例

@helper ShowTree(List<DulcesDeLaRosa.Models.BilletesViewModel> ListaMateriales, string prefix = "ListaMateriales", int nivel = 0)
{
    if (ListaMateriales == null || !ListaMateriales.Any()) return;
    
    // 用for循环拿索引,不要用foreach
    for (int i = 0; i < ListaMateriales.Count; i++)
    {
        var material = ListaMateriales[i];
        // 拼接当前层级的前缀
        var currentPrefix = $"{prefix}[{i}]";
        var marginLeft = 30 * nivel;
        var marginString = marginLeft + "px;";
        
        <div class="form-inline col-12" style="margin-top:2%">
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            @* 设置当前上下文的字段前缀,后续EditorFor会自动拼接 *@
            @{ ViewData.TemplateInfo.HtmlFieldPrefix = currentPrefix; }
            
            @Html.HiddenFor(m => material.Id)
            <hr />
            <div class="col-4 delarosa-max-width">
                <div class="form-group col-12 delarosa-max-width" style="margin-left:@marginString">
                    @Html.EditorFor(m => material.Material, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                    @Html.ValidationMessageFor(m => material.Material, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-max-width">
                    @Html.EditorFor(m => material.Cantidad, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                    @Html.ValidationMessageFor(m => material.Cantidad, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-max-width">
                    @Html.DropDownListFor(m => material.UnidadDeMedidaId, material.ListaUnidadesDeMedida, new { @class = "form-control delarosa-max-width" })
                    @Html.ValidationMessageFor(m => material.UnidadDeMedidaId, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12 delarosa-max-width">
                    @Html.EditorFor(m => material.Merma, new { htmlAttributes = new { @class = "form-control delarosa-max-width" } })
                    @Html.ValidationMessageFor(m => material.Merma, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="col-2">
                <div class="form-group col-12">
                    <div class="col-9 offset-1">
                        <button type="submit" id="BtnAgregar" name="btn" class="btn btn-info delarosa-background" value="Agregar|@material.Id">Agregar Hijo</button>
                    </div>
                    <div class="col-2">
                        <button type="submit" id="BtnEliminar" name="btn" class="btn btn-info delarosa-background" value="Eliminar|@material.Id">X</button>
                    </div>
                </div>
            </div>
        </div>
        
        @* 递归调用子列表,传入拼接好的下一级前缀 *@
        if (material.ListaMateriales != null && material.ListaMateriales.Any())
        {
            <ul>
                @ShowTree(material.ListaMateriales, $"{currentPrefix}.ListaMateriales", nivel + 1)
            </ul>
        }
        
        @* 用完重置前缀,避免影响外层元素 *@
        @{ ViewData.TemplateInfo.HtmlFieldPrefix = ""; }
    }
}
  1. 调用Helper的地方去掉contador参数,改成:
@ShowTree(Model.ListaMateriales, "ListaMateriales", 0)

注意事项

  • 不需要修改控制器代码,Action参数依旧直接接收BilletesViewModel即可,模型绑定器会自动解析所有层级的嵌套列表
  • 动态添加/删除节点时,要保证新增节点的name属性索引是连续的,否则绑定器会跳过索引不连续的元素
  • 如果遇到校验不生效的问题,检查ValidationMessageFor对应的name是否和输入框的name完全一致

内容的提问来源于stack exchange,提问作者IvnBam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:36:01