如何从ViewModel列表中发布ViewModel

时间:2015-10-07 01:31:38

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

我目前有一个视图,我将ViewModel列表传递给。然后我想选择其中一个ViewModel并将其发回给我的控制器。我目前有一个foreach循环遍历每个ViewModel并显示他们的数据。对于每个ViewModel,还有一个提交按钮,但它似乎没有像我希望的那样工作。

解释的代码(查看):

@model IEnumerable<RoboticsScheduler.Models.UserVM>
...
@using (Html.BeginForm("UserApproved", "Approve"))
{
...
    @foreach (var item in Model)
    {
    ...
    @*Modified model data*@
    ...
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Approve User" class="btn btn-default" />
        </div>
    </div>
    }
}

然后在我的接受控制器中,我将UserVM作为参数,但我一直在控制器中获得空的UserVM。

控制器中的代码:

public async Tas<ActionResult> UserApproved(UserVM uvm)
{
...
}

如果有人建议我如何能够完成这样的事情,那就太棒了!

修改

显示更深入的视图并将BeginForm移动到循环中:

...
@foreach (var item in Model)
{
    using (Html.BeginForm("Index", "Approved", FormMethod.Post))
    {
        <tr>
            <td>
                @Html.HiddenFor(modelItem => item.Id)
                @Html.DisplayFor(modelItem => item.Email)
            </td>
            <td>
                @item.EmailConfirmed.ToString()
            </td>
            <td>
                <span class="col-md-10">
                    @{List<string> roles = ViewBag.Roles;
                    int i = 0;
                    }
                    @foreach (string role in roles)
                    {
                        @Html.EditorFor(modelItem => item.Roles[i])
                        @Html.Label(role, new { @class = "control-label" })
                        <br />
                    }
                </span>
            </td>
            <td>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <input type="submit" value="Approve User" class="btn btn-default" />
                    </div>
                </div>
            </td>
        </tr>
    }
}

2 个答案:

答案 0 :(得分:0)

解决方案是了解MVC在发布表单时如何将值绑定回控制器。详细解释..

<强>解决方案: 您的视图模型为@model IEnumerable<RoboticsScheduler.Models.UserVM>,因此表单提交变得棘手,因为您处理单个对象。你有for循环正确,但你需要了解它发生了什么。

@foreach (string role in roles)
 {
    @Html.EditorFor(modelItem => item.Roles[i])
    @Html.Label(role, new { @class = "control-label" })
    <br />
 }

这里的编辑器用于呈现名称类似item.Role的HTML标记,这就是问题所在。 name参数是您使表单发布成功所需的唯一选择。所以你要做的就是......

@Html.EditorFor(modelItem => item.Roles[i], new {Name = 'RoleType'}) 

这里我隐含地给输入标签命名。此外,我假设您的ViewModel UserVM具有名为RoleType的属性。类似下面的内容

public class UserVM
{
  public string RoleType {get;set;}
  public int UserId {get;set;} // you will see why this in my below explanation
} 

现在,当您提交表单时,MVC将看到控制器操作的输入参数类型,其UserVM对象,现在它查看此对象内部以查找与表单内的输入元素同名的属性。在我们的例子中,我们有一个名为RoleType的输入标签,我们在对象中有一个名为RoleType的属性,所以MVC很乐意绑定它的值。

<强>建议: 阅读完您的评论后,我了解到您希望显示用户想要选择角色的角色下拉列表。所以你可以试试这个..

更改从Viewbag中提取数据的方式的逻辑

@{
   List<string> roles = ViewBag.Roles;
   int i = 0;
   var RolesList = roles.select(c => new SelectListItem {Text=c,Value=c}).ToList();
 }

上面的代码将使用Linq语法构建一个SelectListItem对象列表(这是我们在处理下拉列表时必须在MVC中使用的对象)。现在在里面 您的表格更改为此

@foreach (var item in Model)
   {
    using (Html.BeginForm("Index", "Approved", FormMethod.Post))
    {
        @Html.HiddenFor(modelItem => item.Id, new {Name = "UserId"}) 
        @Html.DropDownList("RoleType",RolesList)
        @Html.Label(role, new { @class = "control-label" })
        <br />
    }
   }

所以上面的语法说它是一个下拉列表,并且还有一个名称 RoleType ,还有一个隐藏字段,名称更改为 UserId (我们知道)为什么我在上面的解释)。现在将在提交表单时发布。如果您希望它们也被发布,您可以将任何其他字段放在hiddenfor语法中。

注意:使用MVC时应该知道的主要事情是默认的 MVC模型绑定完全依赖于名称属性输入标签(也是选择标签)以实现成功发布。

其他信息:上述表单帖子等同于在查询字符串中执行相同操作..

yourlocalhost/Approved/Index?RoleType="Admin"&UserId="23"

您仍然可以使用相同的控制器语法。这是为了让您更清楚MVC完成的模型绑定。您可以尝试它并在操作方法中检查您的对象,以查看填充到对象的相应属性的值。

答案 1 :(得分:0)

//Person
@model MvcApplication1.Models.Person
@{
     ViewBag.Title = "Index";    
 }

<h2>Person</h2>

@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <div>
        @Html.TextBoxFor(model => model.Id, new { id = "Id"})
    </div>

    <div>
        @Html.TextBoxFor(model => model.Nome, new { id = "Name" })
    </div>

     if (Model != null && Model.Phone != null)
     {
         foreach (var phone in Model.Phone)
         {
             Html.RenderPartial("_Phone", phone);
         }
     }    

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


//phone
@model MvcApplication1.Models.Phone

@using (Html.BeginCollectionItem("Phone"))
{
     <div>
        <div>
            @Html.EditorFor(model => model.PhoneNumber)
        </div>
    </div>
}

使用Html.BeginCollectionItem https://www.nuget.org/packages/BeginCollectionItem/