MVC张贴复杂对象的列表 [英] MVC post a list of complex objects
问题描述
我有一个包含问题列表的FeedbackViewModel:
公共类FeedbackViewModel
{
公开名单< QuestionViewModel>问题{搞定;组; }
}
这QuestionViewModel是可以通过5种不同类型的问题被继承的对象
公共类QuestionViewModel
{
公共字符串QuestionText {搞定;组; }
公共字符串QuestionType {搞定;组; }
}
继承的问题类型的一个例子:
公共类SingleQuestionViewModel:QuestionViewModel
{
公共字符串AnswerText {搞定;组; }
}
在 HTTPGET
控制器我从数据库中获取的问题首页
的行动,并添加正确的在问题清单问题类型的 FeedbackViewModel
然后我呈现在视图中这个模型:
@using(Html.BeginForm())
{
//的foreach(在Model.Questions VAR项)
的for(int i = 0; I< Model.Questions.Count;我++)
{
< DIV CLASS =表单组>
@ Html.DisplayFor(modelItem => Model.Questions [I] .QuestionText,新{@class =控制标签COL-MD-4})
< DIV CLASS =COL-MD-6>
@if(Model.Questions [I] .QuestionType ==单次)
{
@ Html.EditorFor(modelItem =>(Model.Questions [I]作为OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
否则,如果(Model.Questions [I] .QuestionType ==多)
{
@ Html.TextAreaFor(modelItem =>(Model.Questions [I]作为OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
否则,如果(Model.Questions [I] .QuestionType ==SingleSelection)
{
@ Html.RadioButtonForSelectList(modelItem =>(Model.Questions [I]作为OpenDataPortal.ViewModels.SingleSelectionQuestionViewModel).SelectedAnswer,
(Model.Questions [I]作为OpenDataPortal.ViewModels.SingleSelectionQuestionViewModel).SelectionAnswers)
}
否则,如果(Model.Questions [I] .QuestionType ==MultipleSelection)
{
@ Html.CustomCheckBoxList((Model.Questions [I]作为OpenDataPortal.ViewModels.MultipleSelectionQuestionViewModel).AvailableAnswers)
}
否则,如果(Model.Questions [I] .QuestionType ==UrlReferrer)
{
@ Html.EditorFor(modelItem =>(Model.Questions [I]作为OpenDataPortal.ViewModels.SingleQuestionViewModel).AnswerText)
}
< / DIV>
< / DIV>
< BR />
} < BR />
<按钮式=提交>提交< /按钮>
}
现在,我根本无法把它张贴在模型问题的清单。它甚至有可能发布不同的对象类型的列表?
编辑:以下是帖子中的数据列表,我使用招发现:
经过大量的研究,我发现两个解决方案:
一是写出具有硬$ C $光盘ID和姓名HTML
二是你的ICollection / IEnumerable的转换为数组或列表(即IList的东西与索引),并在你的控制器POST操作您的BindingModel有一个Array对象。
由于菲尔哈克的(@haacked)2008年的博客文章<一个href=\"http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/\">http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
这仍然是有关如何今天ModelBinder的工程MVC的默认。
(注:在菲尔的文章的链接来样,项目和扩展方法被破坏)
HTML片段,启发了我:
&LT;形式方法=邮报行动=/首页/新建&GT;
&LT;输入类型=隐藏的名字=products.IndexVALUE =冷/&GT;
&LT;输入类型=文本名称=产品[感冒] .Name点值=啤酒/&GT;
&LT;输入类型=文本名称=产品[感冒]。价格值=7.32/&GT; &LT;输入类型=隐藏的名字=products.IndexVALUE =123/&GT;
&LT;输入类型=文本名称=产品[123] .Name点值=筹码/&GT;
&LT;输入类型=文本名称=产品[123]。价格值=2.23/&GT; &LT;输入类型=提交/&GT;
&LT; /表及GT;
发表阵列看起来有点像:
<$p$p><$c$c>products.Index=cold&products[cold].Name=Beer&products[cold].Price=7.32&products.Index=123&products[123].Name=Chips&products[123].Price=2.23型号:
公共类CreditorViewModel
{
公共CreditorViewModel()
{
this.Claims =新的HashSet&LT; CreditorClaimViewModel&GT;();
}
[键]
公众诠释CreditorId {搞定;组; }
公共字符串评论{搞定;组; }
公众的ICollection&LT; CreditorClaimViewModel&GT;声明{搞定;组; }
公共CreditorClaimViewModel [] {ClaimsArray
{返回Claims.ToArray(); }
}
}公共类CreditorClaimViewModel
{
[键]
公众诠释CreditorClaimId {搞定;组; }
公共字符串CreditorClaimType {搞定;组; }
[DisplayFormat(ApplyFormatInEditMode = TRUE,DataFormatString ={0:N2})]
公共小数ClaimedTotalAmount {搞定;组; }
}
控制器GET:
公共异步任务&LT;&的ActionResult GT;编辑(INT ID)
{
VAR testmodel =新CreditorViewModel
{
CreditorId = 1,
评论=测试,
声明=新的HashSet&LT; CreditorClaimViewModel&GT; {
新CreditorClaimViewModel {CreditorClaimId = 1,CreditorClaimType =1,ClaimedTotalAmount = 0.00M}
新CreditorClaimViewModel {CreditorClaimId = 2,CreditorClaimType =2,ClaimedTotalAmount = 0.00M}
}
};
返回查看(模型);
}
Edit.cshtml:
@ Html.DisplayNameFor(M = GT; m.Comments)
@ Html.EditorFor(M = GT; m.Comments)&LT;表类=表&GT;
&所述; TR&GT;
&LT;第i个
@ Html.DisplayNameFor(M =&GT; Model.Claims.FirstOrDefault()CreditorClaimType)。
&LT; /第i
&LT;第i个
@ Html.DisplayNameFor(M =&GT; Model.Claims.FirstOrDefault()ClaimedTotalAmount)。
&LT; /第i
&LT; / TR&GT;
&LT;! - 方案一 - &GT;
@foreach(在Model.Claims VAR项)
{
VAR场preFIX =的String.Format({0} [{1}],索赔,item.CreditorClaimId);
&所述; TR&GT;
&所述; TD&GT;
@ Html.DisplayFor(M = GT; item.CreditorClaimType)
&LT; / TD&GT;
&所述; TD&GT;
@ Html.TextBox(场preFIX +ClaimedTotalAmount,item.ClaimedTotalAmount.ToString(F),
新
{
@class =文本框单行
data_val =真,
data_val_number =字段ClaimedTotalAmount必须是一个数字。,
data_val_required =该ClaimedTotalAmount字段是必需的。
})
@ Html.Hidden(名称:Claims.index,值:item.CreditorClaimId,htmlAttributes:空)
@ Html.Hidden(名称:字段preFIX +CreditorClaimId,值:item.CreditorClaimId,htmlAttributes:空)
&LT; / TD&GT;
&LT; / TR&GT;
}
&LT; /表&gt;
&LT;! - 方案二 - &GT;
@for(VAR itemCnt = 0; itemCnt&下; Model.ClaimsArray.Count(); itemCnt ++)
{
&所述; TR&GT;
&LT; TD&GT;&LT; / TD&GT;
&所述; TD&GT;
@ Html.TextBoxFor(M = GT; Model.ClaimsArray [itemCnt] .ClaimedTotalAmount)
@ Html.HiddenFor(M = GT; Model.ClaimsArray [itemCnt] .CreditorClaimId)
&LT; / TD&GT;&LT; / TR&GT;
}
形式是在控制器处理:
邮政型号:
公共类CreditorPostViewModel
{
公众诠释CreditorId {搞定;组; }
公共字符串评论{搞定;组; }
公众的ICollection&LT; CreditorClaimPostViewModel&GT;声明{搞定;组; }
公共CreditorClaimPostViewModel [] {ClaimsArray获得;组; }
}公共类CreditorClaimPostViewModel
{
公众诠释CreditorClaimId {搞定;组; }
公共小数ClaimedTotalAmount {搞定;组; }
}
控制器:
[HttpPost]
公众的ActionResult编辑(INT ID,CreditorPostViewModel creditorVm)
{
// ...
I have a FeedbackViewModel that contains a list of questions:
public class FeedbackViewModel
{
public List<QuestionViewModel> Questions { get; set; }
}
This QuestionViewModel is an object that can be inherited by 5 different types of questions
public class QuestionViewModel
{
public string QuestionText { get; set; }
public string QuestionType { get; set; }
}
An example of one of the inheriting question types:
public class SingleQuestionViewModel : QuestionViewModel
{
public string AnswerText { get; set; }
}
In the HttpGet
of the Index
action in the controller I get the questions from the database and add the correct question type in list of question in the FeedbackViewModel
Then I render this model in the view:
@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>
}
Now, I simply can't get it to post the list of questions in the model. Is it even possible to post a list of different object types?
Edit: Following is the list of data within the post that I discovered using Fiddler:
After much research I've found two solutions:
One is to write HTML that has hardcoded Id's and Names Two is to convert your ICollection/IEnumerable to an Array or List (i.e IList something with an 'index'), and have an Array object in your BindingModel in your Controller POST Action.
Thanks to Phil Haack's (@haacked) 2008 blog post http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ Which is still relevant to how the default ModelBinder works today for MVC. (NB: the links in Phil's article to sample porject and extension methods are broken)
HTML snippet that inspired me:
<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 array looks a bit like:
products.Index=cold&products[cold].Name=Beer&products[cold].Price=7.32&products.Index=123&products[123].Name=Chips&products[123].Price=2.23
Model:
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; }
}
Controller 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", ClaimedTotalAmount=0.00M},
}
};
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", 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>
}
Form is processed in the Controller:
Post Model:
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; }
}
Controller:
[HttpPost]
public ActionResult Edit(int id, CreditorPostViewModel creditorVm)
{
//...
这篇关于MVC张贴复杂对象的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!