!ModelState.IsValid 时复选框选中的值丢失

Checkbox checked value lost if !ModelState.IsValid

我在这里的方法可能完全错误,但我正在慢慢学习 MVC...我有一个表单,用户必须 select 一些(或没有)基于此模型的模块:

public class MyProductModule
{
    public string ModuleName { get; set; }
    public bool Checked { get; set; }
}

public class ProductRequest
{

    public ProductRequest()
    {
        Modules = LoadModules();
    }

    public static List<MyProductModule> LoadModules()
    {
        return new List<MyProductModule>()
        {
            new MyProductModule() { ModuleName = "Module One", Checked = false },
            new MyProductModule() { ModuleName = "Module Two", Checked = false },
            new MyProductModule() { ModuleName = "Module Three", Checked = false }
        };
    }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [DisplayName("MyProduct Modules")]
    public List<MyProductModule> Modules { get; set; }
}

呈现一个复选框列表以显示每个模块:

@for (int i = 0; i < Model.Modules.Count; i++)
{
    @Html.CheckBoxFor(m => m.Modules[i].Checked)
    @Html.HiddenFor(m => m.Modules[i].ModuleName)
    @Html.LabelFor(m => m.Modules[i].Checked, Model.Modules[i].ModuleName)
}

最后表单处理成这样:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ProcessRequest(ProductRequest qd)
{
    if (!ModelState.IsValid)
    {
        return View("Index", qd);
    }
    else
    {
        // check email domains
        List<string> badDomains = new List<string>();
        badDomains.Add("gmail");
        badDomains.Add("yahoo");
        badDomains.Add("hotmail");
        foreach (string s in badDomains)
        {
            if (qd.Email.Contains(string.Format("@{0}.", s)))
            {
                ModelState.AddModelError(string.Empty, string.Format("Please use your work email address.", s));
            }
        }

        if (!ModelState.IsValid)
        {
            return View("Index", qd);
        }
        else
        {
            // process
        }
    }
}

一切正常,除非由于某种原因我的服务器端验证失败,并且模型被发回 (return View("Index", qd);)。那时,复选框列表神秘地发生了变化:

[x] Module One
[ ] Module Two
[ ] Module Three

...为此:

[ ] Module One
[ ] Module Two
[ ] Module Three

所有复选框值都丢失了。如果我检查 Firebug 中的原始发布数据,我发现出于某种原因,选中的框 "checked" 值:

发布了 true 和 false

在服务器端,您的变量 qd 包含您从视图中 post 编辑的值: 对于每个 MyProductModule 你 post 只有 Checked 成员。

因此,当您使用 return View("Index", qd); 时,您仅向视图提供您拥有的值:Checked 成员。

如果你想拥有 ModuleName 成员,你必须 post 它与 Checked 成员

@Html.LabelFor(model => model.Modules, htmlAttributes: new { @class = "required" })
@for (int i = 0; i < Model.Modules.Count; i++)
{
   @Html.CheckBoxFor(m => m.Modules[i].Checked)
   @Html.HiddenFor(m => m.Modules[i].ModuleName)
   @Html.LabelFor(m => m.Modules[i].Checked, Model.Modules[i].ModuleName)
}

好的,我无法重现您的错误,但我可以建议另一种编写方法:使用编辑器模板

使用 @Html.EditorFor(m => m.Modules) 而不是 for 循环 你会得到类似

的东西
@using (Html.BeginForm("ProcessRequest", "Home"))
{
    @Html.AntiForgeryToken()
    @Html.TextBoxFor(m => m.Email)
    @Html.EditorFor(m => m.Modules)
    <input type="submit" value="send" />
}

然后创建一个 EditorTemplates 文件夹和一个名为 MyProductModule.cshtml

的新视图

MyProductModule.cshtml :

@model MyNamespace.MyProductModule

@Html.CheckBoxFor(m => m.Checked)
@Html.HiddenFor(m => m.ModuleName)
@Html.LabelFor(m => m.Checked, Model.ModuleName)