!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)
我在这里的方法可能完全错误,但我正在慢慢学习 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)