C# 动态更新视图后更新ViewModel
我试图定义忠实地表示视图的视图模型(以严格使用该概念) ViewModel的某些元素会动态更新。我遇到的问题是,当我发布文章时,ViewModel返回时没有动态更新的元素 在执行事件时,通过jQuery完成更新。通过Url.action调用操作,并更新Div 我举了一个例子来说明这个情况。仅存储位置(州和城市)的应用程序。为此,我有三个视图模型:一个表示SelectList中的州,一个表示SelectList中的城市,最后一个表示位置(由我首先提到的两个视图模型组成) 型号:C# 动态更新视图后更新ViewModel,c#,asp.net-mvc-5,viewmodel,C#,Asp.net Mvc 5,Viewmodel,我试图定义忠实地表示视图的视图模型(以严格使用该概念) ViewModel的某些元素会动态更新。我遇到的问题是,当我发布文章时,ViewModel返回时没有动态更新的元素 在执行事件时,通过jQuery完成更新。通过Url.action调用操作,并更新Div 我举了一个例子来说明这个情况。仅存储位置(州和城市)的应用程序。为此,我有三个视图模型:一个表示SelectList中的州,一个表示SelectList中的城市,最后一个表示位置(由我首先提到的两个视图模型组成) 型号: public cl
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; }
}
视图模型:
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; }
}
创建[视图]:
@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>
}
@model-viewmodel-example.ViewModels.LocationCreateViewModel
....
@使用(Html.BeginForm())
{
@Html.AntiForgeryToken()
陈述
@Html.ValidationSummary(true,“,new{@class=“text danger”})
@LabelFor(model=>model.StateSelectListViewModels.SelectedStateId,htmlAttributes:new{@class=“control label col-md-2”})
@Html.DropDownListFor(model=>model.StateSelectListViewModels.SelectedStateId,新建SelectList(model.StateSelectListViewModels.States,“Id”,“Name”),“选择一个状态”,htmlAttributes:new{@class=“form control”,@Id=“StateSelectList”})
@Html.ValidationMessageFor(model=>model.StateSelectListViewModels.SelectedStateId,“,新{@class=“text danger”})
@Html.Action(“城市选择列表”)
}
@节脚本{
@Scripts.Render(“~/bundles/jqueryval”)
$(函数(){
//填写城市下拉列表
$('#StateSelectList')。更改(函数(){
var selectedStateId=this.value;
$('#CityContainer').load('@Url.Action(“CitySelectList”)?stateId='+selectedStateId);
});
});
}
城市选择列表[视图]:
@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>
@model-viewmodel-example.ViewModels.CitySelectListViewModel
....
@LabelFor(model=>model.SelectedCityId,htmlAttributes:new{@class=“controllabel col-md-2”})
@DropDownListFor(model=>model.SelectedCityId,new SelectList(model.Cities,“Id”,“Name”),“选择一个城市”,htmlAttributes:new{@class=“form control”})
@Html.ValidationMessageFor(model=>model.SelectedCityId,“,new{@class=“text danger”})
我将展示我的示例的执行情况,我将通过检查我在发布后收到的ViewModel来展示问题:
这是因为在替换
的内部HTML时,您在创建操作中阻止modelBinder准确绑定到位置CreateViewModel
(这是您使用$('.\CityContainer')。加载(…
)。您指示model binder绑定到
@模型ViewModelExample.ViewModels.CitySelectListViewModel,因此您可以获得城市选择列表的以下HTML:
解决此问题的一种方法是将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>
但我也推荐。你能将其存储在隐藏字段中吗?@KevinCook在这种情况下不能。我有大约2400条记录。我需要应用程序尽可能轻。(感谢你的快速响应!)您是否考虑过将记录存储在缓存中?@kevinbook出于我前面提到的相同原因,我希望发送尽可能少的数据。是否无法动态更新ViewModel?因为您的第二个下拉列表具有name=“SelectedCityId”
,但它必须是name=“CitySelectListViewModel.SelectedCityId”
以绑定到您的模型。但是您采取了错误的方法并使其过于复杂。还有其他问题导致代码无法正常工作,包括在返回视图时丢失了第二个dropdownlist中的数据。ModelState
无效。请参阅如何正确实现级联dropdownlist汉克斯,这就解决了我的问题。我发现自己有另一个问题,我不想重复我自己。我想制作可重用的组件,你提到的策略迫使我重复视图和控制器。现在我正在研究你向我建议的自定义视图模型。如果你有更多的想法来实现我想要的r、 我都听到了。再次感谢。好吧,自定义模型绑定可以防止您重复自己的操作,但我不认为我会建议为项目中的每个模型创建自定义绑定。也许您应该检查viewmodels模型,并以有助于绑定的方式设计它们。另一种方法可能是@kevincook建议的,您可以在一个隐藏字段中重新选择selectedCityId
的选定值,该字段的name
属性将使其可访问您尝试绑定的模型的属性。解决此问题的方法有很多,可能是其中之一。但这一切都取决于您项目的整体情况。
@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>
public ActionResult CitySelectList(int? stateId)
{
LocationCreateViewModel locationCreateViewModel = new LocationCreateViewModel();
locationCreateViewModel.CitySelectListViewModel = new CitySelectListViewModel(db.Cities.Where(c => c.StateId == stateId).ToList());
return View(locationCreateViewModel);
}