【问题标题】:MVC4 - Partial View Model binding during SubmitMVC4 - 提交期间的部分视图模型绑定
【发布时间】:2019-01-29 15:12:46
【问题描述】:

我有一个视图模型,它有另一个子模型来渲染局部视图(如下)。

public class ExamResultsFormViewModel
{
    public PreliminaryInformationViewModel PreliminaryInformation { get; set; }

    public string MemberID { get; set; }

    public string MemberName { get; set; }

    public int PatientID { get; set; }

    public string ConfirmationID { get; set; }

    public bool IsEditable { get; set; }

    #region Select Lists
    public SelectList ProviderOptions { get; set; }
    #endregion
}

public class PreliminaryInformationViewModel
{
    public string ProviderName { get; set; }

    public string ProviderID { get; set; }

    public string ServiceLocation { get; set; }
}

此 PreliminaryInformationViewModel 视图模型也用作另一个视图模型中的子模型,因为此初步信息可以在不同的页面上更新。

因此,我将这些初步信息创建为单独的部分并包含在其他页面中。

@{Html.RenderPartial("_PreliminaryInformation", Model.PreliminaryInformation);}

内部部分

@model Web.Models.Preliminary.PreliminaryInformationViewModel
<div>
    @Html.TextBoxFor(x => x.DateOfService })
</div>

但问题是在提交过程中这个初步模型总是空的,因为 HTML name 属性总是呈现为

但是当我将父模型传递给部分时,如下所示。

@model Web.Models.Exam.ExamResultsFormViewModel
<div>
    @Html.TextBoxFor(x => x.PreliminaryInformation.DateOfService })
</div>

现在 HTML 元素生成为

<input type = 'text' name='PreliminaryInformation.DateOfService.DateOfService' id='PreliminaryInformation.DateOfService'>

并且它在提交期间正确绑定。

我了解 MVC 根据 name 属性值绑定元素值,但第二种实现需要我为每个页面创建多个部分,我不喜欢。

到目前为止,我找不到与第一个实现一起使用的解决方案,有没有办法在提交期间将初步信息模型值绑定到第一个实现。

