使用单一视图模型在 MVC Razor 视图上发布多个表单

Posted

技术标签:

【中文标题】使用单一视图模型在 MVC Razor 视图上发布多个表单【英文标题】:Posting multiple forms on MVC Razor View with a Single View Model 【发布时间】:2017-01-15 13:36:44 【问题描述】:

我有一个包含 5 个表单的剃刀视图。 (A、B、C、D、E)。这些表单中的每一个都有自己的 ViewModel(AViewModel、BViewModel、CViewModel、DViewModel、EViewModel)。

我创建了一个父 ProductViewModel,该页面将用作其唯一的 ViewModel。在此 ViewModel 中将包含页面上每个表单的所有其他 ViewModel(如上所列)。

ProductViewModel 的属性如下所示:

public AViewModel  get; set; 
public BViewModel  get; set; 
public CViewModel  get; set; 
public DViewModel  get; set; 
public EViewModel  get; set; 

我的剃刀视图如下所示:

@model MVCApp.ViewModels.ProductViewModel

@
    ViewData["Title"] = "Product Detail";


<h2>Product Detail</h2>

<form asp-controller="A" asp-action="Save" data-ajax="true" data-ajax-method="POST">
    <div class="form-horizontal">
        <h4>Form A</h4>
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="AViewModel.Name" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="AViewModel.Name" class="form-control"/>
                <span asp-validation-for="AViewModel.Name" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="AViewModel.StartDate" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="AViewModel.StartDate" class="form-control"/>
                <span asp-validation-for="AViewModel.StartDate" class="text-danger" />
            </div>
        </div>
        <div class="form-group">
            <label asp-for="AViewModel.EndDate" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="AViewModel.EndDate" class="form-control"/>
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts 
    @await html.RenderPartialAsync("_ValidationScriptsPartial");

当点击 Save 按钮时,我最终进入了 A 控制器的 Save (POST) Action Method,正如我所期望的那样:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Save(AViewModel viewModel)
    
        return Ok();
    

但是,我注意到 viewModel 参数的所有属性都是空的。

这是否意味着我真的必须将 ProductViewModel 对象作为我的 ViewModel 传递给所有 5 个表单的保存操作方法,其中只有范围内的 ViewModel 将被填充,其他所有内容都将为空?还是有更好的办法?

【问题讨论】:

【参考方案1】:

我建议将每个表单都设为局部视图,并仅传入父模型所需的子模型

 @await Html.RenderPartialAsync("AViewPartial", Model.AViewModel); 

那么您在部分中的输入可以更改为

<input asp-for="AViewModel.Name" class="form-control"/>

<input asp-for="Name" class="form-control"/>

这应该使它被模型绑定器正确绑定,以便它被传递到您的操作中

【讨论】:

局部视图正是我需要的。谢谢!【参考方案2】:

POST 方法的参数必须是ProductViewModel

这是因为属性在 HTML 中的命名方式:

<input asp-for="AViewModel.Name" class="form-control"/>

模型绑定器采用您的序列化表单,并看到您正在向 POST 方法发送一个名为 AViewModel.Name 的属性的值。当您的参数类型为 AViewModel 时,它什么也找不到,因为它正在寻找名称为 AViewModel 的参数类型的 子属性,然后分配 对象的Name 属性为输入值。

如果您不想将每个 POST 方法的参数设置为 ProductViewModel,那么您有一个领先的替代方案:为您的五种不同表单创建局部视图,并从您的 ProductViewModel 中传递各个属性作为局部视图的模型。然后,这将从您的 asp-for 属性中消除 AViewModel 属性前缀。

【讨论】:

以上是关于使用单一视图模型在 MVC Razor 视图上发布多个表单的主要内容,如果未能解决你的问题,请参考以下文章

使用 MVC Razor 语法检查视图模型属性在 Javascript 中是不是具有值

MVC3 Razor - 模型和视图

MVC Razor 视图嵌套 foreach 的模型

带有 Razor 的 MVC3 - 避免在部分视图上定义多个 javascript 函数

MVC 5 Razor 视图未将 bool 绑定到输入

MVC 3 Razor Form Post w/ 多个强类型的部分视图不绑定