【问题标题】:How can I bind nested ViewModels from View to Controller in MVC3?如何在 MVC3 中将嵌套的 ViewModel 从 View 绑定到 Controller?
【发布时间】:2011-08-07 17:14:14
【问题描述】:

我正在用 C# 开发一个 ASP.NET MVC 3 应用程序,并且我使用 Razor。我现在正在处理一个关于通过控制器传递/接收到视图/从视图中的视图模型绑定对象的问题。 让我们说清楚。我有以下 ViewModel:

public class ContainerViewModel
{
   public int ContainerId {get; set;}
   public string ContainerName {get; set;}
   public List<ItemPostModel> ItemData {get; set;}
}

public class ItemPostModel
{ 
   public int ItemId {get; set;}
   public string ItemName {get; set;}
   public int ItemValue {get; set;}
}

ContainerViewModel 用于将数据传递给 View。它的属性 ContainerIdContainerName 仅用于显示目的。 List&lt;ItemPostModel&gt; 属性必须使用 Form 填写。视图看起来像这样(它是一个简化版本):

<strong>@Model.ContainerName</strong>


@using (Html.BeginForm()) 
{
    <fieldset>
    @foreach(var item in Model.ItemData)
    {
       @Html.TextBox(item.ItemId);
       @Html.TextBox(item.ItemName);
       @Html.TextBox(item.ItemValue);

       <p>
           <input type="submit" value="Save" />
       </p>
    }
    </fieldset>
}

Controller对应的动作方法如下:

public ActionResult UpdateItems()
{
   //fill in the ContainerViewModel lcontainer

   return View("UpdateItems", lcontainer);
}

[HttpPost]
public ActionResult UpdateItems(int containerId, ItemPostModel itemData)
{
   //store itemData into repository
}

问题在于,使用此代码,传递给 Post ActionMethod UpdateItemsItemPostModel itemData 始终为空。 containerId 已正确传递。如果我在控制器中使用以下代码,结果相同(显然不是 DRY);

[HttpPost]
public ActionResult UpdateItems(ContainerViewModel container)
{
   //extract itemData from ContainerViewModel container
   //store itemData into repository
}

我如何“教导”应用程序我希望将表单元素存储在 List&lt;ItemPostModel&gt; 中?我应该修改 ModelBinder 还是有更简单的方法来执行此任务?谢谢大家的回答。

【问题讨论】:

    标签: c# asp.net-mvc-3 binding viewmodel


    【解决方案1】:

    不要在视图中编写循环。使用编辑器模板:

    <strong>@Model.ContainerName</strong>
    @using (Html.BeginForm()) 
    {
        <fieldset>
            @Html.EditorFor(x => x.ItemData)
            <input type="submit" value="Save" />
        </fieldset>
    }
    

    并在相应的编辑器模板内(~/Views/Shared/EditorTemplates/ItemPostModel.cshtml):

    @model ItemPostModel
    @Html.TextBox(x => x.ItemId)
    @Html.TextBox(x => x.ItemName)
    @Html.TextBox(x => x.ItemValue)
    

    在控制器动作中你可能需要指定前缀:

    [HttpPost]
    public ActionResult UpdateItems(
        int containerId, 
        [Bind(Prefix = "ItemData")]ItemPostModel itemData
    )
    {
       //store itemData into repository
    }
    

    这应该差不多了。编辑器模板将负责为绑定工作生成正确的输入字段名称。

    【讨论】:

    • 感谢您的回答。 ~/Views/Shared/EditorTemplates/ItemPostModel.cshtml 是局部视图对吗?此外,您为什么建议不要在视图中使用 foreach ?不是用代码块“破坏”html吗?谢谢
    • @Francesco,是的,ItemPostModel.cshtml 是部分的。另外我建议避免在视图中使用循环,因为有编辑器模板负责为输入字段生成正确的名称。因此,这不仅简化了代码,而且当您想在控制器中取回这些值时,它还可以与默认模型绑定器一起使用。
    • 我最初错过的一个值得强调的重点是 EditorFor 帮助器自动处理 ItemPostModel 的集合,即使 EditorTemplate 用于单个 ItemPostModel(而不是集合)。
    • 应该是@Html.TextBoxFor(x =&gt; x.ItemId) 而不是@Html.TextBox(x =&gt; x.ItemId)
    • [Bind(Prefix=Items)]... 真的帮了我
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多