Коллекция сложных дочерних объектов в приложении Asp.Net MVC 3? - PullRequest
6 голосов
/ 21 февраля 2011

Я хочу иметь возможность обновлять модель и все ее коллекции дочерних объектов в одном представлении. Я был упомянут к этим примерам: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx и http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/.

Например, у меня есть консультант объекта, у которого есть коллекция "WorkExperiences". Все это в модели Entity Framework. В представлении, простые свойства объекта Консультанта не проблема, но коллекция, я не могу получить текстовое поле для поиска. Я попытался следовать примеру в ссылках выше, но это не работает. Проблема в том, что в этих примерах модель представляет собой просто список (а не объект со свойством дочернего списка). Кроме того, модель снова является моделью EF. И по какой-то причине это не работает, как в этих примерах.

Просто, чтобы сделать это проще, я попытался сделать что-то похожее на пример Фила Хаака, и просто заставил View показать текстовое поле:

@for (int i = 0; i < Model.WorkExperiences.Count; i++)
{
    Html.TextBoxFor(m => m.WorkExperiences[i].Name);
}

Я попытался создать новый объект WorkExperience в контроллере для ViewModel:

    public ActionResult Create(int id)
    {
        Consultant consultant = _repository.GetConsultant(id);
        DetailsViewModel vm = new DetailsViewModel();
        vm.WorkExperiences = consultant.WorkExperiences.ToList();
        vm.WorkExperiences.Add(new WorkExperience());           
        return View(vm);
    }

Но в представлении не отображается пустое текстовое поле для свойства WorkExperience Name. Если, с другой стороны, я создаю отдельный View только для добавления нового объекта WorkExperience, передавая новый пустой объект WorkExperience в качестве модели, это прекрасно работает:

@Html.EditorFor(model => model.Name)

Это дает мне пустое текстовое поле, и я могу сохранить новый объект. Но почему я не могу сделать это в том же виде, что и объект «Консультант», с коллекциями в соответствии с примерами по ссылкам выше?

Кстати, это своего рода дополнительный вопрос к предыдущему, который указал мне на приведенные выше ссылки, но я так и не нашел окончательного решения для него. См. Этот вопрос, если требуется дополнительная информация: Создать представления для свойств объекта в модели в приложении MVC 3?

UPDATE:

Согласно ответам и комментариям ниже, вот обновление с представлением и шаблоном Editor:

Вид:

@model Consultants.ViewModels.DetailsViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id })
</p>
<table>
    <tr>
        <th></th>
        <th>
            Name
        </th>

    </tr>

@foreach (var item in Model.WorkExperiences) {
    <tr>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
            @Html.ActionLink("Details", "Details", new { id = item.Id }) |
            @Html.ActionLink("Delete", "Delete", new { id = item.Id })
        </td>
        <td>
            @item.Name
        </td>

    </tr>

}

</table>

@for (int i = 0; i < Model. WorkExperiences.Count; i++)
{
    Html.EditorFor(m => m. WorkExperiences[i]);
}

(Пожалуйста, обратите внимание, что все это не совсем так, как я буду проектировать в конце, все, что мне нужно сейчас - это заставить объект WorkExperience отображаться в виде пустого текстового поля для заполнения и иметь возможность добавьте и удалите такие текстовые поля, как в примерах Фила Хаака и Стивена Сандерсона.)

Шаблон Editor:

@model Consultants.Models.WorkExperience


@Html.TextBoxFor(m => m.Name);

Этот материал с EditorTemplate прекрасно работает в примере проекта Фила Хаака, который я скачал, чтобы попробовать, но здесь, с моделью EF или какой-то другой проблемой, я не получаю никакого текстового поля вообще. Таблица в представлении служит тестом, потому что в таблице я получаю строки для WorkExperiences, независимо от того, добавляю ли я пустой объект WorkExperience или заполняю его свойства, строки отображаются для каждого объекта. Но опять же, нет текстового поля ...

Ответы [ 2 ]

12 голосов
/ 21 февраля 2011

Например, у меня есть консультант объекта, у которого есть коллекция "WorkExperiences".Все это в модели Entity Framework.

Это первое, что вы должны улучшить: представьте модели представления и не используйте ваши доменные модели в представлении.

При этомдавайте перейдем к шаблонам.Таким образом, вы можете полностью исключить необходимость писать циклы в ваших представлениях.

Итак, вот как может выглядеть ваше представление:

@model Consultants.ViewModels.DetailsViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Add work experience", "CreateWorkExperience", new { id = ViewBag.Consultant.Id })
</p>
<table>
    <tr>
        <th></th>
        <th>
            Name
        </th>
    </tr>
    @Html.DisplayFor(x => x.WorkExperiences)
</table>

@Html.EditorFor(x.WorkExperiences)

Итак, как вы можете, мы используем шаблон отображения ишаблон редактора.Давайте определим их сейчас.

Показать шаблон (~/Views/Shared/DisplayTemplates/WorkExperience.cshtml):

@model AppName.Models.WorkExperience
<tr>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
        @Html.ActionLink("Details", "Details", new { id = Model.Id }) |
        @Html.ActionLink("Delete", "Delete", new { id = Model.Id })
    </td>
    <td>
        @Model.Name
    </td>
</tr>

Шаблон редактора (~/Views/Shared/EditorTemplates/WorkExperience.cshtml):

@model AppName.Models.WorkExperience
@Html.TextBoxFor(x => x.SomePropertyOfTheWorkExperienceModelYouWantToEdit)
...

Что здесь важносоглашение об именах.Имя шаблона должно быть именем типа элемента в коллекции.Так, например, если в вашей модели представления у вас есть свойство

public IEnumerable<Foo> { get; set; }

, соответствующий шаблон должен называться Foo.cshtml и должен находиться в ~/Views/Shared/DisplayTemplates или ~/Views/Shared/EditorTemplates в зависимости от его роли.

Итак, как вы можете видеть, мы избавились от неприятных петель.Теперь не только то, что представления выглядят чистыми, но и вы получаете правильные имена для полей ввода, чтобы вы могли связать значения обратно в действии post.

0 голосов
/ 21 февраля 2011

Самый простой способ сделать это, вероятно, создать класс WorkExperienceList, который наследует List<WorkExperience> (или List<string>, если это так), а затем создать собственный шаблон для вашего WorkExperienceList.Таким образом, вы упростите код представления до @Html.EditorFor(Model), а ASP.NET MVC позаботится обо всем остальном за вас.

...