(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Создание форм для глубоко вложенных View Model в ASP.NET MVC

Jimmy Bogard

Ёще один интересный пост от Jimmy Bogard, посвященный cозданию форм для глубоко вложенных View Model в ASP.NET MVC. Несмотря на то, что в нём постоянно идёт отсылка к ASP.NET MVC 2, информация актуальна и для 3-ей версии.

 ASP.NET MVC 2 представил множество строго типизированных помощников (helpers) для создания элементов форм в строго типизированных представлениях (views). Эти строго типизированные помощники используют лямбда выражения (lambda expressions) для того, чтобы создать полностью готовый элемент ввода, включая корректное имя и значение для элемента.

 Лямбда выражения достаточно выразительны. Они позволяют создавать вам достаточно сложные модели для редактирования и иметь привязку модели (model binding) для того, чтобы сложить всё вместе. Пример сложного типа view model:

public class ProductEditModel

{

  public string Name { get; set; }

  public PriceEditModel Price { get; set; }

 

  public class PriceEditModel

  {

    public decimal Value { get; set; }

    public string Currency { get; set; }

  }

}

 

* This source code was highlighted with Source Code Highlighter.

 Достаточно легко создать для него представление:
@using (Html.BeginForm()) {

  <p>

    @Html.LabelFor(m => m.Name)

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

  </p>

  <p>

    @Html.LabelFor(m => m.Price.Currency)

    @Html.TextBoxFor(m => m.Price.Currency)

  </p>

  <p>

    @Html.LabelFor(m => m.Price.Value)

    @Html.TextBoxFor(m => m.Price.Value)

  </p>

}

 

* This source code was highlighted with Source Code Highlighter.

 До тех пор, пока мы используем выражения, строящиеся с самого верхнего уровня модели, чтобы создать элементы ввода, корректный HMTL будет получен. Предположим, что вы хотите сейчас вытащить PriceEditModel в частичное представление и отделить его от родительского представления. Мы меняем в нашем представлении рендеринг свойства на рендеринг частичного представления:

@using (Html.BeginForm()) {

  <p>

    @Html.LabelFor(m => m.Name)

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

  </p>

  @Html.Partial("_PriceEditModel", Model.Price);

}

* This source code was highlighted with Source Code Highlighter.

 Наше частичное представление представляет собой просто вырезанный код представления, за исключением того, что сейчас оно основано на типе PriceEditModel:
@model ProductEditModel.PriceEditModel

<p>

  @Html.LabelFor(m => m.Currency)

  @Html.TextBoxFor(m => m.Currency)

</p>

<p>

  @Html.LabelFor(m => m.Value)

  @Html.TextBoxFor(m => m.Value)

</p>

* This source code was highlighted with Source Code Highlighter.

 Однако, получающийся в результате HTML больше не сопоставляет члены модели корректно. Несмотря на то, что на экране всё в порядке:

 
Но стоит нам заглянуть в HTML, как мы увидим ошибку:
 
 
Вместо имени нашего члена, имеющего правильный родительский член в своём имени, вроде "Price.Currency", мы видим только "Currency". Действительно, когда мы попадаем в POST действие (action), член Price равен null, т.к. привязка модели не смогла найти соответствие:
 
 

Не совсем то, что нам хотелось бы получить!

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

 Не очень привлекательный вариант!

 У нас есть вариант получше - шаблонизированные помощники из MVC 2. Шаблонизированные помощники элегантно решают проблему глубоко вложенных View Model.

Работа с шаблонизированными помощниками

Шаблонизированные помощники отличаются от частичных представлений тем, что в них специальная контекстная информация передаётся вниз от родителя к потомку тогда, когда мы используем методы Html.EditorXyz() из HtmlHelper. Для того чтобы перестроить наши представления на использование шаблонизированных помощников, давайте просто создадим шаблон редактора для каждой view model, которая у нас есть:

Эти шаблоны обычные частичные представления из Razor, за исключением того, что они помещаются в специальную папку EditorTemplates. Для нашего частичного представления c ProductEditModel, мы просто перемещаем всё, что у нас было в нашем представлении:

@model ProductEditModel

 

<p>

  @Html.LabelFor(m => m.Name)

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

</p>

@Html.EditorFor(m => m.Price)

 

* This source code was highlighted with Source Code Highlighter.

 Однако, здесь есть одна незначительная деталь. Вместо рендеринга частичного представления Price, мы выполняем рендеринг редактор для члена Price. Шаблон PriceEditModel - это то, что у нас было в нашем оригинальном частичном представлении без каких-либо изменений:

@model ProductEditModel.PriceEditModel

<p>

  @Html.LabelFor(m => m.Currency)

  @Html.TextBoxFor(m => m.Currency)

</p>

<p>

  @Html.LabelFor(m => m.Value)

  @Html.TextBoxFor(m => m.Value)

</p>

 

* This source code was highlighted with Source Code Highlighter.

 На данный момент отличие заключается в том, что наш шаблонизированный помощник знает, что родительская модель использовала член "Price" для создания частичного представления. В нашем родительском представлении Edit всё ещё проще:

@using (Html.BeginForm()) {

  @Html.EditorForModel()

  <input type="submit" />

}

 

* This source code was highlighted with Source Code Highlighter.

 ASP.NET MVC будет проверять тип модели для того, чтобы убедиться в том, что шаблон редактора существует для этого типа модели, когда мы вызываем метод EditorForModel. Т.к. мы создаём шаблоны редактора для каждого отдельного типа модели, не имеет значения, где в иерархии расположены эти вложенные типы. ASP.NET MVC будет передавать родительский контекст, так что глубоко вложенные View Model будут иметь корректную информацию о нём.

 Просмотрев получившийся в результате HTML, мы можем убедиться, что всё в порядке:

Имя элемента ввода сейчас имеет корректное имя родительского свойства в качестве значения. А отладка POST действия подтверждает, что привязка модели сейчас работает корректно:

С шаблонизированными помощниками из ASP.NET MVC 2, мы можем создавать вложенные модели в наших представлениях и, вместе с тем, получать все преимущества частичных представлений. Единственное предостережение - убедитесь, что вы создали представления, используя шаблонизированные помощники и Html.EditorXyz методы. В противном случае, воздействие на ваши представления будет минимальным.

 И просто чтобы пожаловаться - этот способ сильно раздражает в MVC 1.0. Я выкинул кучу кода после того, как перешёл на старшие версии MVC!

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 01.11.2011 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft 365 Business Standard (corporate)
Microsoft 365 Apps for business (corporate)
Microsoft Windows Professional 10, Электронный ключ
Microsoft Office для дома и учебы 2019 (лицензия ESD)
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Мастерская программиста
Проект mic-hard - все об XP - новости, статьи, советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100