从传递给局部视图的嵌套复杂对象中获取值

getting the values from a nested complex object that is passed to a partial view

我有一个 ViewModel,它的成员之一是一个复杂的对象。复杂对象有 4 个属性(所有字符串)。我正在尝试创建一个可重复使用的局部视图,我可以在其中传递复杂对象并让它生成 html 和 html 帮助程序的属性。这一切都很好。但是,当我提交表单时,模型联编程序不会将值映射回 ViewModel 的成员,因此我在服务器端得不到任何回报。我如何才能将用户输入的值读入复杂对象的 html 帮助程序。

视图模型

public class MyViewModel
{
     public string SomeProperty { get; set; }
     public MyComplexModel ComplexModel { get; set; }
}

我的复杂模型

public class MyComplexModel
{
     public int id { get; set; }
     public string Name { get; set; }
     public string Address { get; set; }
     ....
}

控制器

public class MyController : Controller
{
     public ActionResult Index()
     {
          MyViewModel model = new MyViewModel();
          model.ComplexModel = new MyComplexModel();
          model.ComplexModel.id = 15;
          return View(model);
     }

     [HttpPost]
     public ActionResult Index(MyViewModel model)
     {
          // model here never has my nested model populated in the partial view
          return View(model);
     }
}

查看

@using(Html.BeginForm("Index", "MyController", FormMethod.Post))
{
     ....
     @Html.Partial("MyPartialView", Model.ComplexModel)
}

局部视图

@model my.path.to.namespace.MyComplexModel
@Html.TextBoxFor(m => m.Name)
...

如何在表单提交时绑定此数据,以便父模型包含从局部视图在 Web 表单上输入的数据?

谢谢

编辑:我发现我需要在部分视图(文本框)中将 "ComplexModel." 添加到我的所有控件名称之前,以便它映射到嵌套对象,但我无法通过将 ViewModel 类型添加到局部视图以获得该额外层,因为它需要通用才能接受多种 ViewModel 类型。我可以用 javascript 重写 name 属性,但这对我来说似乎过于贫民窟。我还能怎么做?

编辑 2:我可以使用 new { Name="ComplexModel.Name" } 静态设置 name 属性,所以我想我在做生意,除非有人有更好的方法?

您可以尝试将 ViewModel 传递给局部。

@model my.path.to.namespace.MyViewModel
@Html.TextBoxFor(m => m.ComplexModel.Name)

编辑

您可以创建一个基础模型并将复杂模型推入其中,然后将基础模型传递给部分模型。

public class MyViewModel :BaseModel
{
    public string SomeProperty { get; set; }
}

 public class MyViewModel2 :BaseModel
{
    public string SomeProperty2 { get; set; }
}

public class BaseModel
{
    public MyComplexModel ComplexModel { get; set; }
}
public class MyComplexModel
{
    public int id { get; set; }
    public string Name { get; set; }
    ...
}

那么你的部分将如下所示:

@model my.path.to.namespace.BaseModel
@Html.TextBoxFor(m => m.ComplexModel.Name)

如果这不是一个可接受的解决方案,您可能需要考虑覆盖模型绑定器。你可以阅读 here.

您可以使用

将前缀传递给部分
@Html.Partial("MyPartialView", Model.ComplexModel, 
    new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }})

它将把前缀添加到您的控件 name 属性中,这样 <input name="Name" ../> 将变为 <input name="ComplexModel.Name" ../> 并正确绑定到 post 后面的 typeof MyViewModel

编辑

为了让它更容易一些,您可以将其封装在 html 帮助程序中

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
  string name = ExpressionHelper.GetExpressionText(expression);
  object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
  var viewData = new ViewDataDictionary(helper.ViewData)
  {
    TemplateInfo = new System.Web.Mvc.TemplateInfo 
    { 
      HtmlFieldPrefix = string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix) ? 
        name : $"{helper.ViewData.TemplateInfo.HtmlFieldPrefix}.{name}"
    }
  };
  return helper.Partial(partialViewName, model, viewData);
}

并将其用作

@Html.PartialFor(m => m.ComplexModel, "MyPartialView")

我遇到了同样的情况,在这些信息丰富的帖子的帮助下,我将部分代码更改为在部分视图生成的输入元素中生成前缀

我已经使用 Html.partial 帮助器为 Html.partial 的构造函数提供部分视图名称和 ModelType 对象以及带有 Html 字段前缀的 ViewDataDictionary 对象实例。

这导致 "Main view" 的 "xyz url" 的 GET 请求,并在其中渲染部分视图,其中生成的输入元素带有前缀,例如较早的 Name="Title" 现在在各自的 HTML 元素中变为 Name="MySubType.Title" 并且对于其余的表单输入元素也是如此。

当向 "xyz url" 发出 POST 请求时出现问题,希望将填写的表格保存到我的数据库中。但是 MVC Modelbinder 没有绑​​定我的 POSTed 模型数据和填充的表单值,而且 ModelState 也丢失了。视图数据中的模型也变为空。

最后,我尝试使用 TryUppdateModel 方法更新发布形式的模型数据,该方法采用模型实例和 html 前缀,该前缀先前传递给部分视图,现在可以看到模型与值绑定,模型状态为也出席了。

请让我知道这种方法是否合适或有点多样化!

如果您使用标签助手,partial 标签助手会接受一个 for 属性,这符合您的预期。

<partial name="MyPartialView" for="ComplexModel" />

使用 for 属性而不是典型的 model 属性,将导致部分中的所有表单字段都以 ComplexModel. 前缀命名。