Asp.net-Mvc
MVC 發布複雜對象列表
我有一個包含問題列表的 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中的Index操作中,我從數據庫中獲取問題並在問題列表中添加正確的問題類型,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 和名稱的 HTML
- 二是將您的 ICollection/IEnumerable 轉換為數組或列表(即 IList 帶有“索引”的東西),並在控制器 POST 操作中的 BindingModel 中有一個數組對象。
感謝 Phil Haack (@haacked) 2008 年的部落格文章<http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/> 這仍然與今天的預設 ModelBinder 的工作方式有關對於 MVC。(注意:Phil 文章中範例項目和擴展方法的連結已損壞)
啟發我的 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>Post 數組看起來有點像:
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; } }控制器獲取:
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", ClaimedTotalAmount=0.00M}, } }; return View(model); }編輯.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", value: item.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> }表單在 Controller 中處理:
崗位型號:
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) { //...

