的ViewModels
//MainViewModel
public class MainViewModel
{
public string UserID { get; set; }
public string ServiceType { get; set; }
public List<Service> Services {get; set;}
}
public class Service
{
public string ServiceID {get; set;}
public string ServiceName {get; set;
}
这是视图
//Index.cshtml
@model ParentViewModel
@{
<div>
@Html.DropDownListFor(model => model.UserID, new{onchange="ddSelectionChanged(this)"})
<div id="services">
//This is filled with the ajax
</div>
</div>
}
这是AJAX Call
<script>
function ddSelectionChanged(element){
$('#services').load('@(Url.Action("GetServices"))?serviceType =' element.value);
};
</script>
这是控制器
//Controller
public class UserServicesController : Controller
{
public ActionResult Index()
{
return View();
}
public PartialViewResult GetServices(string serviceType)
{
//Service servicesViewModel = Fetch Services from DB
return PartialView("PartialViews/Shared/_Services", servicesViewModel);
}
}
这很好,部分View按预期呈现,但是当我发布索引时,MainViewModel的属性“Services”返回“null”。问题是模型的“服务”属性不会重新绑定到MainViewModel,因为它会动态呈现为局部视图。
如何在部分视图渲染时或在发布表单之前重新绑定模型?
答案 0 :(得分:6)
当您发布操作时,模型绑定器填充的唯一部分是已发布的字段和数据。如果您丢失了服务,则需要在表单中提供字段以在帖子中保留该数据。
例如,在您的AJAX返回的任何HTML中,您需要为Service
上的每个属性添加类似隐藏输入的内容:
@Html.HiddenFor(m => m.ServiceID)
@Html.HiddenFor(m => m.ServiceName)
然后,当您的表单发布时,该数据将与其他所有内容一起发布,并且模型绑定器将能够恰当地填充您的Services
列表。但是,您还需要注意生成的字段名称。特别是如果响应AJAX请求的操作返回的部分视图直接使用List<Service>
之类的模型而不是MainViewModel
,则呈现的HTML将失去知道它应该绑定到的Services
的上下文名为[0].ServiceID
的财产。换句话说,在您的HTML中,您的字段名称最终会变为Services[0].ServiceID
而不是ViewDataDictionary
。后者对于让模型绑定器正确处理发布的数据是必要的。
您可以通过将自定义Html.Partial
传递到Html.RenderPartial
或TemplateInfo
来电来弥补此问题。通过定义一个新的HtmlFieldPrefix
@Html.Partial("_SomePartial", someModel, new ViewDataDictionary
{
TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "SomePrefix" }
}
设置为它需要的任何东西,即:
PartialView
但是,直接返回PartialView
时更加棘手,因为ViewDataDictionary
不接受自定义HtmlFieldPrefix
的参数。我自己没有尝试过,但您可以直接在行动中设置public PartialViewResult GetServices(string serviceType)
{
ViewData.TemplateInfo.HtmlFieldPrefix = "Services";
//Service servicesViewModel = Fetch Services from DB
return PartialView("PartialViews/Shared/_Services", servicesViewModel);
}
:
for
另外值得一提的是,如果您之前没有使用过绑定集合,那么您需要使用foreach
循环而不是@foreach (var service in Model)
{
@Html.HiddenFor(m => service.ServiceID)
}
循环来为该字段提供适当的上下文名。例如,类似以下内容:
service.ServiceID
会导致名称为@for (var i = 0; i < Model.Count(); i++)
{
@Html.HiddenFor(m => m[i].ServiceID)
}
的字段。模型绑定器不知道该值应该去哪里,基本上会忽略它。相反,你需要这样做:
[0].ServiceID
这样可以获得名称为{{1}}的字段。同样,前缀是一个问题,因此您需要两个组件才能使其正常工作。