【问题标题】:ASP.NET MVC 4.5 Map Partial View to Main View on Form submitASP.NET MVC 4.5 将部分视图映射到表单提交时的主视图
【发布时间】:2017-07-29 08:48:12
【问题描述】:

你好强大的 Stackoverflowers,

我目前正在开发一个 ASP.NET MVC 4.5 应用程序。 当我提交创建表单时,我需要将部分视图中的输入值映射到主视图模型。

在我的视图中“Create.cshtml”我称之为局部视图“_SwotPart.cshtml”。我将 ViewModel 的一部分传递给 Partial View,如下所示:

创建.cshtml:

@model MyCoolApp.BLL.Models.MainVm

@foreach (var swot in Model.Swots)
{
        <tr>
            @foreach (var swotPart in swot.SwotParts)
            {
                @Html.Partial("~/Views/Shared/_SwotPart.cshtml", swotPart)
            }
        </tr>
}

我的局部视图如下所示,_SwotPartial.cshtml:

<td class="form-group">
    @Html.TextAreaFor(model => model.Label, htmlAttributes: new { Name = nameField, ID = nameField, @class = "form-control", placeholder = Model.SwotTypeId.GetLabel() })
</td>

无论如何,当我提交表单时,部分视图中的值永远不会到达控制器。

您对如何正确映射有任何想法吗?

谢谢!

【问题讨论】:

    标签: c# asp.net asp.net-mvc asp.net-mvc-4 razor


    【解决方案1】:

    问题在于将按照您当前尝试实现此目的的方式生成的输入名称。 Razor 需要整个列表的上下文,或者至少需要项目在其中的位置,才能生成正确的输入名称。换句话说,解决您的问题的最简单方法(带有警告)是:

    @for (var i = 0; i < Model.Swots.Count(); i++)
    {
        ...
    
        @for (var j = 0; j < Model.Swots[i].SwotParts.Count(); j++)
        {
            if (Model.Swots[i].SwotParts[j].SwotTypeId == SwotType.InternalHelpful || Model.Swots[i].SwotParts[j].SwotTypeId == SwotType.InternalHarmful)
            {
                @Html.Partial("~/Views/Shared/_SwotPart.cshtml", Model.Swots[i].SwotParts[j])
            }
        }
    
        ...
    

    然后,partial 有正确的上下文可以使用,您的输入将被命名为 Swots[0].SwotParts[0].Label,modelbinder 将能够使用它。

    然而,这里需要注意的是,您要将此列表分成两个循环。这仍然行不通,因为您实际上是在弄乱模型中项目位置的整体上下文。要解决这个问题,您应该在模型中拆分列表,这样更好,因为您可以从视图中删除此业务逻辑:

    public class SwotVm
    {
        ...
    
        public List<SwotPartVm> InternalSwotParts { get; set; }
        public List<SwotPartVm> ExternalSwotParts { get; set; }
    }
    

    然后,您可以简单地单独遍历每个列表,这些值自然会回传到相应的列表中。

    但是,鉴于您使用部分来呈现特定类类型的字段,创建编辑器模板会更好。如果您只是将部分代码移动到视图:Views\Shared\EditorTemplates\SwotPartVm.cshtml,那么在您的主视图中,您可以这样做:

    @for (var i = 0; i < Model.Swots.Count(); i++)
    {
        ...
    
        <tr>
            <th class="swot-heading">Internal</th>
            @Html.EditorFor(m => m.Swots[i].InternalSwotParts)
        </tr>
        <tr>
            <th class="swot-heading">External</th>
            @Html.EditorFor(m => m.Swots[i].ExternalSwotParts)
        </tr>
    }
    

    这明显很多更干净,您可以通过添加SwotVm.cshtml 编辑器模板来进一步推广这个概念,甚至可以用以下代码替换这一点代码:

    @Html.EditorFor(m => m.Swots)
    

    注意:在您的 SwotVm.cshtml 编辑器模板中,您将只包含单个 SwotVm 的代码。换句话说,不包括for 语句。

    【讨论】:

    • 感谢 Chris 的精彩而详细的解释!
    【解决方案2】:

    为了让您的应用程序能够解析发布的值并正确地将其绑定到您的视图模型。发布的表单数据的名称必须是一样的。

    swots[x1].swotParts[x2].label

    其中 x1 是一个从 0 到每个 swot 的数字。 其中 x2 是 swot 中每个 swot 部分从 0 到更大的数字。

    现在,当您发布时,表单数据名称只是 label

    而不是:

     @Html.TextAreaFor(model => model.Label, htmlAttributes: new { Name = nameField, ID = nameField, @class = "form-control", placeholder = Model.SwotTypeId.GetLabel() })
    

    试试:

    <textarea name="swots[x1].swotParts[x2].label" class="form-control" placeholder="@Model.SwotTypeId.GetLabel()" >@Model.Label</textarea>
    

    不要忘记将 x1 和 x2 替换为数字。

    您可以在此处阅读有关模型绑定到集合的更多信息。

    http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多