【问题讨论】:

    标签: asp.net-mvc-4


    【解决方案1】:

    我知道它有点晚了,但它可能对某人有所帮助

    如果你有复杂的模型,你仍然可以将它传递给部分使用:

    @Html.Partial("_YourPartialName", Model.Contact, new ViewDataDictionary()
    {
        TemplateInfo = new TemplateInfo()
        {
            HtmlFieldPrefix = "Contact"
        }
    })
    

    我在哪里定义了具有“联系人”属性的模型。现在 HtmlFieldPrefix 所做的是为每个模型添加属性绑定“以便模型绑定器可以找到父模型”

    有一篇关于它的博文:http://www.cpodesign.com/blog/bind-partial-view-model-binding-during-submit/

    .NET Core 2 绑定

    在 .NET Core 2 和 MVC 中,上述答案将不起作用,该属性不再可设置。

    解决方案非常相似。

     @{ Html.ViewData.TemplateInfo.HtmlFieldPrefix = "Contact"; }
     @await Html.PartialAsync("_YourPartialName", Model.Contact)
    

    你可以提交你的模型后,它会再次绑定。

    希望有帮助

    【讨论】:

    • 如果我有一个联系人对象列表并想将其绑定到模型怎么办?
    • 您需要使用上述样式为每个循环换行
    • 我没有看到任何合理的循环应该去的地方,你能建议吗?
    • 太棒了,感谢您提供的这个很棒的提示!这提供了编辑器模板的所有功能以及部分视图的灵活性。编辑器模板的整个概念有点夸大其词,恕我直言,它们只是调用部分视图的不同语法,其中添加的视图约束绑定到项目中的特定目录。使用您的答案,您将获得两全其美。再次感谢!
    • 这对我很有帮助:D 谢谢
    【解决方案2】:

    您可以将 HtmlFieldPrefix 添加到局部视图的顶部:

    @{
        ViewData.TemplateInfo.HtmlFieldPrefix = "Contact";
    }
    

    这与@cpoDesign 所描述的方法相同,但这意味着您可以在需要时将前缀保留在局部视图中。

    【讨论】:

    • 是的,我知道这可能是对原始答案的评论,但我没有代表。
    • 当您在不同的地方和不同的表单中使用局部视图时,这非常有用,每个视图都可以与绑定到不同类型模型的表单一起提交到服务器。可能需要一些逻辑来指定嵌入部分视图的正确前缀。
    【解决方案3】:

    你需要为PreliminaryInformationViewModel创建一个编辑器模板来替换局部视图,然后用Html.EditorFor( m =&gt; m.PreliminaryInformation )调用。参考this solution。创建模板应该像将部分视图移动到 Views/Shared/EditorTemplates 目录一样简单。 Html.EditorFor(...) 将根据您作为模型传入的类型自动使用此模板(在本例中为PreliminaryInformationViewModel

    【讨论】:

    • 好的,使用EditerFor 解决了绑定问题,但它也替换了我在视图中应用的所有类和样式。 ''
    • 将您的局部视图移动到 Views\Shared\EditorTemplates,对 Html.EditorFor(...) 的调用应该会根据您作为模型传入的类型自动为您的编辑器模板选择此视图
    • 感谢莫霍的回复。我能够在使用 EditorFor 提交期间渲染部分和元素值,但是使用 EditorFor 渲染会向 div 和元素添加一些编辑器类,并删除实际放置在视图上的那些有什么方法可以阻止添加这些编辑器类到部分中的元素。
    【解决方案4】:

    我也遇到了这个问题。我将使用您的代码解释我的解决方案。我从这个开始:

    @{
       Html.RenderPartial("_PreliminaryInformation", Model.PreliminaryInformation);
    }
    

    与 http post 对应的操作正在寻找父模型。 http post 正确提交了表单,但子部分中没有对父部分的引用。子部分提交的值被忽略,相应的子属性保持为空。

    我创建了一个接口 IPreliminaryInfoCapable,其中包含子类型的定义,如下所示:

    public interface IPreliminaryInfoCapable
    {
        PreliminaryInformationViewModel PreliminaryInformation { get; set; }
    }
    

    我让我的父模型实现了这个接口。然后我的局部视图使用顶部的界面作为模型:

    @model IPreliminaryInfoCapable
    

    最后,我的父视图可以使用以下代码将自己传递给子部分:

    @{
        Html.RenderPartial("ChildPartial", Model);
    }
    

    那么子partial就可以使用子对象了,像这样:

    @model IPreliminaryInfoCapable
    ...
    @Html.LabelFor(m => m.PreliminaryInformation.ProviderName)
    etc.
    

    所有这些都会在 http post 到相应的操作时正确填充父模型。

    【讨论】:

      【解决方案5】:

      快速提示:在调用 EditorFor 方法时,可以将模板名称设置为 Html.EditorFor 方法的参数。或者,命名约定可以成为您的朋友;只需确保您的编辑器模板文件名与模型属性类型的名称完全相同

      即模型属性类型 'CustomerViewModel' => 'CustomerViewModel.cshtml' 编辑器模板。

      【讨论】:

        【解决方案6】:

        请对您的部分页面进行以下更改。所以它会随您的 Parent 模型一起提供

        //Parent Page
        @{Html.RenderPartial("_PreliminaryInformation", Model.PreliminaryInformation);}
        
        //Partial Page
        @model Web.Models.Preliminary.PreliminaryInformationViewModel
        @using (Html.BeginCollectionItem("PreliminaryInformation", item.RowId, true))
            {
        <div>
        @Html.TextBoxFor(x => x.DateOfService })
        </div>
        
        }
        

        【讨论】:

          【解决方案7】:

          对于 .net core 2 和 mvc,使用如下:

          @{
           Html.ViewData.TemplateInfo.HtmlFieldPrefix = "Contact"; 
          }
           @await Html.PartialAsync("_YourPartialViewName", Model.Contact)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-04-03
            • 2023-04-01
            相关资源
            最近更新 更多