我遇到了一个问题,即通过POST复制一个复杂的ViewModel并且它的所有对象组件都为null,即使我已经在Action中初始化它们并使用GET方法将整个ViewModel返回给View。
让我解释一下情况。我有一个View的复杂模型,它包含三个部分:Applicant
详细信息,Application
详细信息和Recordings
列表。这个视图很复杂,(1)让我看到Applicant
我正在创建应用程序的详细信息,(2)有一个我想要选择的录音列表,然后我可以添加到Application
。这是我的ViewModel:
public class ApplicantApplicationRecordingsViewModel
{
// Applicant
public Applicant Applicant { get; set; }
// Application
public Application Application { get; set; }
public SelectList UsageTypeSelectList { get; private set; }
public SelectList UsageEndAppSelectList { get; private set; }
// Recordings
public IEnumerable<RecordingViewModelApp>
RecordingsViewModelApp { get; set; }
public ApplicantApplicationRecordingsViewModel()
: this(new MyDBContext())
{
}
public ApplicantApplicationRecordingsViewModel(MyDBContext dbContext)
{
PopulateUsageTypeSelectList(dbContext);
PupulateUsageEndAppSelectList(dbContext);
}
private void PopulateUsageTypeSelectList(MyDBContext dbContext,
int? usageTypeSelected = null)
{
IEnumerable<UsageType> utQuery =
dbContext.UsageTypes.OrderBy(
ut => ut.UsageTypeName).ToList();
this.UsageTypeSelectList =
new SelectList(utQuery,
"UsageTypeID",
"UsageTypeName",
usageTypeSelected);
}
private void PupulateUsageEndAppSelectList(
MyDBContext dbContext,
int? usageEndAppSelected = null)
{
IEnumerable<UsageEndApp> ueaQuery =
dbContext.UsageEndApps.OrderBy(uea => uea.UsageEndAppName).ToList();
this.UsageEndAppSelectList =
new SelectList(ueaQuery,
"UsageEndAppID",
"UsageEndAppName",
usageEndAppSelected);
}
}
在控制器中,我只需填充RecordingViewModelApp
的录音列表,将申请人的详细信息放入Applicant
,并将Application
对象留空,以便在视图中填充。
public ActionResult Create(int? ApplicantID)
{
if (ApplicantID == null)
{
// Error 400. Bad Request Exception
}
ApplicantApplicationRecordingsViewModel viewModel = null;
using (MyDBContext dbContext = new MyDBContext())
{
Applicant applicant =
dbContext.Applicants.Find(ApplicantID);
if (applicant == null)
{
// Error 404. Http not found
}
List<RecordingViewModelApp> recordings =
getViewModel(
dbContext.Recordings.ToList(),
dbContext);
viewModel =
new ApplicantApplicationRecordingsViewModel(dbContext);
viewModel.Applicant = applicant;
viewModel.RecordingsViewModelApp = recordings;
}
return View(viewModel);
}
问题在于,当我将ViewModel(ApplicantApplicationRecordingsViewModel
)返回到[HttpPost] Create()
操作时,所有View Model的组件都为空,例如RecordingViewModelApp
的列表为空。我错过了什么?我需要了解幕后发生的事情,以及为什么默认的模型绑定不起作用。
[HttpPost]
[ActionName("Create")]
public ActionResult Create_post(
ApplicantApplicationRecordingsViewModel viewModelToValidate)
{
// Validation against Application only and TryToUpdate() etc.
}
干杯!
<小时/> 编辑:
视图
@model Project.ApplicantApplicationRecordingsViewModel
@{
string applicantDetails = string.Format("{0} {1} {2}",
Model.Applicant.title, Model.Applicant.firstName, Model.Applicant.lastName);
ViewBag.Title = "Create a new application for " + applicantDetails;
}
<h2>@ViewBag.Title</h2>
<hr />
@using (Html.BeginForm())
{
<h3>Details of the applicant</h3>
@Html.HiddenFor(item => Model.Applicant.ApplicantID)
@Html.HiddenFor(item => Model.Application.ApplicationID)
<table>
<tr>
<th>@Html.DisplayNameFor(item => Model.Applicant.title)</th>
<th>@Html.DisplayNameFor(item => Model.Applicant.firstName)</th>
<th>@Html.DisplayNameFor(item => Model.Applicant.lastName)</th>
<th>@Html.DisplayNameFor(item => Model.Applicant.telephone)</th>
<th>@Html.DisplayNameFor(item => Model.Applicant.mobile)</th>
<th>@Html.DisplayNameFor(item => Model.Applicant.email)</th>
</tr>
<tr>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.title)</td>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.firstName)</td>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.lastName)</td>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.telephone)</td>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.mobile)</td>
<td class="display-field">@Html.DisplayFor(item => Model.Applicant.email)</td>
</tr>
</table>
<hr /> // ----------------------------------------------------------------------------------------------
<h3>Details of the application</h3>
<table id="main">
<tr>
<td>
<table>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.ApplicationNo)</td>
<td class="editor-field">
@Html.EditorFor(item => Model.Application.ApplicationNo)
@Html.ValidationMessageFor(item => Model.Application.ApplicationNo)
</td>
</tr>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.StartDate)</td>
<td class="editor-field">
@Html.EditorFor(item => Model.Application.StartDate)
@Html.ValidationMessageFor(item => Model.Application.StartDate)
</td>
</tr>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.EndDate)</td>
<td class="editor-field">
@Html.EditorFor(item => Model.Application.EndDate)
@Html.ValidationMessageFor(item => Model.Application.EndDate)
</td>
</tr>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.UsageTypeID)</td>
<td class="editor-field">
@Html.DropDownListFor(item => Model.Application.UsageTypeID, Model.UsageTypeSelectList, "-- Select Usage --")
@Html.ValidationMessageFor(item => Model.Application.UsageTypeID)
</td>
</tr>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.UsageEndAppID)</td>
<td class="editor-field">
@Html.DropDownListFor(item => Model.Application.UsageEndAppID, Model.UsageEndAppSelectList, "-- Select Type --")
@Html.ValidationMessageFor(item => Model.Application.UsageEndAppID)
</td>
</tr>
<tr>
<td class="editor-label first-label">@Html.DisplayNameFor(item => Model.Application.linkToPaperVer)</td>
<td class="editor-field">
@Html.EditorFor(item => Model.Application.linkToPaperVer)
@Html.ValidationMessageFor(item => Model.Application.linkToPaperVer)
</td>
</tr>
</table>
</td>
<td class="editor-label">
@Html.DisplayNameFor(item => Model.Application.Info)
</td>
<td class="editor-field">
@Html.EditorFor(item => Model.Application.Info)
@Html.ValidationMessageFor(item => Model.Application.Info)
</td>
</tr>
</table>
<hr /> // ----------------------------------------------------------------------------------------------
<h3>List of recordings</h3>
Html.RenderPartial("~/Views/Recordings/_List_App.cshtml", Model.RecordingsViewModelApp);
<hr /> // ----------------------------------------------------------------------------------------------
<p>
<input type="submit" value="Create" />
</p>
}
<div>
@Html.ActionLink("Back to List", "Index", "Applicants")
</div>
<小时/> 编辑2
PartialView:
@model IEnumerable<Project.ViewModels.RecordingViewModelApp>
@if (Model != null)
{
<div>
<table class="data-in-table">
<tr>
<th>@Html.DisplayNameFor(model => model.IsSelected)</th>
<th>@Html.DisplayNameFor(model => model.FileLocation)</th>
<th>@Html.DisplayNameFor(model => model.EnteredDate)</th>
<th>@Html.DisplayNameFor(model => model.Duration)</th>
<th>@Html.DisplayNameFor(model => model.Status)</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td class="display-field">@Html.EditorFor(model => item.IsSelected)</td>
<td class="display-field">@Html.DisplayFor(model => item.FileLocation)</td>
<td class="display-field">@Html.DisplayFor(model => item.EnteredDate)</td>
<td class="display-field">@Html.DisplayFor(model => item.Duration)</td>
<td class="display-field">@Html.DisplayFor(model => item.Status)</td>
</tr>
}
</table>
</div>
}
else
{
<h3>No recordings attached to this Patient</h3>
}
<小时/> 编辑3
RecordingViewModelApp
:
public class RecordingViewModel
{
public int RecordingID { get; set; }
public string FileLocation { get; set; }
public DateTime EnteredDate { get; set; }
public int Duration { get; set; }
public string Status { get; set; }
}
public class RecordingViewModelApp : RecordingViewModel
{
public bool IsSelected { get; set; }
}
答案 0 :(得分:1)
首先修复视图模型。视图模型应该只包含表示要显示和/或编辑的简单属性
查看模型
public class ApplicantApplicationRecordingsViewModel
{
public Applicant Applicant { get; set; }
public Application Application { get; set; }
public IEnumerable<RecordingViewModelApp> Recordings { get; set; }
public string Title { get; set; }
public SelectList UsageTypeSelectList { get; private set; }
public SelectList UsageEndAppSelectList { get; private set; }
}
控制器(省略注释验证检查)
public ActionResult Create(int ApplicantID) // assume you must have a custom route for this?
{
ApplicantApplicationRecordingsViewModel viewModel = new ApplicantApplicationRecordingsViewModel();
Applicant applicant = dbContext.Applicants.Find(ApplicantID);
viewModel.Applicant = applicant;
viewModel.Title = string.Format("Create a new application for {0} {1} {2}", applicant.title, applicant.firstName, applicant.lastName);
viewModel.Recordings = getViewModel(dbContext.Recordings.ToList(), dbContext); // not sure what this is?
viewModel.UsageTypeSelectList = new SelectList(dbContext.UsageTypes.OrderBy(ut => ut.UsageTypeName), "UsageTypeID", "UsageTypeName");
viewModel.UsageEndAppSelectList = new SelectList(dbContext.UsageEndApps.OrderBy(uea => uea.UsageEndAppName), "UsageEndAppID", "UsageEndAppName");
return View(viewModel);
}
查看
@model Project.ApplicantApplicationRecordingsViewModel
<h2>@Model.Title</h2>
@using (Html.BeginForm())
{
@Html.HiddenFor(item => Model.Applicant.ApplicantID) // include for post back but Application.ApplicationID not necessary (its a new application!)
<h3>Details of the applicant</h3>
// Add display detail for applicant, but use css for layout (position, floats etc), not tables (which are for tabular data)
<h3>Details of the application</h3>
// Add controls for Application but use LabelFor() so the label is associated with the control (otherwise its not a label)
@Html.DisplayNameFor(m => m.Application.ApplicationNo)
@Html.EditorFor(m => m.Application.ApplicationNo)
@Html.ValidationMessageFor(m => m.Application.ApplicationNo)
....
<h3>List of recordings</h3>
<table>
<thead>
.... // add table headings
</thead>
<tbody>
@Html.EditorFor(m => m.Recordings) // This uses a custom editor template to display and select recordings
</tbody>
</table>
<input type="submit" value="Create" />
}
EditorTemplate(/Views/Shared/EditorTemplates/RecordingViewModelApp.cshtml
)
请注意,您必须使用for
循环或自定义EditorTemplate
来渲染集合。您使用的foreach
循环只会在没有正确索引器的情况下呈现重复的id
(无效的html)和name
属性,因此不会回发到集合。
@model RecordingViewModelApp
<tr>
<td class="display-field">
@Html.CheckBoxFor(m => m.IsSelected) // required for postback
@Html.HiddenFor(m => m.RecordingID) // required for postback
</td>
<td class="display-field">@Html.DisplayFor(m => m.FileLocation)</td>
.... // other display properties
</tr>
POST方法
[HttpPost]
public ActionResult Create(ApplicantApplicationRecordingsViewModel model)
{
// model is now bound with the Applicant ID, all the properties of Application
// and the collection of Recordings with their ID and IsSelected property.
}