![](/img/trans.png)
[英]Post MVC form calling a controller action view that requires a viewmodel. Why does the ViewModel not get sent to the view?
[英]Complex ViewModel. View returns an empty ViewModel. [HttpPost] Action
我有一个问题,该问题通过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的组件都为null,例如RecordingViewModelApp
的列表为null。 我想念什么? 我需要了解幕后发生的事情以及为什么默认模型绑定不起作用。
[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>
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> }
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; } }
首先要修复视图模型。 视图模型应仅包含表示要显示和/或编辑的内容的简单属性。
查看模型
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.
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.