MVC - 使用自定义模板将数据绑定到集合的问题

Nei*_*ski 1 asp.net-mvc binding model razor asp.net-mvc-3

我试图绑定到具有集合属性的模型,特别是List.出于此示例的目的,这表示用户角色列表:

public class RolesModel
{
   private List<SelectListItem> _Roles = null;
   public string Name { get; set; }
   public List<SelectListItem> Roles
   {
      get {
        if (_Roles == null) { _Roles = new List<SelectListItem>(); }
        return _Roles;
      }
      set { _Roles = value; }
   }
}
Run Code Online (Sandbox Code Playgroud)

我通过以下Controller将其绑定到强类型视图:

public class TestController : Controller
{
   RolesModel myModel = new RolesModel();

   [HttpGet]
   public ActionResult Edit()
   {
      myModel.Name    = "Joe Bloggs";
      myModel.Roles = new List<SelectListItem>
      {
         new SelectListItem { Value = "1", Text = "Member", Selected = true },
         new SelectListItem { Value = "2", Text = "Manager", Selected = true },
         new SelectListItem { Value = "3", Text = "Administrator", Selected = false }
      };

      return View(myModel);
   }


   [HttpPost]
   public ActionResult Edit(RolesModel m)
   {
      // !!! m.Roles is always empty !!!
      return View("Results", m);
   }
}
Run Code Online (Sandbox Code Playgroud)

然后调用以下视图:

@model MyProject.WebUI.Models.RolesModel
@using (Html.BeginForm())
{
   <p>
      @Html.LabelFor(m => m.Name)
      @Html.EditorFor(m => m.Name)
   </p>                              
   <div>
      @Html.EditorFor(m => m.Roles, "CheckBoxList")
   </div>                              
   <p>
      <input type="submit" value="Save" />
   </p>
}
Run Code Online (Sandbox Code Playgroud)

请注意在'/Views/Shared/EditorTemplates/CheckBoxList.cshtml'中对我的自定义编辑器模板的模板特定调用,如下所示:

@model List<System.Web.Mvc.SelectListItem>

<h3>Type: @Html.LabelFor(m => m)</h3>
<ul>
   @for (int i = 0; i < Model.Count; i++)
   {
      <li>
         @Html.CheckBoxFor(m => m[i].Selected)
         @Html.LabelFor(m => m[i].Selected, Model[i].Text)
         @Html.HiddenFor(m => m[i].Value)
      </li>
   }
</ul>
Run Code Online (Sandbox Code Playgroud)

这个想法是每个SelectListItem由循环呈现的Html表示.

该过程的第一部分似乎正常工作,表单按预期显示,您可以更新"名称"文本框并选中/取消选中复选框.

问题是,当表单回发到控制器时,永远不会填充Roles集合.

我是MVC的新手,并认为框架实际上通过强制表单元素命名约定从帖子重新构建了模型数据.我显然错过了一个重点,我希望有人可以指出我正确的方向.

谢谢,并为长篇大论道歉.

Dar*_*rov 5

以下是您可以继续的方式:

@model MyProject.WebUI.Models.RolesModel
@using (Html.BeginForm())
{
   <p>
      @Html.LabelFor(m => m.Name)
      @Html.EditorFor(m => m.Name)
   </p>                              
   <div>
      <ul>
          @Html.EditorFor(m => m.Roles)
      </ul>
   </div>                              
   <p>
      <input type="submit" value="Save" />
   </p>
}
Run Code Online (Sandbox Code Playgroud)

并在EditorTemplate(/Views/Shared/EditorTemplates/SelectListItem.cshtml)内:

@model System.Web.Mvc.SelectListItem
<h3>Type: @Html.LabelFor(m => m)</h3>
<li>
    @Html.CheckBoxFor(m => m.Selected)
    @Html.LabelFor(m => m.Selected, Model.Text)
    @Html.HiddenFor(m => m.Value)
</li>
Run Code Online (Sandbox Code Playgroud)

请注意编辑器模板的简化.它不再需要一个List<SelectListItem>模型,而只需一个SelectListItem.它将自动为Roles集合的每个元素调用,这样您就不需要编写任何循环.只需按照惯例.

我也会像这样简化你的视图模型:

public class RolesModel
{
    public string Name { get; set; }
    public IEnumerable<SelectListItem> Roles { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

和你的控制器:

public class TestController : Controller
{
    public ActionResult Edit()
    {
        var myModel = new RolesModel
        {
            Name = "Joe Bloggs",
            Roles = new[]
            {
                new SelectListItem { Value = "1", Text = "Member", Selected = true },
                new SelectListItem { Value = "2", Text = "Manager", Selected = true },
                new SelectListItem { Value = "3", Text = "Administrator", Selected = false }
            }
        };
        return View(myModel);
    }

    [HttpPost]
    public ActionResult Edit(RolesModel m)
    {
        // m.Roles should be correctly bound
        return View("Results", m);
    }
}
Run Code Online (Sandbox Code Playgroud)