Asp.net-Mvc

MVC 發布複雜對象列表

  • October 2, 2014

我有一個包含問題列表的 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 發現的文章中的數據列表:

在此處輸入圖像描述

經過大量研究,我找到了兩種解決方案:

  1. 一種是編寫具有硬編碼 ID 和名稱的 HTML
  2. 二是將您的 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 片段:

&lt;form method="post" action="/Home/Create"&gt;
   &lt;input type="hidden" name="products.Index" value="cold" /&gt;
   &lt;input type="text" name="products[cold].Name" value="Beer" /&gt;
   &lt;input type="text" name="products[cold].Price" value="7.32" /&gt;

   &lt;input type="hidden" name="products.Index" value="123" /&gt;
   &lt;input type="text" name="products[123].Name" value="Chips" /&gt;
   &lt;input type="text" name="products[123].Price" value="2.23" /&gt;

   &lt;input type="submit" /&gt;
&lt;/form&gt;

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&lt;CreditorClaimViewModel&gt;();
   }
   [Key]
   public int CreditorId { get; set; }
   public string Comments { get; set; }
   public ICollection&lt;CreditorClaimViewModel&gt; 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&lt;ActionResult&gt; Edit(int id)
   {
       var testmodel = new CreditorViewModel
       {
           CreditorId = 1,
           Comments = "test",
           Claims = new HashSet&lt;CreditorClaimViewModel&gt;{
               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 =&gt; m.Comments)
@Html.EditorFor(m =&gt; m.Comments)

&lt;table class="table"&gt;
   &lt;tr&gt;
       &lt;th&gt;
           @Html.DisplayNameFor(m =&gt; Model.Claims.FirstOrDefault().CreditorClaimType)
       &lt;/th&gt;
       &lt;th&gt;
           @Html.DisplayNameFor(m =&gt; Model.Claims.FirstOrDefault().ClaimedTotalAmount)
       &lt;/th&gt;
   &lt;/tr&gt;        
&lt;!--Option One--&gt;
@foreach (var item in Model.Claims)
{
   var fieldPrefix = string.Format("{0}[{1}].", "Claims", item.CreditorClaimId);
   &lt;tr&gt;
       &lt;td&gt;
           @Html.DisplayFor(m =&gt; item.CreditorClaimType)
       &lt;/td&gt;
       &lt;td&gt;
       @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)
       &lt;/td&gt;
   &lt;/tr&gt;
   }
&lt;/table&gt;    
&lt;!--Option Two--&gt;
@for (var itemCnt = 0; itemCnt &lt; Model.ClaimsArray.Count(); itemCnt++)
{
   &lt;tr&gt;
       &lt;td&gt;&lt;/td&gt;
       &lt;td&gt;
           @Html.TextBoxFor(m =&gt; Model.ClaimsArray[itemCnt].ClaimedTotalAmount)
           @Html.HiddenFor(m =&gt; Model.ClaimsArray[itemCnt].CreditorClaimId)
   &lt;/td&gt;&lt;/tr&gt;
}

表單在 Controller 中處理:

崗位型號:

public class CreditorPostViewModel
{
   public int CreditorId { get; set; }
   public string Comments { get; set; }
   public ICollection&lt;CreditorClaimPostViewModel&gt; 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)
   {
       //...

引用自:https://stackoverflow.com/questions/26155607