Asp.net mvc 通过AJAX加载后,部分视图的ViewModel未绑定到主ViewModel的ViewModel

Asp.net mvc 通过AJAX加载后,部分视图的ViewModel未绑定到主ViewModel的ViewModel,asp.net-mvc,asp.net-ajax,Asp.net Mvc,Asp.net Ajax,视图模型 //MainViewModel public class MainViewModel { public string UserID { get; set; } public string ServiceType { get; set; } public List<Service> Services {get; set;} } public class Service {

视图模型

//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;
     }
这很好,局部视图按预期呈现,但当我发布索引时,MainViewModel的属性“Services”返回“null”。问题在于,模型的“服务”属性没有重新绑定到MainViewModel,因为它动态地呈现为局部视图


如何在部分视图渲染时或发布表单之前重新绑定模型?

发布到动作时,modelbinder仅填充已发布的字段和数据。如果您正在丢失服务,那么您需要在表单中提供字段,以便在发布期间保留该数据

例如,在AJAX返回的任何HTML中,您都需要为
服务上的每个属性包含类似于隐藏输入的内容:

@Html.HiddenFor(m => m.ServiceID)
@Html.HiddenFor(m => m.ServiceName)
然后,当您的表单发布时,这些数据将与其他所有内容一起发布,modelbinder将能够适当地填写您的
服务
列表。但是,您还需要注意生成的字段名。特别是,如果响应AJAX请求的操作返回的部分视图直接使用了类似于
List
的模型,而不是
MainViewModel
,则呈现的HTML将失去知道它应该绑定到名为
Services
的属性的上下文。换句话说,在HTML中,字段名将以类似于
[0].ServiceID
的形式结束,而不是
服务[0].ServiceID
。后者对于让modelbinder正确处理发布的数据是必要的

您可以通过将自定义的
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
的字段。modelbinder不知道这个值应该放在哪里,基本上会忽略它。相反,您需要执行以下操作:

@for (var i = 0; i < Model.Count(); i++)
{
    @Html.HiddenFor(m => m[i].ServiceID)
}
for(var i=0;im[i].ServiceID) }

这将得到名为
[0].ServiceID
的字段。同样,前缀是一个问题,因此您需要两个组件才能使其正常工作。

嘿,克里斯,谢谢你。你救了我几个小时。ViewData.TemplateInfo.HtmlFieldPrefix=“Services”这解决了问题。干杯,我欠你人情。嗨,我有一个类似的问题,即使是通过在浏览器中向表中添加新行来正确呈现局部视图,但在表单发布时,父模型列表对象的项目数始终为0。它永远不会来inside@for(var i=0;ipublic PartialViewResult GetServices(string serviceType) { ViewData.TemplateInfo.HtmlFieldPrefix = "Services"; //Service servicesViewModel = Fetch Services from DB return PartialView("PartialViews/Shared/_Services", servicesViewModel); }
@foreach (var service in Model)
{
    @Html.HiddenFor(m => service.ServiceID)
}
@for (var i = 0; i < Model.Count(); i++)
{
    @Html.HiddenFor(m => m[i].ServiceID)
}