我正在尝试定义忠实代表视图的ViewModel(严格使用该概念)。
ViewModel的一些元素是动态更新的。我遇到的问题是,当我执行Post时,ViewModel将返回没有动态更新的元素。
当执行事件时,更新通过jQuery完成。通过Url.Action调用操作,并更新Div。
我举了一个例子来澄清这个场景。仅存储位置(州和城市)的应用程序。为此,我有三个ViewModel:一个用于表示SelectList中的状态,一个用于表示SelectList中的Cities,最后一个用于表示Location(由我首先提到的两个ViewModel形成)。
型号:
public class State
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
public class City
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public int StateId { get; set; }
public virtual State State { get; set; }
}
的ViewModels:
public class CitySelectListViewModel
{
public CitySelectListViewModel() { }
public CitySelectListViewModel(IEnumerable<Models.City> cities)
{
this.Cities = cities;
}
[Display(Name = "Cities")]
[Required]
public int? SelectedCityId { get; set; }
public IEnumerable<City> Cities { get; }
}
public class StateSelectListViewModel
{
public StateSelectListViewModel() { }
public StateSelectListViewModel(IEnumerable<State> states)
{
this.States = states;
}
[Display(Name = "States")]
[Required]
public int? SelectedStateId { get; set; }
public IEnumerable<State> States { get; }
}
public class LocationCreateViewModel
{
public LocationCreateViewModel() { }
public LocationCreateViewModel(ICollection<State> states)
{
this.StateSelectListViewModels = new StateSelectListViewModel(states);
this.CitySelectListViewModel = new CitySelectListViewModel();
}
public StateSelectListViewModel StateSelectListViewModels { set; get; }
public CitySelectListViewModel CitySelectListViewModel { set; get; }
}
位置[控制器]:
public class LocationController : Controller
{
private DALDbContext db = new DALDbContext();
// GET: Location/Create
public ActionResult Create()
{
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel(db.States.ToList());
return View(locationCreateViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(LocationCreateViewModel pLocationCreateViewModel)
{
if (ModelState.IsValid)
{
//db.States.Add(state);
//db.SaveChanges();
return RedirectToAction("Index", "Home");
}
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel(db.States.ToList());
return View(locationCreateViewModel);
}
public ActionResult CitySelectList(int? stateId)
{
CitySelectListViewModel citySelectListViewModel = new CitySelectListViewModel(db.Cities.Where(c => c.StateId == stateId).ToList());
return View(citySelectListViewModel);
}
}
创建[查看]:
@model ViewModelExample.ViewModels.LocationCreateViewModel
....
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>State</h4>
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.StateSelectListViewModels.SelectedStateId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.StateSelectListViewModels.SelectedStateId, new SelectList(Model.StateSelectListViewModels.States, "Id", "Name"), "Select a State", htmlAttributes: new { @class = "form-control", @id = "StateSelectList" })
@Html.ValidationMessageFor(model => model.StateSelectListViewModels.SelectedStateId, "", new { @class = "text-danger" })
</div>
</div>
<div id="CityContainer">
@Html.Action("CitySelectList")
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(function () {
// Fill City DropDownList
$('#StateSelectList').change(function () {
var selectedStateId = this.value;
$('#CityContainer').load('@Url.Action("CitySelectList")?stateId=' + selectedStateId);
});
});
</script>
}
CitySelectList [查看]:
@model ViewModelExample.ViewModels.CitySelectListViewModel
....
<div class="form-group">
@Html.LabelFor(model => model.SelectedCityId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.SelectedCityId, new SelectList(Model.Cities, "Id", "Name"), "Select a City", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.SelectedCityId, "", new { @class = "text-danger" })
</div>
</div>
我将展示我的示例的执行情况,我将通过检查Post后收到的ViewModel来显示问题:
我检查Post后收到的ViewModel。我们可以看到CitySelectListViewModel是如何为null,我想要的是带来通过jQuery更新的最后一个ViewModel 。
我承认我提供了一个很长的例子,但这是我找到解释我需要的唯一方法。提前谢谢。
答案 0 :(得分:1)
这是因为在替换LocationCreateViewModel
的内部HTML时,你阻止了modelBinder准确地绑定到Create
操作中的<div id="CityContainer">
(这就是你对{{1}所做的事情})。您指示模型绑定器绑定到
@model ViewModelExample.ViewModels.CitySelectListViewModel,因此您可以获得城市选择列表的HTML:
解决此问题的一种方法是将$('#CityContainer').load(...
修改为:
CitySelectList.cshtml
以及您的@model ViewModelExample.ViewModels.LocationCreateViewModel
@{
Layout = null;
}
<div class="form-group">
@Html.LabelFor(model => model.CitySelectListViewModel.SelectedCityId,
htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model =>
model.CitySelectListViewModel.SelectedCityId, new
SelectList(Model.CitySelectListViewModel.Cities, "Id", "Name"), "Select a City", htmlAttributes: new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.CitySelectListViewModel.SelectedCityId, "", new { @class = "text-danger" })
</div>
</div>
操作:
CitySelectList
但我也会推荐custom model binding。