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