Asp.Net MVC3 Razor - список дочерних элементов, не отправляемых обратно из редактора - PullRequest
4 голосов
/ 18 января 2012

Я пытаюсь создать многоуровневый редактор в MVC3.Под многоуровневым я имею в виду, что я хотел бы иметь возможность редактировать данные для трех уровней иерархии (родительский объект, дочерний объект родителя и коллекция дочерних объектов).Моя модель выглядит примерно так:

namespace MvcApplication1.Models
{
    public class Parent
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Child Child { get; set; }
    }

    public class Child
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public IEnumerable<SubChild> SubChildren { get; set; }    
    }

    public class SubChild
    {
        public int Id { get; set; }
        public string Name { get; set; }
        private DateTime _date = DateTime.Now;
        public DateTime Date { get { return _date; } set { this._date = value; } }
    }
}

Поскольку я хочу отобразить всю иерархию на одном экране, я создал следующую модель представления:

namespace MvcApplication1.Models.ViewModels
{
    public class ParentViewModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public Child Child { get; set; }
        public IEnumerable<SubChild> SubChildren { get { return Child.SubChildren; } set { this.Child.SubChildren = value; } }
    }
}

, а контроллер выглядит так:

    public class ParentController : Controller
    {
        public ActionResult MultiLevelEdit(int id)
        {
            // Simulate data retrieval 
            Parent parent = new Parent { Id = 2 , Name = "P"};
            var child = new Child { Id = 3, Name = "Cild1" };
            List<SubChild> children = new List<SubChild>();
            children.Add(new SubChild { Id = 3, Name = "S1"});
            children.Add(new SubChild { Id = 5, Name = "S 22" });
            child.SubChildren = children;
            parent.Child = child;
            // Create view model
            ParentViewModel vm = new ParentViewModel() { Id = parent.Id, Name = parent.Name, Child = parent.Child, SubChildren = parent.Child.SubChildren };

            return View(vm);
        }

    }

отображаемое представление:

@model MvcApplication1.Models.ViewModels.ParentViewModel

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>

    @Html.HiddenFor(model => model.Id)
    @Html.LabelFor(model => model.Name)
    @Html.EditorFor(model => model.Name)
    <hr />
    Child
    <br />
    @Html.EditorFor(model => model.Child)

    <hr />
    SubChild
    <br />
    @Html.EditorFor(model => model.SubChildren)


    <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

Я создал два шаблона редактора в Views \ Shared \ EditorTemplates:

ChildTemplate.cshtml

@model MvcApplication1.Models.Child

@{
    ViewBag.Title = "Child";
}

<h2>Child</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Child</legend>

        @Html.HiddenFor(model => model.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name, "Child Name")
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    </fieldset>
}

и SubChildTemplate.cshtml

@model MvcApplication1.Models.SubChild

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>SubChild</legend>

        @Html.HiddenFor(model => model.Id)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Date)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Date)
            @Html.ValidationMessageFor(model => model.Date)
        </div>
    </fieldset>
}

Все отображается правильно, однако, когда я пытаюсь сохранить изменения, коллекция SubChildren становится пустой.Я попробовал две подписи метода редактирования:

[HttpPost]
public ActionResult MultiLevelEdit(ParentViewModel parentVM)
{...

[HttpPost]
public ActionResult MultiLevelEdit(ParentViewModel parentVM, FormCollection collection)
{...

и ни в одном из них нет значения.

Кто-нибудь может подсказать, что можно улучшить, чтобы это работало?Заранее большое спасибо.

Ответы [ 2 ]

4 голосов
/ 18 января 2012

Ваши шаблоны не названы правильно.Должно быть:

  • ~/Views/Shared/EditorTemplates/Child.cshtml
  • ~/Views/Shared/EditorTemplates/SubChild.cshtml

Кроме того, я не совсем понимаю цель свойства SubChildren на вашеммодель представления.

Вы можете удалить ее и на главном экране:

@model MvcApplication1.Models.ViewModels.ParentViewModel

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>

    @Html.HiddenFor(model => model.Id)
    @Html.LabelFor(model => model.Name)
    @Html.EditorFor(model => model.Name)
    <hr />
    Child
    <br />
    @Html.EditorFor(model => model.Child)

    <hr />
    SubChild
    <br />
    @Html.EditorFor(model => model.Child.SubChildren)

    <p>
        <input type="submit" value="Save" />
    </p>
    </fieldset>
}

Но ваша самая большая проблема заключается в том, что у вас есть вложенные элементы HTML <form>, которые не разрешены.Это неверный HTML и приводит к неопределенному поведению.Некоторые значения могут быть опубликованы, другие нет, ... Удалите все Html.BeginForm помощники из ваших шаблонов, потому что ваш основной вид уже содержит форму.

1 голос
/ 18 января 2012

См. эту статью для решения.Магия содержится в блоке using (Html.BeginCollectionItem ("...")).

Короче говоря, вы должны использовать правильные имена / префиксы полей при работе со стандартным компоновщиком моделей.

...