0

many-to-many在菜单模型中有一个名为 的字段Roles,我正在尝试为模型创建一个“创建”视图。

我的创建操作方法:

    public ActionResult Create()
    {
        ViewBag.ParentMenuId = new SelectList(_db.Menus, "Id", "Name");
        ViewBag.Roles = new SelectList(_db.UserRoles.ToList(), "Id", "Name");
        return View();
    }

    [HttpPost]
    public ActionResult Create(Menu menu)
    {
        if (ModelState.IsValid)//the state is always **invalid**
        {
            _db.Menus.Add(menu);
            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.ParentMenuId = new SelectList(_db.Menus, "Id", "Name", menu.ParentMenuId);
        return View(menu);
    }

我的观点(Create.cshtml):

    <div class="editor-label">
        @Html.LabelFor(model => model.Roles, "Roles")
    </div>
    <div class="editor-field">
        @Html.ListBox("Roles")
        @Html.ValidationMessageFor(model => model.Roles)
    </div>

如何解决?我收到以下错误:

The ViewData item that has the key '' is of type '' but must be of type 'IEnumerable<SelectListItem>'

4

2 回答 2

4

嗯,错误信息很清楚,你需要一个IEnumerable<SelectListItem>

所以改变你的 ViewBag.Roles 定义

new SelectList(_db.UserRoles.ToList(), "Id", "Name");

_db.UserRoles.ToList().Select(m => new SelectListItem { Value=m.Id, Text=m.Name});

编辑

在您看来:

@Html.ListBox("Roles", (IEnumerable<SelectListItem>)ViewBag.Roles)

编辑2

您有模型绑定问题

在你看来

@Html.ListBox("selectedRoles", (IEnumerable<SelectListItem>)ViewBag.Roles)

在您的 Post Action 中,尝试添加一个新参数:

[HttpPost]
    public ActionResult Create(Menu menu, int[] selectedRoles)

并在您的操作代码中“手动”处理每个选定的角色。

编辑

ViewModel 示例(不按原样工作)在您看来,您需要

  • 下拉列表(ParentMenuId)

  • 一个列表框(角色 ID)

  • 此列表框的结果(发布操作的模型绑定)

  • Menu 类的其他属性(可能不是全部)

这个想法是创建一个

public class MenuViewModel 
{
  public IEnumerable<SelectListItem> ParentMenuList {get;set;}//a dropDown
  public IEnumerable<SelectListItem> RoleList {get;set;}//a listBox
  public string Name {get;set;}//the menu name //the menu name
  public List<int> SelectedRoles {get;set;}
}

那么你的 get Action 将是

public ActionResult Create()
{
  var model = new MenuViewModel();
  model.ParentMenuList = new SelectList(_db.Menus, "Id", "Name");
  model.RoleList = new SelectList(_db.UserRoles.ToList(), "Id", "Name");
  return View(model);
}

您的视图将 MenuViewModel... 作为模型

@model MenuViewModel
//your other code
//the listbox
 <div class="editor-label">
        @Html.LabelFor(model => model.SelectedRoles, "Roles")
    </div>
    <div class="editor-field">
        @Html.ListBoxFor(m => m.SelectedRoles, Model.RoleList)
        @Html.ValidationMessageFor(model => model.Roles)
    </div>

那么您的 POST 操作将变为

[HttpPost]
public ActionResult Create(MenuViewModel model)
{
    if (ModelState.IsValid)
    {
       var menu = new Menu {Name = model.Name };//for example
       menu.Roles =  _db.UserRoles.Where(rl => model.SelectedRoles.Contains(rl.Id)).ToList();
       _db.SaveChanges();
       return RedirectToAction("Index");
    }
    return View(model);
}

专业视图模型:

  • 你只是在使用你需要的属性。

  • 你不需要 ViewBag (这很好避免:它是动态的,不是强类型的,所以......很难测试,重构问题等)

  • 一切都在您的视图模型中

缺点视图模型:

  • 您必须在 get 操作中将您的 Model 映射到您的 ViewModel,并在 post 操作中从 ViewModel 映射到 Model,但是......价格更糟!
于 2012-10-29T07:45:31.460 回答
-1

我正在创建相同的项目,但我没有收到该错误。

似乎列表框的模型绑定到了另一种类型,尝试像这样显式指定 viewbag 模型:

@Html.ListBox("Roles",ViewBag.Roles as SelectList)

并在 [HttpPost] 方法中尝试添加存在于 Create - get 方法中的 ViewBag.Roles,如下所示:

[HttpPost]
    public ActionResult Create(Menu menu)
    {
        if (ModelState.IsValid)//the state is always **invalid**
        {
            _db.Menus.Add(menu);
            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        ViewBag.ParentMenuId = new SelectList(_db.Menus, "Id", "Name", menu.ParentMenuId);
        ViewBag.Roles = new SelectList(_db.UserRoles.ToList(), "Id", "Name");
        return View(menu);
    }
于 2012-10-29T08:15:59.287 回答