提交MVC 5视图时,部分视图中的数据丢失

本文关键字:视图 数据 MVC 提交 | 更新日期: 2023-09-27 18:11:11

这个问题已经问过了,但是没有人能解决我的问题。问题是缺少或来自部分视图的空数据未与主视图数据一起提交(POST)。

我有一个名为_Address的类型化部分视图。cshtml,我将其包含在另一个名为Site.cshtml的视图中。

类型化站点视图绑定到名为SiteEditModel.cs

的视图模型
public class SiteEditModel
{
   ...properties
   public AddressEditModel Address {get;set;}
  public SiteEditModel()
  {
   Address = new AddressEditModel();
  }
}
Site视图有一个表单:
        @model Insight.Pos.Web.Models.SiteEditModel
        ...
        @using ( Html.BeginForm( "Edit", "Site", FormMethod.Post ) )
        {
            @Html.HiddenFor( m => m.SiteId )
            ...
            @Html.Partial( "~/Views/Shared/Address.cshtml", this.Model.Address )
            ...
            @Html.SaveChangesButton()
        }

部分地址视图只是一堆@Html…绑定到Address模型的调用。

@model Insight.Pos.Web.Models.AddressEditModel
@{
    Layout = null;
}
<div>
@Html.HiddenFor(...)
@Html.HiddenFor(...)
@Html.HiddenFor(...)
@hmtl.LabelFor(...)
</div>

在控制器操作Edit中,我可以看到SiteEditModel是正确填充的,但该模型的Address属性不是。我哪里做错了?

提交MVC 5视图时,部分视图中的数据丢失

http://davybrion.com/blog/2011/01/prefixing-input-elements-of-partial-views-with-asp-net-mvc/

@Html.Partial("~/Views/Shared/_Address.cshtml", Model.Address, new ViewDataDictionary
{
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Address" }
})  

解决这个问题的关键是命名partialviews的输入元素。渲染部分不知道它是某个更大的东西的一部分。

我已经做了一个简单的例子,如何解决这个问题,你可以有多个地址使用相同的部分视图:

public static class HtmlHelperExtensions
    {
        public static MvcHtmlString PartialWithPrefix(this HtmlHelper html, string partialViewName, object model, string prefix)
        {
            var viewData = new ViewDataDictionary(html.ViewData)
            {
                TemplateInfo = new TemplateInfo
                {
                    HtmlFieldPrefix = prefix
                }
            };
            return html.Partial(partialViewName, model, viewData);
        }
    }

在视图中使用如下扩展:

@using (Html.BeginForm("Edit", "Site", FormMethod.Post))
{
    @Html.HiddenFor(m => m.SiteId)
    @Html.PartialWithPrefix("_Adress", this.Model.Address, "Address")
    <input type="submit" />
}

你当然可以用表达式和反射让它更花哨一点,但那是另一个问题;-)

您的SiteEditModel Address属性未标记为public,更改为:

public AddressEditModel Address {get;set;}

我也会改变你的部分使用SiteEditModel代替:

@model Insight.Pos.Web.Models.SiteEditModel
@{
    Layout = null;
}
<div>
@Html.HiddenFor(m => m.Address.FooProperty)
...
</div>

这将意味着您的属性最终将被正确命名,以便模型绑定器拾取它们。使用上面的示例,它将是Name"=Address.FooProperty"

我没记错,问题是Html.Partial没有正确地填充输入名称。您应该设置如下:

<input id="Address.Street" name="Address.Street" />

但我假设你有以下HTML:

<input id="Street" name="Street" />

你有几个解决方案:

  1. 手动插入输入名称:

     @Html.HiddenFor(x => x.Street, new { Name = "Address.Street" })
    
  2. 使用Html.EditorFor()

  3. 覆盖Html.Partial()中解析的名称

第一个解决方案的缺点是您正在硬编码属性名称,这是不理想的。我建议使用Html.EditorFor()Html.DisplayFor()帮助程序,因为它们可以正确填充输入名称。

如果在局部视图中填充子模型,则模型绑定器无法正确绑定子模型。考虑使用编辑器模板,因为它是为此而实现的。

把你的AddressEditModel.cshtml文件放在'Views'Shared'EditorTemplates'文件夹中,在你的主视图中使用如下命令:

@using ( Html.BeginForm( "Edit", "Site", FormMethod.Post ) )
{
    // because model type name same as template name MVC automatically picks our template
    @Html.EditorFor(model=>model.Address)
    // or if names do not match set template name explicitly 
    @Html.EditorFor(model=>model.Address,"NameOfTemplate")
}