MVC 4 List Model Binding如何工作?

Eri*_*ric 60 .net c# asp.net-mvc model-binding asp.net-mvc-4

如果我希望表单中的一组输入绑定到ListMVC 4中,我知道以下input name属性的命名约定将起作用:

<input name="[0].Id" type="text" />
<input name="[1].Id" type="text" />
<input name="[2].Id" type="text" />
Run Code Online (Sandbox Code Playgroud)

但我很好奇模型粘合剂是多么宽容.例如,以下内容如何:

<input name="[0].Id" type="text" />
<input name="[3].Id" type="text" />
<input name="[8].Id" type="text" />
Run Code Online (Sandbox Code Playgroud)

模型绑定器如何处理这个?它会List与null 结合长度为9吗?或者它仍然会绑定到List3的长度?还是会完全窒息?

为什么我在乎

我想实现一个动态表单,用户可以在其中向表单添加行,也可以从表单中删除行.因此,如果我用户从总共8行中删除第2行,我想知道是否需要重新编号所有后续输入.

Eri*_*sch 50

有一种特定的电线格式可用于集合.这将在Scott Hanselman的博客上讨论:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Phil Haack的另一篇博客文章在此处讨论了这个问题:

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

最后,博客条目完全符合您的要求:

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

  • 您应该将相关代码复制到答案中. (15认同)
  • @shashwat - 如何对开放式问题给出明确的是或否答案,答案不可能是肯定或否定? (4认同)
  • @AnimalsAreNotOursToEat `MVC 4 列表模型绑定如何工作?` **是** (3认同)
  • 请将信息放在答案本身中,这可以保护它免受链接腐烂。 (3认同)

Mat*_*hew 17

我遵循上面博客中链接的这种方法并添加了一些可能对某些人有帮助的细节 - 特别是因为我想动态添加任意数量的行但不想使用AJAX这样做(我希望表单只提交在文中).我也不想担心维护顺序ID.我正在捕获一个开始和结束日期列表:

查看型号:

public class WhenViewModel : BaseViewModel {
    public List<DateViewModel> Dates { get; set; }
    //... Other properties
}
Run Code Online (Sandbox Code Playgroud)

开始/结束日期视图模型:

public class DateViewModel {
    public string DateID { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后在页面中使用它们(使用datepicker):

<div class="grid-8-12 clear" id="DatesBlock">
@{
    foreach (DateViewModel d in Model.Dates) {
        @:<div class="grid-5-12 left clear">
            @Html.Hidden("Dates.Index", d.DateID)
            @Html.Hidden("Dates[" + d.DateID + "].DateID", d.DateID) //ID again to populate the view model
            @Html.TextBox("Dates[" + d.DateID + "].StartDate", 
                          d.StartDate.Value.ToString("yyyy-MM-dd"))
        @:</div>
        @:<div class="grid-5-12">
            @Html.TextBox("Dates[" + d.DateID + "].EndDate", 
                          d.EndDate.Value.ToString("yyyy-MM-dd"))
        @:</div>

        <script type="text/javascript">
            $('input[name="Dates[@d.DateID].StartDate"]')
               .datepicker({ dateFormat: 'yy-mm-dd'});
            $('input[name="Dates[@d.DateID].EndDate"]')
               .datepicker({dateFormat: 'yy-mm-dd'});
        </script>
     }
}
</div>
<a href="#" onclick="AddDatesRow()">Add Dates</a>
Run Code Online (Sandbox Code Playgroud)

正如上面描述的@ErikTheVikings帖子中链接的博客文章所述,该集合由重复的隐藏元素创建:@Html.Hidden("Dates.Index", d.DateID)对于页面上集合中的每个条目.

我想在不使用AJAX的情况下随意添加行,将数据发送回服务器,我通过创建一个隐藏的div包含集合中一个"row"/ item的模板:

隐藏的"模板"行:

<div id="RowTemplate" style="display: none">
    <div class="grid-5-12 clear">
        @Html.Hidden("Dates.Index", "REPLACE_ID")
        @Html.Hidden("Dates[REPLACE_ID].DateID", "REPLACE_ID") 
        @Html.TextBox("Dates[REPLACE_ID].StartDate", "")
    </div>
    <div class="grid-5-12">
        @Html.TextBox("Dates[REPLACE_ID].EndDate", "")
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

然后使用jQuery克隆模板,提供一个随机id用于新行,并将现在可见的克隆行追加到上面包含的div:

jQuery来完成这个过程:

<script type="text/javascript">
    function AddDatesRow() {
        var tempIndex = Math.random().toString(36).substr(2, 5);
        var template = $('#RowTemplate');
        var insertRow = template.clone(false);
        insertRow.find('input').each(function(){ //Run replace on each input
            this.id = this.id.replace('REPLACE_ID', tempIndex);
            this.name = this.name.replace('REPLACE_ID', tempIndex);
            this.value = this.value.replace('REPLACE_ID', tempIndex);
        });
        insertRow.show();
        $('#DatesBlock').append(insertRow.contents());

        //Attach datepicker to new elements
        $('input[name="Dates['+tempIndex+'].StartDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
        $('input[name="Dates['+tempIndex+'].EndDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
    }
</script>
Run Code Online (Sandbox Code Playgroud)

JSFiddle结果示例:http://jsfiddle.net/mdares/7JZh4/