问题
My approach here may be entirely wrong, but I'm slowly learning MVC... I have a form whereby a user must select a number of (or no) modules, based on this model:
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; }
}
A check box list is rendered to display each module:
@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)
}
Finally, the form is processed like this:
[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
}
}
}
Everything is working perfectly, unless for some reason my server-side validation fails, and the model is sent back (return View("Index", qd);
). At that point, the checkbox list mysteriously changes from this:
[x] Module One
[ ] Module Two
[ ] Module Three
...to this:
[ ] Module One
[ ] Module Two
[ ] Module Three
All of the checkbox values are lost. If I examine the raw posted data in Firebug, I see that for some reason both true AND false are posted for the checked boxes "checked" value:
回答1:
On the server side, your variable qd
contains the values you posted from view :
For each MyProductModule
you post only the Checked
member.
So when you use return View("Index", qd);
you give to the view only the value you have : Checked
member.
If you want to have the ModuleName
member, you have to post it alongside to the Checked
member
@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)
}
Ok, I can't reproduce your error, but I can suggest another way to write it : using an editor template
Instead of the for loop, use @Html.EditorFor(m => m.Modules)
You will have something like
@using (Html.BeginForm("ProcessRequest", "Home"))
{
@Html.AntiForgeryToken()
@Html.TextBoxFor(m => m.Email)
@Html.EditorFor(m => m.Modules)
<input type="submit" value="send" />
}
Then create a EditorTemplates folder and a new view named MyProductModule.cshtml
MyProductModule.cshtml :
@model MyNamespace.MyProductModule
@Html.CheckBoxFor(m => m.Checked)
@Html.HiddenFor(m => m.ModuleName)
@Html.LabelFor(m => m.Checked, Model.ModuleName)
来源:https://stackoverflow.com/questions/41223489/checkbox-checked-value-lost-if-modelstate-isvalid