是否可以在 MVC 中将一个 ViewModel 放在另一个 ViewModel 中?

Is it possible to have one ViewModel in another ViewModel in MVC?

我有一个供应商可以有多个地址的要​​求。所以我创建了一个 CommunicationDetailsViewModel 如下所示:

public class CommunicationDetailsViewModel
{
    public string OrganizationName { get; set; }
    public List<Country> Country { get; set; }

    public List<State> State { get; set; }

    public List<City> City { get; set; }

    [Display(Name = "Id")]
    public int CountryId { get; set; }

    [Display(Name = "Id")]
    public int StateId { get; set; }

    [Display(Name = "Id")]
    public int CityId { get; set; }

    [StringLength(32), Required(ErrorMessage ="Address is required")]
    public string Address { get; set; }

}

我还有一个叫 SuppllierInformationViewModelViewModel,如下所示:

public class SupplierInformationViewModel
{
    [StringLength(50, ErrorMessage = "Organization name cannot be greater than 50 characters"), Required(ErrorMessage ="Organization name is required")]
    public string OrganizationName { get; set; }

    public List<CommunicationDetailsViewModel> CommunicationDetailsViewModel { get; set; }
}

我创建了这个 ViewModel 因为 Supplier 可以有多个地址。所以创建了一个 CommunicationDetailsViewModel 的集合。更进一步,供应商实体将拥有其他信息,如银行信息、税务信息等。所以我想为每一个创建一个 ViewModel 和一个 SupplierInformationViewModel 来保存所有这些其他 ViewModels。我们可以创建 ViewModelViewModels 吗?

在视图中,我必须绑定这多个地址。以下是我的看法:

@model WebAPI.ViewModels.SupplierInformationViewModel
@{
    ViewBag.Title = "Supplier Information";
}

<h4>Supplier Details</h4>

@using (Html.BeginForm("Save", "SupplierInformation", FormMethod.Post))
{
    <div class="demo-section k-content">
        <div class="form-group">
            @Html.Label("Organization name")
            @Html.Kendo().TextBoxFor(model => model.OrganizationName).Name("OrganizationName").HtmlAttributes(new { @class = "k-textbox required", placeholder = "Organization Name" })
        </div>

        @for (int i = 0; i < Model.CommunicationDetailsViewModel.Count; i++)
        {
            <div class="form-group">
                @Html.Label("Country")
                @(Html.Kendo().DropDownList().Name("CountryId").DataTextField("CountryName").DataValueField("Id").BindTo(Model.CommunicationDetailsViewModel[i].Country))
            </div>
            <div class="form-group">
                @Html.Label("State")
                @(Html.Kendo().DropDownList().Name("StateId").DataTextField("StateName").DataValueField("Id").BindTo(Model.CommunicationDetailsViewModel[i].State))
            </div>
            <div class="form-group">
                @Html.Label("City")
                @(Html.Kendo().DropDownList().Name("CityId").DataTextField("CityName").DataValueField("Id").BindTo(Model.CommunicationDetailsViewModel[i].City))
            </div>
            <div class="form-group">
                @Html.Label("Address")
                @Html.Kendo().TextBoxFor(model => model.CommunicationDetailsViewModel[i].Address).Name("Address").HtmlAttributes(new { @class = "k-textbox required", placeholder = "Address", @maxlength = "32" })
            </div>
            <div class="form-group">
                @Html.Label("Building name")
                @Html.Kendo().TextBoxFor(model => Model.CommunicationDetailsViewModel[i].BuildingName).Name("BuildingName").HtmlAttributes(new { @class = "k-textbox required", placeholder = "Address", @maxlength = "32" })
            </div>
        }
    </div>
    @Html.Kendo().Button().Name("btnSave").Content("Save").HtmlAttributes(new { type = "submit", @class = "k-button k-primary" })
}    

现在,当我 post 返回操作时,我确实在 SupplierInformationViewmodel 中得到 OrganizationName,但 CommunicationDetailsViewModel 为空。
这是为什么?它与命名约定有什么关系吗?如果是这样,我该如何处理?
任何帮助表示赞赏。

我的操作方法

[HttpPost]
public ActionResult Save(SupplierInformationViewModel supplierInformationViewModel)
{
    return View();
}

您需要使用索引和强类型 DropDownListFor(),以便生成正确的名称属性并指向循环中的项目:

Model.CommunicationDetailsViewModel[i].CountryId

像这样:

@Html.Kendo().DropDownListFor(model => model.CommunicationDetailsViewModel[i].CountryId)

您应该使用强类型 DropDownListFor() 来绑定嵌套视图模型,如下所示:

@(Html.Kendo().DropDownListFor(model => model.CommunicationDetailsViewModel[i].CountryId)
              .DataTextField("CountryName")
              .DataValueField("Id")
              .DataSource(ds => ds.Read(read => 
                  read.Action("GetCountry", "ControllerName")
               ))
 )

当使用 DropDownListFor() 时,则 Name("CountryId") 变得不必要。

您也可以尝试添加无参数构造函数,它分配 List<CommunicationDetailsViewModel> 的新实例:

public class SupplierInformationViewModel
{
    public SupplierInformationViewModel()
    {
        this.CommunicationDetailsViewModel = new List<CommunicationDetailsViewModel>();
    }

    [StringLength(50, ErrorMessage = "Organization name cannot be greater than 50 characters"), Required(ErrorMessage ="Organization name is required")]
    public string OrganizationName { get; set; }

    public List<CommunicationDetailsViewModel> CommunicationDetailsViewModel { get; set; }
}