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

时间:2012-10-29 06:50:22

标签: c# .net asp.net-mvc razor

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

我的创建动作方法:

Roles

我的观点( Create.cshtml ):

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

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

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

2 个答案:

答案 0 :(得分: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)

Edit2

您有模型绑定问题

在你看来

@Html.ListBox("selectedRoles", (IEnumerable<SelectListItem>)ViewBag.Roles)
在你的Post Action中,尝试添加一个新参数:

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

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

修改

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

  • DropDownList(ParentMenuId)

  • ListBox(RoleIDs)

  • 此listBox的结果(后期操作的模型绑定)

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

然后你的行动将是

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

Pro ViewModel:

  • 您只是使用了所需的属性。

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

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

Cons ViewModel:

  • 你必须在get动作中将你的Model映射到你的ViewModel,并在post动作中从ViewModel映射到Model,但是......它的价格更差!

答案 1 :(得分:-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);
    }