从传递给局部视图的嵌套复杂对象中获取值
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.
前缀命名。
我有一个 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.
前缀命名。