ASP.NET MVC 无法 POST 绑定到复选框的视图模型
ASP.NET MVC cannot POST view model with binding to checkbox
这是我的视图模型:
public class UserViewModel
{
public User GroupUser { get; set; }
public bool Checked { get; set; }
}
public class GroupUserViewModel
{
public Guid GroupId { get; set; }
public string GroupName { get; set; }
public IList<UserViewModel> Users;
}
我的看法:
@model GroupUserViewModel
@{
ViewBag.Title = "Users";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@Model.GroupName</h2>
@using (Html.BeginForm("AddUserToGroup", "Group", FormMethod.Post))
{
for (var userIter = 0; userIter < Model.Users.Count(); userIter++)
{
<div class="form-group">
@Html.DisplayFor(model => model.Users[userIter].GroupUser.UserName)
@Html.CheckBoxFor(model => model.Users[userIter].Checked)
@Html.HiddenFor(model => model.GroupId)
@Html.HiddenFor(model => model.GroupName)
</div>
}
<input type="submit" class="btn btn-success" value="Save"/>
}
我的控制器:
[HttpPost]
public ActionResult AddUserToGroup(GroupUserViewModel groupUsers)
{
//do things
}
我检查了 POST 数据,它是:
Users[0].Checked=true
Users[0].Checked=false
Users[1].Checked=false
对于我勾选的方框,有 2 个条目,一个 true
和一个 false
。这正常吗?
同样在控制器中,我得到的是:
groupUsers.GroupId = {00000000-0000-0000-0000-000000000000}
groupUsers.GroupName = null
groupUsers.Users = null
显然,由于表单实际上并未将我想要的视图模型发布回控制器,因此发生了这种情况。有什么方法可以将所需的视图模型传递回控制器,因为我需要 GroupId
和 GroupName
?
编辑:
经过一些更新并添加 GroupId
和 GroupName
的隐藏字段后,现在 POST 数据为:
Users[0].Checked=true
Users[0].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName
MyObjects[1].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName
GroupId
和 GroupName
现在正在正确传递,但列表仍然是 null
。
是的,这很正常。原因是因为未选中的复选框不会 post 值,因此 ASP.NET 为每个具有与复选框控件后面的复选框相同 ID 的复选框呈现一个隐藏字段,并将其值设置为 false。 ASP.NET 如果有多个同名表单字段,DefaultModelBinder 将取第一个值。如果未选中该复选框,这会导致从隐藏字段 post 编辑一个 false 值,以及两个值,一个 false 用于隐藏字段,一个 true 用于选中的复选框。因为隐藏字段在复选框之后,如果复选框 post 是一个值,它将覆盖隐藏字段。
但是,这并没有回答您关于模型为何不具有约束力的问题..
GroupUserViewModel
中的 IList<UserViewModel> Users
是一个字段,而不是 属性,因此 DefaultModelBinder
无法设置其值。改成
public class GroupUserViewModel
{
....
public IList<UserViewModel> Users { get; set; } // make it a property
}
这是我的视图模型:
public class UserViewModel
{
public User GroupUser { get; set; }
public bool Checked { get; set; }
}
public class GroupUserViewModel
{
public Guid GroupId { get; set; }
public string GroupName { get; set; }
public IList<UserViewModel> Users;
}
我的看法:
@model GroupUserViewModel
@{
ViewBag.Title = "Users";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>@Model.GroupName</h2>
@using (Html.BeginForm("AddUserToGroup", "Group", FormMethod.Post))
{
for (var userIter = 0; userIter < Model.Users.Count(); userIter++)
{
<div class="form-group">
@Html.DisplayFor(model => model.Users[userIter].GroupUser.UserName)
@Html.CheckBoxFor(model => model.Users[userIter].Checked)
@Html.HiddenFor(model => model.GroupId)
@Html.HiddenFor(model => model.GroupName)
</div>
}
<input type="submit" class="btn btn-success" value="Save"/>
}
我的控制器:
[HttpPost]
public ActionResult AddUserToGroup(GroupUserViewModel groupUsers)
{
//do things
}
我检查了 POST 数据,它是:
Users[0].Checked=true
Users[0].Checked=false
Users[1].Checked=false
对于我勾选的方框,有 2 个条目,一个 true
和一个 false
。这正常吗?
同样在控制器中,我得到的是:
groupUsers.GroupId = {00000000-0000-0000-0000-000000000000}
groupUsers.GroupName = null
groupUsers.Users = null
显然,由于表单实际上并未将我想要的视图模型发布回控制器,因此发生了这种情况。有什么方法可以将所需的视图模型传递回控制器,因为我需要 GroupId
和 GroupName
?
编辑:
经过一些更新并添加 GroupId
和 GroupName
的隐藏字段后,现在 POST 数据为:
Users[0].Checked=true
Users[0].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName
MyObjects[1].Checked=false
Id=015f5aef-eb6c-449e-9f08-9d42110c5347
GroupName=MyName
GroupId
和 GroupName
现在正在正确传递,但列表仍然是 null
。
是的,这很正常。原因是因为未选中的复选框不会 post 值,因此 ASP.NET 为每个具有与复选框控件后面的复选框相同 ID 的复选框呈现一个隐藏字段,并将其值设置为 false。 ASP.NET 如果有多个同名表单字段,DefaultModelBinder 将取第一个值。如果未选中该复选框,这会导致从隐藏字段 post 编辑一个 false 值,以及两个值,一个 false 用于隐藏字段,一个 true 用于选中的复选框。因为隐藏字段在复选框之后,如果复选框 post 是一个值,它将覆盖隐藏字段。 但是,这并没有回答您关于模型为何不具有约束力的问题..
GroupUserViewModel
中的 IList<UserViewModel> Users
是一个字段,而不是 属性,因此 DefaultModelBinder
无法设置其值。改成
public class GroupUserViewModel
{
....
public IList<UserViewModel> Users { get; set; } // make it a property
}