这个问题类似于之前提出的其他问题,但我的用法(和MVC知识)不同,所以我无法弄清楚如何调整其他答案以满足我的需求。
我有一个用户请求产品价格的表单。该产品有许多可选模块,这会影响整体价格。然后,控制器应该向我发送一封电子邮件,其中包含所选模块“DisplayName
。
我可以在请求表单中正确呈现这些模块标题,但在提交表单时无法读取它们。调试显示!ModelState.IsValid
,并且在模型状态中存在转换异常:
从类型'System.String'到类型的参数转换 'MyNamspace.Models.MyProductModule'失败,因为没有类型转换器 可以在这些类型之间进行转换。
我的整个方法可能有误,但我已经在产品模型中定义了模块(SO的简化示例),工作于this tutorial:
public class MyProductModule
{
public string ModuleName { get; set; }
public bool Checked { get; set; }
}
public class ProductRequest
{
public ProductRequest()
{
Modules = LoadModules();
}
private 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 }
};
}
[DisplayName("MyProduct Modules")]
public List<MyProductModule> Modules { get; set; }
}
这是我用来呈现复选框列表的代码:
@model MyNamespace.Models.ProductRequest
@foreach (var item in Model.Modules)
{
<label>
<input type="checkbox" name="Modules" value="@item.ModuleName" checked="@item.Checked" />
@item.ModuleName
</label>
}
以下是我尝试收集发布的表单数据的方法:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ProcessRequest(ProductRequest qd)
{
if (!ModelState.IsValid)
{
return View("Index", qd); // Code exits here with ModelState error
}
else
{
StringBuilder sb = new StringBuilder();
// null checks removed for brevity...
sb.Append("<ol>");
var selectedModules = qd.Modules.Where(x => x.Checked).Select(x => x).ToList();
foreach (MyProductModule sm in selectedModules)
{
sb.AppendFormat("<li>{0}</li>", sm.ModuleName);
}
sb.Append("</ol>");
}
// ....
}
非常感谢任何帮助或建议。作为一个长期的webforms开发人员,我发现MVC学习曲线无情!
见帖子回答。
答案 0 :(得分:2)
您可能希望像这样渲染视图:
for (var i = 0; i < Model.Modules.Count; i++ )
{
var item = Model.Modules[i];
<label>
@Html.CheckBox(string.Format("Modules[{0}].Checked", i), item.Checked)
@item.ModuleName
</label>
@Html.Hidden(string.Format("Modules[{0}].ModuleName", i), item.ModuleName)
}
答案 1 :(得分:2)
感谢Stephen Muecke ...
如建议的链接中所述,可以在不使用数据模型实例的情况下引用数据模型。因此,这是呈现复选框的正确方法:
<div>
@for (int i = 0; i < Model.Modules.Count; i++)
{
@Html.CheckBoxFor(m => m.Modules[i].Checked)
@Html.LabelFor(m => m.Modules[i].Checked, Model.Modules[i].ModuleName)
<br />
}
</div>
这确保列出所有模块,即使用户实际上并未全部选择它们,验证也会失败。
然后在发布表单时自动完成模型绑定,因此用于处理表单的控制器代码不需要修改需要稍微修改。获取所有可用模块的代码应该是静态的。这样,可以方便地“读取”/使所有模块可用。然后将该静态列表与用户提交的列表(可能只包含部分模块或不包含任何可用模块)进行比较:
List<MyProductModule> allModules = ProductRequest.LoadModules();
foreach(MyProductModule sm in qd.Modules)
{
if(sm.Checked)
{
sb.AppendFormat("<li>{0}</li>", allModules[qd.Modules.IndexOf(sm)].ModuleName);
}
}