如何编写模型的“创建”视图?

时间:2022-09-14 09:28:10

I have a many-to-many field in Menu model named Roles, i'm trying to create a 'create' view for the model.

我在Menu模型中有一个名为Roles的多对多字段,我正在尝试为模型创建一个“创建”视图。

my create action methods:

我的创建动作方法:

    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);
    }

my view(Create.cshtml):

我的观点(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>

how to fix it? I'm getting the following error:

怎么解决?我收到以下错误:

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

具有键''的ViewData项的类型为'',但必须是'IEnumerable 类型的'

2 个解决方案

#1


4  

Well, the error message is rather clear, you nead a IEnumerable<SelectListItem>

好吧,错误信息相当清楚,你有一个IEnumerable

So change your ViewBag.Roles definition from

所以改变你的ViewBag.Roles定义

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

to

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

Edit

编辑

In your view :

在你看来:

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

Edit2

EDIT2

You have a model binding problem

你有一个模型绑定问题

In your view

在你看来

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

in your Post Action, try to add a new parameter :

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

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

and treat each selected role "manually" in your action code.

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

EDIT

编辑

ViewModel sample (not working as is) In your view, you need

ViewModel示例(不按原样工作)在您的视图中,您需要

  • a DropDownList (ParentMenuId)

    DropDownList(ParentMenuId)

  • a ListBox (RoleIDs)

    ListBox(RoleIDs)

  • the result of this listBox (model binding for the post action)

    这个listBox的结果(post动作的模型绑定)

  • other properties of the Menu class (maybe not all)

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

The idea would be to create a

想法是创建一个

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;}
}

then your get Action would be

然后你的行动将是

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);
}

your view would have MenuViewModel... as 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>

then your POST action would become

然后你的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);
}

Pro ViewModel :

Pro ViewModel:

  • you're just using the properties you need.

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

  • you don't need ViewBag (which is nice to avoid : it's dynamic, not strongly typed, so... hard to test, refactoring problems, etc.)

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

  • everything is in your view's model

    一切都在你视图的模型中

Cons ViewModel :

缺点ViewModel:

  • you have to map your Model to your ViewModel in the get action, and map from ViewModel to Model in post action, but... it's worse the price !
  • 你必须在get动作中将你的Model映射到ViewModel,并在post动作中从ViewModel映射到Model,但是......它的价格更差!

#2


-1  

I was create same project but i don't get that error.

我是创建相同的项目,但我没有得到该错误。

It seems model of listbox was bound to another type, try to specify explicitly viewbag model like this:

似乎列表框的模型绑定到另一个类型,尝试明确指定viewbag模型,如下所示:

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

And in [HttpPost] method try to add ViewBag.Roles which exists in Create - get method, like this:

并在[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);
    }

#1


4  

Well, the error message is rather clear, you nead a IEnumerable<SelectListItem>

好吧,错误信息相当清楚,你有一个IEnumerable

So change your ViewBag.Roles definition from

所以改变你的ViewBag.Roles定义

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

to

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

Edit

编辑

In your view :

在你看来:

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

Edit2

EDIT2

You have a model binding problem

你有一个模型绑定问题

In your view

在你看来

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

in your Post Action, try to add a new parameter :

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

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

and treat each selected role "manually" in your action code.

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

EDIT

编辑

ViewModel sample (not working as is) In your view, you need

ViewModel示例(不按原样工作)在您的视图中,您需要

  • a DropDownList (ParentMenuId)

    DropDownList(ParentMenuId)

  • a ListBox (RoleIDs)

    ListBox(RoleIDs)

  • the result of this listBox (model binding for the post action)

    这个listBox的结果(post动作的模型绑定)

  • other properties of the Menu class (maybe not all)

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

The idea would be to create a

想法是创建一个

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;}
}

then your get Action would be

然后你的行动将是

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);
}

your view would have MenuViewModel... as 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>

then your POST action would become

然后你的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);
}

Pro ViewModel :

Pro ViewModel:

  • you're just using the properties you need.

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

  • you don't need ViewBag (which is nice to avoid : it's dynamic, not strongly typed, so... hard to test, refactoring problems, etc.)

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

  • everything is in your view's model

    一切都在你视图的模型中

Cons ViewModel :

缺点ViewModel:

  • you have to map your Model to your ViewModel in the get action, and map from ViewModel to Model in post action, but... it's worse the price !
  • 你必须在get动作中将你的Model映射到ViewModel,并在post动作中从ViewModel映射到Model,但是......它的价格更差!

#2


-1  

I was create same project but i don't get that error.

我是创建相同的项目,但我没有得到该错误。

It seems model of listbox was bound to another type, try to specify explicitly viewbag model like this:

似乎列表框的模型绑定到另一个类型,尝试明确指定viewbag模型,如下所示:

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

And in [HttpPost] method try to add ViewBag.Roles which exists in Create - get method, like this:

并在[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);
    }