Та информация, которая остается неизменной от страницы к странице, должна идти в файлы макета, или Layout. Если посмотреть на мой сайт Flenov.info, то это будет шапка (включая большую страницу наверху), рекламу и конечно подвал.
Файл шаблона – это такой же cshtml файл, как и уже знакомые нам. Для него обычно используют имя _Layout.cshtml. Символ подчеркивания указывает на то, что это специальный файл, который не вызывался в контроллере, и не является результатом работы какого-то кода.
Остальные страницы могут отображаться внутри основного шаблона. Следующее изображение показывает мой сайт blo.moe, который использует классическую разметку. Красным прямоугольником выделен блок страницы, который приходит из конкретной страницы View, а все остальное – это макет, хотя правая часть приходит на страницу из подключаемого файла.
Итак, с именем файла мы уже определились, а теперь нужно определиться с расположением. В главе 2.5. Представления мы знакомились с представлениями и тогда в случае неверного указания файла в тексте ошибки были пути, по которым фреймворк ищет эти файлы представлений. И имена папок были – такая же, как имя контроллера и Shared. Вторая – это как раз папка, в которой хранятся файлы, к которым можно получить доступ из любого места. Это как раз то, что нам нужно и именно здесь нужно создать файл макета.
Сейчас в нашем проекте нет такой папки, поэтому ее нужно создать. Кликаем правой кнопкой по View и выбираем Add -> New Folder.
Создав папку, внутри создаем файл макета, кликая правой кнопкой по папке Shared и выбираем File -> New File. Тут снова можно выбрать совершенно любое тип файла и указать в качестве имени _Layout.cshtml, а можно выбрать уже заранее подготовленный шаблон, который просто наполнит файл базовым смыслом. Имя шаблона MVC View Layout Page:
Майкрософт иногда меняет шаблоны, поэтому вы можете увидеть и другой результат, но в моем случае получился такой код:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div> @RenderBody() </div> </body> </html>
Расширение файла cshtml снова указывает на то, что это смесь CS и HTML файла и здесь мы можем писать абсолютно все то же самое. Просто модели как таковой нет. Здесь уже есть два вызова CS кода.
@RenderBody() – в этом месте будет отображено содержимое View, которое мы вызовем из контроллера. То есть если мы скажем, что представление rezortest/index.cshtml должно использовать этот макет, то содержимое index.cshtml будет размещено как раз в месте вызова RenderBody()
@ViewBag.Title – указывает на то, что мы хотим отобразить свойство Title от ViewBag. Мы с ViewBag еще не знакомились, поэтому я хотел бы представить вас этому прекрасному динамической структуре данных - dynamic. Она динамическая, потому что для создания нового поля достаточно просто написать его имя и присвоить значение, например, мы можем создать поле Test:
ViewBag.Test = "Это строка";
ViewBag доступен как из контроллеров, так и из View и может использоваться как раз для того, чтобы передавать информацию из контроллеров в представления.
Стопарики – скажет злопамятный алкоголик. Я же утверждал, что для передачи информации из контроллера в представления нужно использовать классы-модели. Да, именно так. Если вам нужно передать информацию, ваши помыслы должны быть в первую очередь направлены именно на модель. Только в крайних случаях, когда другого выхода нет, можно использовать ViewBag и заголовок – это как раз может быть таким случаем, потому что в макете у нас нет модели.
Есть еще один способ, но о нем мы пока говорить не будем, а раз уж VS подкинул нам такую подлянку и включил ViewBag в макет, с ним пришлось познакомится.
Я не могу сказать, что в использовании ViewBag есть что-то криминальное. Нет, его можно использовать, но лучше все же стараться обходить его стороной по мере возможности. На мой взгляд тогда код будет даже чище.
В некоторых других фреймворках в качестве модели можно передать более одного параметра, например, так работает популярный Symfony для PHP. Тут у нас такой гибкости нет, только одна модель и практически глобальная динамическая фигня в виде ViewBag.
Вернемся к нашему шаблону. Чтобы он был более наглядным, я добавил к нему заголовок и подвал:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> </head> <body> <div style="background:#eee; font-size:200%; padding:30px"> Logo </div> <div> @RenderBody() </div> <div style="background:#eee; padding:30px"> Copyright: www.flenov.info </div> </body> </html>
Я знаю, устанавливать стили через атрибут style для каждого элемента в отдельности не очень эффективно, но это всего лишь пример и мы пока не будем усложнять жизнь отдельным CSS файлом, а все в одном месте, чтобы вы могли тут же видеть, что я изменил. В реальных приложениях конечно же стили будут отдельно, HTML отдельно, котлеты в холодильнике.
Теперь открываем файл Views/razortest/Index.cshtml и в нем убираем тэги типа html, body и все техническое, а оставляем только самое необходимое, что мы хотим отобразить в теле страницы внутри макета. А в самом начале добавляем такой код:
@{ ViewBag.Title = "This is my index page"; Layout = "~/Views/Shared/_Layout.cshtml"; }
В первой строке мы устанавливаем заголовок страницы, присваивая строковое значение свойству ViewBag.Title. Как мы уже выяснили, макет потом сможет прочитать эту строку.
Во второй строке устанавливается файл макета. У вас на сайте может использоваться несколько различных макетов – один для основных страниц, другой для админки, третий для какого-то специфичного раздела и т.д. Пока мы установим макет прямо в файле Index.cshtml, но чуть позже познакомимся с тем, как указать, какой макет использовать по умолчанию и тогда эта строка станет ненужной.
Итак, файл Index.cshtml должен выглядеть так:
@model MyWebSite.Model.Person @{ ViewBag.Title = "This is my index page"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h1>Hello</h1> <p>First Name: @("Mr. " + Model.FirstName.ToUpper())</p> <p>Last Name: @Model.LastName</p> <p>Age: @(Model.Age * 2)</p> <p>Число: @(Int32.Parse("4"))</p> <p> @if (Model.Age < 15) { <p>Классно быть молодым, но сайт только для старше 15</p> } else { <p> отлично </p> int index = 10; <p> index = @index</p> } </p>
Если запустить этот пример, то в результате в браузере мы должны увидеть эту страницу:
Лого и футер пришли к нам из макета, а центральная часть уникальна для этой страницы.
Теперь можно обновить все представления, чтобы они использовали этот шаблон и получить преимущество от того, что весь однородный код находится только в одном месте. Стоит поменять файл макета и изменения будут тут же видны на всех страницах, которые используют этот макет.