动态复选框 - 错误:集合是只读的

时间:2014-07-30 14:03:52

标签: c# asp.net asp.net-mvc-4 visual-studio-2012

我对MVC4很陌生,而我之前使用asp.net的经历一直在与Webforms合作,所以我觉得我需要小心谨慎。提前谢谢!

我正在创建一个类似于选择乐透号码的简单Web应用程序。用户选择他们想要的任何数字(没有限制,从" 1"开始)并将其发布到下一页,我继续使用用户选择的数字。数字的数量 - 可供选择是动态的,并由复选框表示。

问题是,当提交视图时,我会收到错误页面"收集是只读的。"

模型 - LottoNumbers.cs bool []数字用于存储用户已检查过的数字。

namespace Lotto.Models
{
    public class LottoNumbers
    {
        public string name { get; set; }
        public bool[] numbers { get; set; }

        public LottoNumbers() {
            numbers = new bool[49];
        }

        public LottoNumbers(int limit)
        {
            numbers = new bool[limit];
        }
    }
}
HomeController.cs中的

... 我宣布了LottoNumbers ln和

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Lotto.Models;

namespace Lotto.Controllers
{
    public class HomeController : Controller
    {
        public LottoNumbers ln;

        public ActionResult Index()
        {
            return View();
        }

        public ActionResult SetNumbers()
        {
            ln = new LottoNumbers(30); 
            // 30 checkboxes will be generated on the view

            return View(ln);
        }

        [HttpPost]
        public ViewResult SetNumbers(LottoNumbers l)
        {
            // get checkbox values
            return View();
        }
    }
}

查看 - SetNumbers.cshtml

@model Lotto.Models.LottoNumbers
@{
    ViewBag.Title = "SetNumbers";
}
<h2>SetNumbers</h2>

@using (Html.BeginForm()) {
    <div>
        @Html.LabelFor(m => m.name)
        @Html.EditorFor(m => m.name)
    </div>

    <div id="numberlist">
    @for (int i = 0; i < Model.numbers.Length; i++)
    {
    <div class="item-number" style="">
        @Html.EditorFor(m => m.numbers[i])
        <label class="lbl-number" for="numbers[@i]">@(i+1)</label>
    </div>
    }
    </div>
    <div style="clear:both;">
        <input type="reset" value="Reset everything" />
        <input type="submit" value="Submit" />
    </div>

}

2 个答案:

答案 0 :(得分:3)

将数组更改为列表。

  public string Name { get; set; }
    public List<bool> Numbers { get; set; }

    public LottoNumbers()
    {
        Numbers = new List<bool>();
        for (var i = 0; i < 40; i++)
        {
            Numbers.Add(false);
        }
    }

    public LottoNumbers(int limit)
    {
        Numbers = new List<bool>();
        for (var i = 0; i < limit; i ++)
        {
            Numbers.Add(false);
        }
    }

然后您的视图将是

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(m => m.Name)
        @Html.EditorFor(m => m.Name)
    </div>

    <div id="numberlist">
        @for (var i = 0; i < Model.Numbers.Count; i++)
        {
            <div class="item-number" style="">
                @Html.CheckBox("Numbers[" + i.ToString() + "]")
                <label class="lbl-number" for="numbers[@(i + 1)]">@(i + 1)</label>

            </div>
        }
    </div>
    <div style="clear:both;">
        <input type="reset" value="Reset everything" />
        <input type="submit" value="Submit" />
    </div>

}

空参考例外

您最有可能在提交后获得空引用异常,因为您没有将模型传递回视图。您将页面设置为期望LottoNumbers模型。

[HttpPost]
public ViewResult SetNumbers(LottoNumbers l)
{
    // get checkbox values
    return View(); //Nothing being passed to the view
}

所以在您的代码到达此处后发布

@foreach (var numberBool in Model.Numbers)
当模型为空时,它会爆炸。您可以通过多种方式解决此问题,具体取决于您希望应用的运行方式。如果您希望用户在提交后看到一个空白的数字列表,只需执行此操作并在回发后添加某种成功消息

[HttpPost]
public ViewResult SetNumbers(LottoNumbers l)
{
    //process stuff
    ln = new LottoNumbers(30);
    return View(ln);
}

您也可以简单地将用户重定向回索引页面。无论哪种方式,都会导致错误,因为您没有将带有数字的模型传递回视图。

答案 1 :(得分:2)

如果您查看&#34的堆栈跟踪;收集是只读的#34;错误,您可以看到它在模型绑定期间发生,也就是它尝试从表单帖子传回的数据重新创建您的LottoNumbers对象。

您正在收到错误,因为您使用带有参数的构造函数初始化数组大小的对象,但是当它回发数据时,它不会知道数组在重新创建对象时需要的大小。

要解决此问题,最好使用List,并将大小作为LottoNumbers对象的属性。

使用List意味着您不必使用大小预先初始化数组。将大小作为属性意味着您可以将大小嵌入到隐藏的输入变量中,以便可以将其传递回控制器,并且应该正确地进行模型绑定。