Файлы layout или мастер-страницы позволяют определить единый шаблон для страниц Razor и применяются для создания единообразного, унифицированного вида приложения. Для определения интерфейса мастер-страницы также применяют код Razor и html, как обычные страницы razor, но при этом упрощают создание приложения. Например, можно определить на мастер-странице общие для всех остальных страниц Razor меню и другие элементы, а также подключить общие стили и скрипты. В итоге нам не придется на каждой отдельной странице прописывать путь к файлам стилей, а потом при необходимости его изменять.
Например, у нас есть страница Razor Index.cshtml и код связанной модели IndexModel в файле Index.cshtml.cs:
Создадим в папке Pages новый каталог, который назовем Shared. Далее добавим в этот каталог добавим новый файл, который назовем _Layout.cshtml. Для добавления мастер-страниц в Visual Studio можно использовать шаблон файла Razor Layout:
После добавления файла _Layout.cshtml изменим его код следующим образом:
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>METANIT.COM | @ViewBag.Title</title> </head> <body> <h2>@ViewBag.Title</h2> <div><a href="/">Home</a> | <a href="About">About</a></div> <div> @RenderBody() </div> </body> </html>
Код мастер-страницы напоминает полноценную веб-страницу: здесь присутствуют основные теги <html>
, <head>
,
<body>
и так далее. И также здесь могут использоваться конструкции Razor. Например, через выражение
@ViewBag.Title
из каждой отдельной страницы Razor будет передаваться значение для заголовка веб-страницы.
Отличительной особенностью файлов layout является использование метода @RenderBody(). Этот метод будет вставлять содержимое страниц Razor, которые используют данную мастер-страницу. В итоге мы сможем легко установить для всех страниц единообразный стиль оформления.
Теперь определим папке Pages следующую страницу Index.cshtml:
@page @{ ViewBag.Title = "Index"; Layout = "/Pages/Shared/_Layout.cshtml"; } <h3>Index Content</h3>
Здесь задается значение ViewBag.Title
, которое применяется на мастер-странице для вывода заголовка.
Кроме того, с помощью свойства Layout устанавливается используемая мастер-страница layout. В данном случае это файл по пути /Pages/Shared/_Layout.cshtml
Также добавим в папку Pages новую страницу About.cshtml со следующим кодом:
@page @{ ViewBag.Title = "About"; Layout = "/Pages/Shared/_Layout.cshtml"; } <h3>About Content</h3>
Оно выглядит аналогично странице Index.cshtml.
В итоге весь проект будет выглядеть следующим образом:
Запустим проект и в браузере при обращении к обоим страницам Razor мы лицезреем в браузере единообразую веб-страницу:
При необходимости мы можем определять одни и те же или разные мастер-страницы для разных страниц Razor.
Хотя выше приведенный код вполне успешно работает, у нас есть одна проблема - мы сталкиваемся с необходимостью на каждой странице явным образом прописывать, какую мастер-страницу layout будет применять страницы. Чтобы упростить данное действие, можно применять файлы _ViewStart.cshtml
Итак, добавим в папку Pages новый файл, которое назовем _ViewStart.cshtml. Для этого можно использовать элемент Razor View Start:
Код этого файла добавляется в самое начало кода преставлений при их запуске. Определим в файле _ViewStart.cshtml следующий код (в принципе этот же код должен быть в добавляемом файле по умолчанию):
@{ Layout = "_Layout"; }
Когда будет происходить рендеринг страницы Razor, то система будет искать мастер-страницу _Layout по следующим путям:
/Pages/_Layout.cshtml /Pages/Shared/_Layout.cshtml
Если в обеих папках: и в /Pages, и в /Pages/Shared/ имеется файл с одинаковым
именем, например, _Layout.cshtml
, то к странице применяется файл, который находится с ним в одной папке как более приоритетный.
После определения этого файла мы можем удалить из страниц Index.cshtml и About.cshtml подключение мастер-страницы. Например, код страницы Index.cshtml:
@page @{ ViewBag.Title = "Index"; } <h3>Index Content</h3>
Если вдруг мы хотим глобально по всему проекту поменять мастер-страницу на другой файл, который расположен в какой-то другой папке, например, в корне каталога Pages, то нам надо использовать полный путь к файлу в _ViewStart.cshtml:
@{ Layout = "~/Pages/Shared/_Layout.cshtml"; }
Код из _ViewStart.cshtml выполняется до любого кода на странице Razor.
Естественно также мы можем переопределить мастер-страницу на каждой отдельной странице с помощью свойства Layout.
@page @{ ViewBag.Title = "Home Page"; Layout = "~/Pages/Shared/_Layout.cshtml"; } <h2>Страница Index.cshtml</h2>
Мы можем вообще не использовать мастер-страницу, тогда на странице Razor свойству Layout
надо присвоить значение null
:
@page @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Home Page</title> </head> <body> <h2>Страница Index.cshtml</h2> </body> </html>
Кроме метода RenderBody()
, который вставляет освновное содержимое страниц Razor, файлы layout также могут использовать специальный
метод RenderSection()
для вставки секций. Мастер-страница может иметь несколько секций, куда страницы Razor могут поместить свое содержимое.
Например, добавим к мастер-странице _Layout.cshtml секцию с именем "footer":
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>METANIT.COM | @ViewBag.Title</title> </head> <body> <h2>@ViewBag.Title</h2> <div><a href="/">Home</a> | <a href="About">About</a></div> <div> @RenderBody() </div> <footer>@RenderSection("Footer")</footer> </body> </html>
Теперь при запуске предыдущей страницы Index мы получим ошибку, так как секция Footer не определена. По умолчанию страница должна
передавать содержание для каждой секции мастер-страницы. Поэтому добавим вниз страницы Index секцию footer. Это мы можем сделать с помощью
выражения @section
:
@page @{ ViewBag.Title = "Index"; } </h3>Index Content</h3> @section Footer { Copyright© Metanit.com, @DateTime.Now.Year. All rights reserved }
Но при таком подходе, если у нас есть куча страниц, и мы вдруг захотели определить новую секцию на мастер-странице, нам придется изменить все имеющиеся страницы Razor, что не очень удобно. В этом случае мы можем воспользоваться одним из вариантов гибкой настройки секций.
Первый вариант заключается в использовании перегруженной версии метода RenderSection, которая позволяет указать, что
данную секцию не обязательно определять на странице Razor. Чтобы отметить секцию Footer
в качестве необязательной, надо передать в метод
в качестве второго параметра значение false
:
<footer>@RenderSection("Footer", false)</footer>
Второй вариант позволяет задать содержание секции по умолчанию, если данная секция не определенана странице Razor:
<footer> @if (IsSectionDefined("Footer")) { @RenderSection("Footer") } else { <span>Содержание элемента footer по умолчанию.</span> } </footer>