MVC Complex模型按索引绑定到列表

时间:2015-11-06 17:25:00

标签: c# asp.net-mvc

真的可以在这里使用另一组眼睛,我做错了什么?

型号:

public class reqView {
    public string Name { get; set; }
    /* Loads of properties */
    private lsAddress _addresses = new lsAddress {
        new Address { id = 1 }, new Address { id = 2 }
    };
    public lsAddress lsAddress {
        get { return _addresses; }
        set { _addresses = value; }
    }
}

查看:

@Html.DropDownListFor(model => model.lsAddress[1].addrCC,
                        new SelectList(CacheConfig.Countries.Where(c => c.dix.Contains(Model.dix)), "id", "text", Model.lsAddress[1].addrCC),
                        new {@class = "form-control"} as object);

控制器:

public ActionResult Index() {
        var model = (reqView) TempData["reqView"];

        if (model == null) model = new reqView();

        TempData["reqView"] = model;

        return View(model);
    }

lsAddress:

public class lsAddress : List<Address>, IEnumerable<SqlDataRecord>{
    IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
    {
        var sqlRow = new SqlDataRecord(
            new SqlMetaData("id", System.Data.SqlDbType.TinyInt, false, true, SortOrder.Unspecified, -1),
            new SqlMetaData("nmContact", System.Data.SqlDbType.NVarChar, 80)
            );

        foreach (Address obj in this)
        {
            sqlRow.SetValue(0, obj.id);
            sqlRow.SetValue(1, obj.cName);
            yield return sqlRow;
        }
    }
}  

要复制:.net fiddle 选择1然后2 - &gt;指数超出范围 选择2然后1 - >;对象引用未设置为对象的实例。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

问题在于:如何在提交时绑定模型属性。

1)你在构造函数中初始化_addresses,所以如果在提交时你没有传递这个属性的值,那么默认情况下这将是:带有两个元素的列表。

这就是为什么当您从0变体提交时所有内容都有效:您将已禁用属性设置为选择,并在提交时未提供此值。

2)当你提交来自&#39; 1&#39 ;: select - enabled,并且具有映射到_addresses的第一个元素的名称时,MVC会从请求来看到字段,并替换列表with to element,它是在构造函数中创建的,用于列出来自请求的on元素。

这就是你1工作的原因,但是如果你看到他发送的内容 - 你会看到_addresses列出一个元素的模型。这就是为什么从1转到2时出错的原因 - 您只需发送包含一个元素的列表,但在视图中尝试从index = 1的元素获取值而不是0。

3)当您从2提交时:select也启用并且具有映射到_addresses的第一个元素的名称,但MVC无法从一个元素创建正确的列表,索引为不是0如果你看到post方法中的内容,你可以看到_addresses null

对于解决方案,您可以添加隐藏字段,这将是其他列表项的保存值:

@{var cur = -1;}
@switch (Model.dix)
{
    case 0:
        @Html.DropDownListFor(model => model.lsAddress[0].addrCC,
                new SelectList(mvc.Controllers.CacheConfig.Countries.Where(c => c.dix.Contains(Model.dix)), "id", "text", Model.lsAddress[0].addrCC),
                new { @class = "form-control", disabled = "disabled" } as object)
        break;
    case 1:
    @Html.DropDownListFor(model => model.lsAddress[0].addrCC,
                new SelectList(mvc.Controllers.CacheConfig.Countries.Where(c => c.dix.Contains(Model.dix)), "id", "text", Model.lsAddress[0].addrCC),
                new { @class = "form-control" } as object);
    cur = 0;                    
    break;
    case 2:
    @Html.DropDownListFor(model => model.lsAddress[1].addrCC,
                new SelectList(mvc.Controllers.CacheConfig.Countries.Where(c => c.dix.Contains(Model.dix)), "id", "text", Model.lsAddress[1].addrCC),
                new { @class = "form-control" } as object);
    cur = 1;
        break;
}
@for (int i = 0; i < Model.lsAddress.Count; i++)
{
    if (i == cur) { continue; }
    @Html.HiddenFor(model => model.lsAddress[i].addrCC)
}

DotNetFiddle