我在发布包含字典的viewmodel时遇到问题。每次我在控制器操作中收到模型时,所有值都为空(实际上只是我需要的字典值),而且我不确定如何解决这个问题或者为什么会发生这种情况。您可以在下面找到我的视图(不相关的部分除外),我的控制器和我正在使用的视图模型。这里的想法是传递一个将用户与角色相关联的字典,允许管理员编辑各种用户角色,然后将信息传递回控制器以使用新角色信息更新数据库。我有幸运过过去的序列化IEnumerables(列表等),但不能让它为字典工作。所有帮助表示赞赏。
观点:
@model RecipeManager.ViewModels.AdminViewModel
@{
ViewBag.Title = "Index";
}
<h2>Admin</h2>
@using (Html.BeginForm("UpdateRoles", "Admin", FormMethod.Post))
{
<div>
@for (int i = 0; i < Model.UsersAndRoles.Count; i++)
{
<strong>@Model.UsersAndRoles.ElementAt(i).Key.UserName</strong>
@Html.DropDownListFor(m => m.UsersAndRoles.ElementAt(i).Value, Model.RoleTypes, Model.UsersAndRoles.ElementAt(i).Value, new { @class = "form-control" })
}
</div>
<input type="submit" value="Update Roles" />
}
html的示例产生了用户名和管理员角色下拉列表:
<strong>test+cook@test.com</strong> <select class="form-control" id="Value" name="Value"><option value="">Cook</option>
<option value="1">Admin</option>
<option value="2">Cook</option>
<option value="3">Retail</option>
</select>
Controller Action(在AdminController
中):
[AuthorizeUser(Activity = "ViewAdmin")]
[HttpPost]
public ActionResult UpdateRoles(AdminViewModel vm)
{
return View("Index");
}
ViewModel(AdminViewModel
):
namespace RecipeManager.ViewModels
{
public class AdminViewModel
{
public SelectList RoleTypes { get; set; }
public String SelectedRole { get; set; }
public String InviteEmailAddress { get; set; }
public Dictionary<ApplicationUser, string> UsersAndRoles { get; set; }
}
}
答案 0 :(得分:2)
您生成的<select>
元素的名称属性(name="Value"
)与您的属性没有关系Dictionary
。要绑定到Dictionary
以需要Key
和Value
属性的输入,并且因为它是一个集合,它们也需要被编入索引。在你的情况下,它变得更糟,因为你的Key
是一个复杂的对象。
为了绑定,您生成的html必须是
<input type="hidden" name="UsersAndRoles[0].Key.Id" value="...." />
<input type="hidden" name="UsersAndRoles[0].Key.UserName" value="...." />
.... // more hidden inputs for each property of ApplicationUser
<select name="UsersAndRoles[0].Value">
<option value="">Cook</option>
....
</select>
<input type="hidden" name="UsersAndRoles[1].Key.Id" value="...." />
<input type="hidden" name="UsersAndRoles[1].Key.UserName" value="...." />
.... // more hidden inputs for each property of ApplicationUser
<select name="UsersAndRoles[1].Value">
<option value="">Cook</option>
....
</select>
标准HtmlHelper
方法不会开箱即用(尽管您可以创建自己的扩展方法来生成html)。但是,如果您只是设计视图模型来表示要在视图中编辑的内容,那将会容易得多。
然而,从您当前的视图模型中不清楚您想要绑定到什么。
您有public String SelectedRole { get; set; }
属性未使用且Dictionary
Value
类型为string
,但SelectListItem
的值为int
类型。此外,使用DropDownListFor()
方法将无法正常运行,除非您将EditorTemplate
与AdditionalViewData
结合使用,或生成this answer中所述的新IEnumerable<SelectListItem>
。 (请注意,即使第3个选项(“cook”)应该是),也没有任何选项具有selected
属性。另请注意,DropDownListFor()
的第3个参数会生成null
选项,因此它应为"Please select"
或类似,而不是当前角色的值。
您的视图模型(基于您显示的视图代码)应为
public class AdminViewModel
{
public SelectList RoleTypes { get; set; }
public List<UserRoleViewModel> UserRoles { get; set; }
}
public class UserRoleViewModel
{
public int ID { get; set; }
public string UserName { get; set; }
[Display(Name = "Role")]
[Required(ErrorMesage = "Please select a role")]
public int SelectedRole { get; set; }
}
然后在EditorTemplate
/Views/Shared/EditorTemplates/UserRoleViewModel.cshtml
@model UserRoleViewModel
@Html.HiddenFor(m => m.ID)
@Html.HiddenFor(m => m.UserName)
<strong>@Html.DisplayFor(m => m.UserName)</strong>
@Html.LabelFor(m => m.SelectedRole)
@Html.DropDownListFor(m => m.SelectedRole, (SelectList)ViewData["RoleTypes"], "Please Select")
@Html.ValidationMessageFor(m => m.SelectedRole)
然后在主视图中
@model RecipeManager.ViewModels.AdminViewModel
....
@using (Html.BeginForm("UpdateRoles", "Admin", FormMethod.Post))
{
@Html.EditorFor(m => m.UserRoles, new { RoleTypes = Model.RoleTypes })
<input type="submit" value="Update Roles" />
}