我有一个Feedbackviewmodel包含一个问题列表:
public class Feedbackviewmodel { public List<Questionviewmodel> Questions { get; set; } }
这个Questionviewmodel是一个可以由5种不同类型的问题继承的对象
public class Questionviewmodel { public string QuestionText { get; set; } public string QuestionType { get; set; } }
一个继承问题类型的例子:
public class SingleQuestionviewmodel : Questionviewmodel { public string AnswerText { get; set; } }
在控制器中的索引操作的HttpGet中,我从数据库中获取问题,并在Feedbackviewmodel中的问题列表中添加正确的问题类型然后在视图中渲染此模型:
@using (Html.BeginForm()) { //foreach (var item in Model.Questions) for (int i = 0; i < Model.Questions.Count; i++) { <div class="form-group"> @Html.DisplayFor(modelItem => Model.Questions[i].QuestionText,new { @class = "control-label col-md-4" }) <div class="col-md-6"> @if (Model.Questions[i].QuestionType == "Single") { @Html.EditorFor(modelItem => (Model.Questions[i] as OpenDataPortal.viewmodels.SingleQuestionviewmodel).AnswerText) } else if (Model.Questions[i].QuestionType == "Multiple") { @Html.TextAreaFor(modelItem => (Model.Questions[i] as OpenDataPortal.viewmodels.SingleQuestionviewmodel).AnswerText) } else if (Model.Questions[i].QuestionType == "SingleSelection") { @Html.RadioButtonForSelectList(modelItem => (Model.Questions[i] as OpenDataPortal.viewmodels.SingleSelectionQuestionviewmodel).SelectedAnswer,(Model.Questions[i] as OpenDataPortal.viewmodels.SingleSelectionQuestionviewmodel).SelectionAnswers) } else if (Model.Questions[i].QuestionType == "MultipleSelection") { @Html.CustomCheckBoxList((Model.Questions[i] as OpenDataPortal.viewmodels.MultipleSelectionQuestionviewmodel).AvailableAnswers) } else if (Model.Questions[i].QuestionType == "UrlReferrer") { @Html.EditorFor(modelItem => (Model.Questions[i] as OpenDataPortal.viewmodels.SingleQuestionviewmodel).AnswerText) } </div> </div> <br /> } <br /> <button type="submit">Submit</button> }
现在,我根本无法让它在模型中发布问题列表.是否可以发布不同对象类型的列表?
编辑:以下是我发现使用Fiddler的帖子中的数据列表:
解决方法
经过多次研究,我发现了两个解决方案:
一个是编写具有硬编码的Id和Name的HTML
二是将您的ICollection / IEnumerable转换为数组或列表(即使用“索引”来IList),并在Controller POST Action中的BindingModel中有一个Array对象.
感谢Phil Haack(@haacked)2008年博客文章http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
哪个仍然与默认的ModelBinder如何在MVC上工作有关.
(注意:菲尔文章中关于采样和扩展方法的链接被打破)
启发我的HTML片段:
<form method="post" action="/Home/Create"> <input type="hidden" name="products.Index" value="cold" /> <input type="text" name="products[cold].Name" value="Beer" /> <input type="text" name="products[cold].Price" value="7.32" /> <input type="hidden" name="products.Index" value="123" /> <input type="text" name="products[123].Name" value="Chips" /> <input type="text" name="products[123].Price" value="2.23" /> <input type="submit" /> </form>
后阵列看起来有点像:
products.Index=cold&products[cold].Name=Beer&products[cold].Price=7.32&products.Index=123&products[123].Name=Chips&products[123].Price=2.23
模型:
public class Creditorviewmodel { public Creditorviewmodel() { this.Claims = new HashSet<CreditorClaimviewmodel>(); } [Key] public int CreditorId { get; set; } public string Comments { get; set; } public ICollection<CreditorClaimviewmodel> Claims { get; set; } public CreditorClaimviewmodel[] ClaimsArray { get { return Claims.ToArray(); } } } public class CreditorClaimviewmodel { [Key] public int CreditorClaimId { get; set; } public string CreditorClaimType { get; set; } [DisplayFormat(ApplyFormatInEditMode = true,DataFormatString = "{0:N2}")] public Decimal ClaimedTotalAmount { get; set; } }
控制器GET:
public async Task<ActionResult> Edit(int id) { var testmodel = new Creditorviewmodel { CreditorId = 1,Comments = "test",Claims = new HashSet<CreditorClaimviewmodel>{ new CreditorClaimviewmodel{ CreditorClaimId=1,CreditorClaimType="1",ClaimedTotalAmount=0.00M},new CreditorClaimviewmodel{ CreditorClaimId=2,CreditorClaimType="2",} }; return View(model); }
Edit.cshtml:
@Html.DisplayNameFor(m => m.Comments) @Html.EditorFor(m => m.Comments) <table class="table"> <tr> <th> @Html.DisplayNameFor(m => Model.Claims.FirstOrDefault().CreditorClaimType) </th> <th> @Html.DisplayNameFor(m => Model.Claims.FirstOrDefault().ClaimedTotalAmount) </th> </tr> <!--Option One--> @foreach (var item in Model.Claims) { var fieldPrefix = string.Format("{0}[{1}].","Claims",item.CreditorClaimId); <tr> <td> @Html.DisplayFor(m => item.CreditorClaimType) </td> <td> @Html.TextBox(fieldPrefix + "ClaimedTotalAmount",item.ClaimedTotalAmount.ToString("F"),new { @class = "text-Box single-line",data_val = "true",data_val_number = "The field ClaimedTotalAmount must be a number.",data_val_required = "The ClaimedTotalAmount field is required." }) @Html.Hidden(name: "Claims.index",value: item.CreditorClaimId,htmlAttributes: null) @Html.Hidden(name: fieldPrefix + "CreditorClaimId",htmlAttributes: null) </td> </tr> } </table> <!--Option Two--> @for (var itemCnt = 0; itemCnt < Model.ClaimsArray.Count(); itemCnt++) { <tr> <td></td> <td> @Html.TextBoxFor(m => Model.ClaimsArray[itemCnt].ClaimedTotalAmount) @Html.HiddenFor(m => Model.ClaimsArray[itemCnt].CreditorClaimId) </td></tr> }
表单在控制器中处理:
邮政型号:
public class CreditorPostviewmodel { public int CreditorId { get; set; } public string Comments { get; set; } public ICollection<CreditorClaimPostviewmodel> Claims { get; set; } public CreditorClaimPostviewmodel[] ClaimsArray { get; set; } } public class CreditorClaimPostviewmodel { public int CreditorClaimId { get; set; } public Decimal ClaimedTotalAmount { get; set; } }
控制器:
[HttpPost] public ActionResult Edit(int id,CreditorPostviewmodel creditorVm) { //...