MVC - проблема с привязкой данных к коллекции с использованием пользовательского шаблона - PullRequest
1 голос
/ 01 марта 2011

Я пытаюсь привязать модель, которая имеет свойство коллекции, в частности список.Для целей этого примера это представляет список ролей пользователя:

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

Я связываю это со строго типизированным представлением через следующий Контроллер:

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

Это тогдавызывает следующее представление:

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

Обратите внимание на специфичный для шаблона вызов для моего пользовательского шаблона редактора в '/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>

Идея состоит в том, что каждый SelectListItem представлен HTML-кодом, отображаемым в цикле.

Первая часть процесса работает правильно, форма представлена ​​в ожидаемом виде, и вы можете обновить текстовое поле «Имя».и установите / снимите флажки.

Проблема в том, что когда форма отправляется обратно на контроллер, коллекция ролей никогда не заполняется.

Я новичок в MVC и подумал, чтофреймворк фактически перестроил данные модели из поста с помощью обязательного соглашения об именовании элементов формы.Я, очевидно, упускаю важный момент, и я надеюсь, что кто-то может указать мне правильное направление.

Спасибо, и приношу извинения за длинный пост.

1 Ответ

5 голосов
/ 01 марта 2011

Вот как можно продолжить:

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

и внутри шаблона 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>

Обратите внимание на упрощение шаблона редактора.Он больше не принимает List<SelectListItem> в качестве модели, а просто SelectListItem.Он будет автоматически вызываться для каждого элемента коллекции ролей, поэтому вам не нужно писать какие-либо циклы.Просто следуйте соглашениям.

Я также упростил бы вашу модель представления следующим образом:

public class RolesModel
{
    public string Name { get; set; }
    public IEnumerable<SelectListItem> Roles { get; set; }
}

и ваш контроллер:

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...