Перевод серии статей посвящённых шаблонам отображения и редактирования. Одно из главных новых нововведений в ASP.NET MVC — это шаблоны.
 Шаблоны подобны динамическим данным (Dynamic Data) в классическом ASP.NET. По существующему объекту данного типа, система автоматически генерирует разметку для его отображения или редактирования, вне зависимости от того представляет ли собой объект простые данные (integer, decimal, string и т.п.), или же является представителем класса.
 Для того чтобы отобразить элемент, используется три метода отображения (каждый из которых имеет по несколько перегрузок):
 1-ый метод, может использоваться для показа данных как из ViewData, так и из модели, тип которой вы можете и не знать.
 Следующий метод используется в основном для передачи данных из модели. Кроме того, этот метод можно использовать, например, полностью игнорируя значения исходных данных (model => someOtherValue).
 И последний метод является хелпером, для текущей модели. Метод DisplayForModel эквивалентен записи DisplayFor(model => model).
 Начнём примеры с модели:
 … затем action:
 … и наконец View:
 В результате получим такую страничку:
 Подобно Html.Display, также три метода, которые используются для генерации html для редактирования объекта:
 Если я поменяю в своём View метод DisplayForModel на EditorForModel, то страница будет выглядеть так:
 Как видите, система сгенерировала текстбоксы для строк и для целых значений.
 Система шаблонов в MVC 2 содержит несколько встроенных шаблонов.
 Для того чтобы отобразить объект, система использует рефлексию для поиска всех свойств объекта, затем генерирует разметку для каждого из свойств.
 Если вы не будете использовать шаблоны, то разметка может выглядеть примерно так:
 Стоит иметь в виду, что сейчас это ещё не законченная реализация. Я расскажу чего здесь не хватает позже.
 Это основа шаблона для отображения сложного объекта: пройтись по всем свойствам текущей модели, для каждой из них показать лэйбл и вызвать метод Html.Display() для отображения значения свойства.
 Что происходит когда мы хотим показать строку? А происходит приблизительно следующее:
 И снова, это не реальный код, То что происходит на самом деле, обсуждается позже.
 Существует множество достоинств встроенных шаблонов, но пожалуй самое важное, это возможность подменить их в любом месте рендеринга.
 Давайте рассмотрим пример подмены шаблона для строк. Для этого создадим partial view, который назовём String и расположим в папке ~/Views/ControllerName/DisplayTemplates:
 В файле напишем: Обновив страницу мы увидим:
 Как видите, новый шаблон был подставлен автоматически и нам не понадобилось просматривать все наши строки. Однако, шаблон применился и к свойству Age, тип которого на самом деле является целым, но об это поговорим чуть позже.
 Если нам понадобится написать шаблон для редактирования, то его необходимо разместить в папке EditorTemplates.
 Один из новых классов, появившийся вместе с ASP.NET MVC 2 — это Model Metadata. Этот класс разработан для того, чтобы сообщить вам необходимую информацию об объекте для его отображения. И хотя в основном это используется для написания шаблонов, метаданные доступны всегда, не только в шаблонах.
 В контексте использования ModelMetadata, определение понятия «Model» немного расплывается.
 Рассмотрим опять же модель из предыдущей части:
 Мы создали строго-типизированное представление для этой модели. Если в этом представлении вы обратитесь к ViewData.ModelMetadata, то модель в этом случае будет объект класса Contact.
 Однако, с помощью объекта метаданных вы можете получить информацию обо всех свойствах объекта. Вы можете получить коллекцию объектов ModelMetadata для каждого из свойств. В контексте нашего примера, мы получим 3 новых метаобъекта, для FirstName, LastName и Age. Если вы посмотрите на метаданные для свойства FirstName, вы увидите что тип данных модели string, а тип объекта-контейнера — Contact. Таким образом вы можете рекурсивно перебрать все свойства сложного объекта.
 Используя текущую модель.
 Самый простой способ получить доступ к метаданным — это использовать свойство ViewData. В этом случае ModelMetadata описывает модель, представленную в ViewData. В случае рендеринга шаблона для объекта, этот способ является самым простым.
 Получить одно из свойств метаданных, которые у вас уже есть.
 Если у вас уже есть объект метаданных, вы можете использовать свойство Properties, которое возвращает список объектов ModelMetadata для каждого свойства. 
 Используя выражения
 Класс ModelMetadata имеет два статических метода: FromStringExpression и FromLambdaExpression. Эти методы используются когда мы хотим получить из выражения (к примеру «PropertyName» или «m => m.PropertyName») соответствующие метаданные. Большинство существующих HTML хелперов уже переписаны в рамках этих двух методов.
 Перед тем как говорить от том как работать с ModelMetadata, давайте посмотрим какую информацию предоставляет объект класса ModelMetadata.
 Свойства относящиеся к модели и её контейнеру:
 Метаданные модели
 Методы Значение по умолчанию для SimpleDisplayText следует следующим правилам: Мы добавили настраиваемую систему метаданных в ASP.NET MVC 2. По умолчанию, мета-объекты формируются на основе данных, полученных из атрибутов.
 Следующие атрибуты используются для формирования модели метаданных:
 Перед тем как поговорить о встроенных шаблонах, потратим несколько минут на объяснение того, как шаблоны используются в работе, как напрямую перекрыть шаблон.
 Когда решено какой шаблон использовать, система просматривает несколько путей. По каждому из них, ищет ascx-файл с именем «DisplayNames/TemplateName» или «EditorName/TemplateName», в зависимости от того какой результат вы хотите.
 Поиск происходит в следующем порядке:
 (Замените DisplayTemplates на EditorTemplates для шаблонов редактирования.)
 Имена шаблонов ищутся в следующем порядке: Когда происходит поиск по имени типа, то имеется в виду простое имя (например Type.Name), без пространства имён. Кроме того, если тип является Nullable<T>, поиск выполняется для типа T (то есть шаблон Boolean будет использоваться как для «bool», так и для «Nullable<bool>»). То есть если вы пишете шаблон для value-типа, вам необходимо учитывать, будет ли тип nullable. Ниже рассматривается пример со встроенным шаблоном для типа Boolean.
 И последнее о чем стоит сказать перед тем, как углубиться в реализацию, это класс TemplateInfo. TemplateInfo не всегда доступен из ViewData, в отличии от метаданных модели, только в момент когда вы находитесь в шаблоне.
 Основное свойство, используемое в TemplateInfo — это FormattedModelValue. Значением этого поля является либо корректно отформатированное значение модели, в виде строки (на основе формата указанного в ModelMetadata), либо оригинальное значение модели (если не указан формат строки).
 Есть ещё несколько вещей, которые мы тоже будем использовать (например свойство TemplateDepth и метод Visited). Но смысл их я объясню по мере знакомства с ними.
 Всего существует 9 имён шаблонов, которые используются системой для отображения данных: «Boolean», «Decimal», «EmailAddress», «HiddenInput», «Html», «Object», «String», «Text» и «Url». Два из них («Text» и «String») реализованы одинаково. У некоторых из них есть соответствующие аналоги для шаблонов редактирования, у некоторых — нет.
 Встроенные шаблоны в ASP.NET MVC реализованы в коде, но для примера я переписал их функциональность в .ascx файлах. Это поможет вам лучше разобраться с ними, и вам будет проще написать свою версию любого из этих шаблонов. 
 Никаких сюрпризов: просто отображаем модель, заменив в ней специальные символы html.
 Этот шаблон даже немного проще предыдущего, потому что тип «Html» подразумевает, что содержимое будет в виде html и поэтому не должно быть кодировано. Будьте аккуратны при использовании этого типа если данные получены от конечного пользователя, во избежание XSS-атак!
 Этот шаблон предполагает, что ваша модель является адресом электронной почты, и автоматически создаёт ссылку на неё. Обратите внимание, что модель используется для адреса электронной почты, а FormattedModelValue для отображения.
 Работает подобно предыдущему примеру.
 Этот шаблон используется в паре с атрибутом [HiddenInput] (описанный выше). Он будет генерировать отображаемое значение только если пользователь явно не указал свойство HideSurroundHtml.
 Этот шаблон отображает значение типа decimal, с двумя знаками после запятой, поскольку этот тип в основном используется для денежных представлений. Обратите внимание на условие такого форматирования.
 Шаблон для Boolean интересен тем, что в нём необходимо генерировать разметку в зависимости от того является ли тип nullable, или нет. Для non-nullable используется обычный чекбокс, в противном случае отображается выпадающий список с тремя значениями.
 Стоит объяснить логику работы этого шаблона, прежде чем мы рассмотрим код, поскольку очень много работы проделывается от вашего имени.
 Главная цель шаблон для типа object это всех свойств сложного объекта, вместе с html-разметкой для каждого. Кроме того, он ответственный за отображение значения модели NullDisplayText, если значение её null. И обеспечивает, так называемое «мелкое погружение» (shallow dive), отображая только нужный уровень свойств. Позднее мы поговорим о настройке этого шаблона, включая подготовку операции «глубокое погружение» (deep dive).
 Давайте рассмотрим этот пример более детально.
 В этом месте всё понятно, выводится NullDisplayText, в случае если модель равна null.
 В этом месте мы ограничиваем уровень вложенности свойств («мелкое погружение», shallow dive). Класс TemplateInfo отслеживает глубину вложенности шаблонов. Для верхнего уровня свойство TemplateDepth равно 1.
 Это основной цикл прохода по свойствам объекта. Свойства, которым указано что они не должны отображаться, игнорируются. Другая часть фильтра свойств, спрашивает у TemplateInfo рендерился ли этот объект ранее, для того чтобы предотвратить бесконечную рекурсию.
 Если это свойство установлено в true, то шаблон просто просит свойство отобразиться, без лишней html-разметки.
 В этом месте проверяется есть ли отображаемое имя у свойства и, если оно есть, оно выводится, обрамляемое div-ом. Затем запускается рендеринг для свойства.
 Шаблоны редактирования немного сложнее, чем шаблоны отображения, поскольку они включают возможность редактирования значений. Они строятся на основе существующих HTML-хелперов. Всего существует 7 шаблонов редактирования: «Boolean», «Decimal», «HiddenInput», «MultilineText», «Object», «Password» и «String».
 Часто, в качестве имени элемента в html-хелперы будут передаваться пустые строки. Обычно это неправильно, но в случае с шаблонами у нас есть «контекст» свойства. С помощью этого нам проще работать со сложными объектами, поскольку мы можем сохранить иерархию вложенности свойств (например «Contact.HomeAddress.City»).
 Когда вы передаёте имя в html-хелпер, вы как бы говорите «дай мне текстбокс для редактирования свойства объекта, которого зовут „City“. Но что случится если ваш шаблон не для адреса, как сложного объекта, а для города, как для строки? Если вы передаёте пустую строку, в качестве имени, то вы говорите html-хелперу „дай мне текстбокс, чтобы отредактировать себя“.
 И снова начнём со строки, поскольку это простейший для понимания шаблон. Этот шаблон говорит системе, что хочет получить текстбокс (для редактирования себя), и мы инициируем его форматированным значением редактируемого свойства. Дополнительно, для этого текстбокса мы хотим использовать два класса CSS „text-box“ и „single-line“.
 Шаблон для ввода пароля похож на шаблон для строки, за исключением того, что мы вызываем метод хелпера Password и используем ещё один класс CSS (»password").
 И снова без всяких сюрпризов. Вызываем метод TextArea, указываем количество строк и колонок равное 0 (поскольку мы используем CSS), и вместо класса «single-line» используем класс «multi-line».
 Как видите, намного сложнее, чем в шаблоне для отображения. Свойство ModelValue определяет является ли модель массивом байт или бинарным linq2sql объектом, и конвертирует их в строку с помощью base64. Затем записывает результат в hidden-поле.
 Шаблон для Decimal похож на соответствующий шаблон для отображения, за исключением того, что генерируется текстбокс для редактирования.
 Этот шаблон тоже похож на соответствующий шаблон для отображения.
 Точно также этот шаблон практически не изменился, только добавился вызов метода ValidationMessage.
 Для дальнейших примеров будут использоваться следующие модель, контроллер и представление:
 Если мы запустим приложение с шаблонами по умолчанию, то мы увидим такую страницу:
 Страница для редактирования будет выглядеть так:
 Давайте сделаем нашу разметку в виде таблицы, чтобы пара имя/значение отображалась в одной строке. Обратите внимание, что в шаблоне для редактирования выводятся звёздочки для обязательных полей.
 В итоге получаем следующий вид:
 Таким образом мы сделали такую разметку:
 На скриншоте выше, ChildModel отображается как (null value), потому что мы установили это значение с помощью атрибута в коде.
 Обратите внимание, что даже в режиме редактирования, мы не можем изменить это свойство.
 Если мы изменим шаблон редактирования, удалив в нём первое условие «if», то получим следующее:
 А в режиме просмотра:
 Поскольку мы не изменили шаблон для отображения, мы всё ещё получаем результат с логикой «мелкого погружения» (shallow dive). Полное имя показывается потому что мы используем для модели атрибут [DisplayColumn], с помощью которого указали что отображать надо свойство FullName.
 Если мы изменим шаблон отображения для использования «глубокого погружения» (deep dive), то получим следующее:
 Первое что нам необходимо сделать, это определить MasterPage, который будет использоваться по шаблону. Один для шаблона редактирования и один для шаблона отображения.
 Суть поведения этой страницы заключается в определении двух ContentPlaceHolder-ов, называемыми «Label» и «Data». Контент «Label» должен отображать имя свойства, а «Data», соответственно, значение.
 Этот шаблон использует одну особенность веб-форм. В методе OnInit реорганизует страницу, в зависимости от того хотите ли вы использовать для модели обрамляющую html-разметку, или нет.
 Версия шаблона для редактирования отличается только тем, что есть третий placeholder, предназначенный для сообщений валидаторов и для отмечаются обязательные поля.
 В простых типах для использования мастер-шаблонов используется серверный тег <asp:Content ...>
 Шаблон для сложного типа стал намного проще, потому что мы вынесли общую разметку в мастер-шаблон. Остаётся только логика.
 Обратите внимание, что эти шаблоны не используют MasterPage, потому что в них нет разметки, а только логика. Разметка генерируется при вызове шаблонов для простых типов.
 ASP.NET MVC 2 находится ещё в стадии бета-тестирования и кое-что может измениться к релизу. Но основные моменты останутся именно такими как и описано, и освоив это материал, вы окажетесь более подготовлены к выходу финальной версии.