Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP_NET_MVC_4_Framework_s_primerami_na_C_dlya_p

.pdf
Скачиваний:
25
Добавлен:
19.03.2016
Размер:
17.66 Mб
Скачать

Таблица 18-1: Свойства поиска движка Razor

 

 

 

 

 

Свойство

 

Описание

Значение по умолчанию

 

 

 

 

 

 

Адреса для

~/Views/{1}/{0}.cshtml,

ViewLocationFormats

 

поиска

 

представлений,

~/Views/{1}/{0}.vbhtml,

MasterLocationFormats

 

частичных

~/Views/Shared/{0}.cshtml,

PartialViewLocationFormats

 

 

 

представлений и

~/Views/Shared/{0}.vbhtml

 

 

макетов

 

 

 

 

 

 

 

Адреса для

 

 

 

поиска

~/Areas/{2}/Views/{1}/{0}.cshtml,

AreaViewLocationFormats

 

представлений,

 

~/Areas/{2}/Views/{1}/{0}.vbhtml,

AreaMasterLocationFormats

 

частичных

AreaPartialViewLocationFormats

 

представлений и

~/Areas/{2}/Views/Shared/{0}.cshtml,

 

 

макетов для

~/Areas/{2}/Views/Shared/{0}.vbhtml

 

 

областей

 

Эти свойства предшествовали появлению Razor, поэтому каждой группе из трех свойств соответствует один набор значений. Каждый набор значений представляет собой массив строк. Ниже приведены значения параметров, которые соответствуют заполнителям:

{0} - имя представления.

{1} - имя контроллера.

{2} - имя области.

Для изменения адресов поиска создайте новый класс, наследующий от RazorViewEngine, и измените значения для одного или нескольких свойств, описанных в таблице 18-1.

Чтобы продемонстрировать, как изменять адреса поиска, мы добавили в приложение проект Infrastructure и создали движок представлений под названием CustomLocationViewEngine, который показан в листинге 18-12.

Листинг 18-12: Изменяем адреса поиска в Razor

using System.Web.Mvc;

namespace WorkingWithRazor.Infrastructure

{

public class CustomLocationViewEngine : RazorViewEngine

{

public CustomLocationViewEngine()

{

ViewLocationFormats = new string[] {"~/Views/{1}/{0}.cshtml", "~/Views/Common/{0}.cshtml"};

}

}

}

Мы установили новое значение для ViewLocationFormats. Наш новый массив содержит записи только для файлов .cshtml. Кроме того, мы изменили каталог для общих представлений на Views/Common вместо Views/Shared. Далее мы зарегистрировали наш пользовательский движок,

используя коллекцию ViewEngines.Engines в методе Application_Start файла Global.asax, как показано в листинге 18-13.

461

Листинг 18-13: Регистрируем пользовательский движок представлений

using System.Web.Http; using System.Web.Mvc;

using System.Web.Optimization; using System.Web.Routing;

using WorkingWithRazor.Infrastructure;

namespace WorkingWithRazor

{

public class MvcApplication : System.Web.HttpApplication

{

protected void Application_Start()

{

AreaRegistration.RegisterAllAreas();

ViewEngines.Engines.Clear();

ViewEngines.Engines.Add(new CustomLocationViewEngine());

WebApiConfig.Register(GlobalConfiguration.Configuration);

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

RouteConfig.RegisterRoutes(RouteTable.Routes);

BundleConfig.RegisterBundles(BundleTable.Bundles);

}

}

}

Вы должны помнить, что механизм вызова действий обращается к каждому движку по очереди, проверяя, какой из них может найти представление. Когда нам нужно было добавить в коллекцию пользовательский движок, она уже содержала стандартный движок Razor. Чтобы избежать конкуренции с этой реализацией, мы вызвали метод Clear и удалили все зарегистрированные движки, а затем зарегистрировали наш пользовательский движок с помощью метода Add.

Чтобы продемонстрировать изменение адресов поиска, мы создали папку /Views/Common и добавили в нее файл представления под названием List.cshtml. Содержимое этого файла показано в листинге

18-14.

Листинг 18-14: Содержимое файла /Views/Common/List.cshtml

@{

ViewBag.Title = "List";

}

<h3>This is the /Views/Common/List.cshtml View</h3>

Для отображения этого представления мы добавили в контроллер Home метод действия, показанный в листинге 18-15.

Листинг 18-15: Добавляем метод действия в контроллер Home

using System.Web.Mvc;

namespace WorkingWithRazor.Controllers

{

public class HomeController : Controller

{

public ActionResult Index()

{

string[] names = {"Apple", "Orange", "Pear"}; return View(names);

}

public ActionResult List()

{

462

return View();

}

}

}

Если мы запустим приложение и перейдем по ссылке /Home/List, поиск файла представления List.cshtml будет осуществляться в добавленной нами папке Views/Common, как показано на рисунке 18-5.

Рисунок 18-5: Результат добавления новых адресов поиска в движок представления

Добавление динамического контента в представление Razor

Главная цель представлений - визуализировать компоненты доменной модели как компоненты пользовательского интерфейса. Для этого нужно уметь добавлять в представления динамический контент. Динамический контент генерируется во время выполнения и может быть разным для разных запросов. Это его отличие от статического контента, такого как HTML, который вы создаете при написании приложения и который остается одинаковым для всех запросов. Динамический контент можно добавить в представления несколькими способами, которые описаны в таблице 18-2.

Таблица 18-2: Способы добавления динамического контента в представления

Способ

Код

Вспомогательные методы HTML

Используется для

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

Используются для создания одного элемента HTML или небольшой коллекции элементов, обычно на основании данных модели представления или объекта ViewData. Можно использовать встроенные вспомогательные методы MVC Framework, можно также создавать свои собственные. Вспомогательные методы HTML рассматриваются в главе 19.

Секции

 

Используются для разбиения контента на блоки, которые будут вставлены в макет в

 

 

 

 

 

 

463

Способ

Частичные

представления

Используется для

определенных местах.

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

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

действия, визуализирует представление и внедряет результат в поток ответа.

Первые два способа рассматриваются в других главах этой книги, а три последних мы опишем в последующих разделах.

Используем секции

Движок Razor поддерживает концепцию секций, которые позволяют выделять различные области в макете. Секции Razor позволяют разбивать представление на части и контролировать то, где они внедряются в макет. Чтобы продемонстрировать работу секций, мы отредактировали файл

/Views/Home/Index.cshtml, как показано в листинге 18-16.

Листинг 18-16: Определяем секцию в представлении

@model string[] @{

ViewBag.Title = "Index";

}

@section Header { <div class="view">

@foreach (string str in new[] { "Home", "List", "Edit" })

{

@Html.ActionLink(str, str, null, new { style = "margin: 5px" })

}

</div>

}

<div class="view">

This is a list of fruit names: @foreach (string name in Model)

{

<span><b>@name</b></span>

}

</div>

@section Footer { <div class="view">

This is the footer </div>

}

464

Секции определяются с помощью тега Razor @, за которым следует имя секции. В нашем примере их две - Header и Footer. Их содержание представляет собой обычную смесь разметки HTML и тегов

Razor.

Чтобы указать, где в макете должны отображаться секции, используется вспомогательный метод @RenderSection. В листинге 18-17 показаны изменения, которые мы внесли в файл

~/Views/Shared/_Layout.cshtml.

Подсказка

Движок представлений все еще использует наши пользовательские адреса поиска, что означает, что макеты находятся в папке /Views/Shared, а представления - в

/Views/Common.

Листинг 18-17: Используем секции в макете

<!DOCTYPE html> <html>

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width" /> <style type="text/css">

div.layout { background-color: lightgray;

}

div.view {

border: thin solid black; margin: 10px 0;

}

</style>

<title>@ViewBag.Title</title>

</head>

<body>

@RenderSection("Header")

<div class="layout">

This is part of the layout </div>

@RenderBody()

<div class="layout">

This is part of the layout </div>

@RenderSection("Footer")

<div class="layout">

This is part of the layout </div>

</body>

</html>

Когда Razor анализирует макет, он заменяет вспомогательный метод RenderSection на содержимое секции представления с указанным именем. Те части представления, которые не содержатся в секциях, вставляются в макет с помощью вспомогательного метода RenderBody.

465

Чтобы увидеть работу секций, запустите приложение, как показано на рисунке 18-6. Мы добавили некоторые базовые стили CSS, чтобы было понятно, какие из выведенных секций принадлежат представлению и какие - макету. Результат выглядит незамысловато, но он демонстрирует, как можно внедрить части контента представления в макет в заданной последовательности.

Рисунок 18-6: Используем секции в представлении, чтобы внедрить контент в макет

Примечание

В представлении можно определить только те секции, на которые есть ссылки в макете. При попытке определить в представлении секции, для которых нет соответствующего вызова вспомогательного метода @RenderSection в макете,

MVC Framework выбросит исключение.

Смешивание секций с остальным кодом представления – нестандартный подход. По соглашению секции определяются либо в начале, либо в конце представления, чтобы легче было увидеть, какие области контента будет рассматриваться как секции и будут захвачены вспомогательным методом RenderBody. Мы часто используем и другой подход, согласно которому представление должно содержать только секции, тело представления также заключается в секцию, как показано в листинге

18-18.

Листинг 18-18: Определяем представление с помощью секций Razor

@model string[] @{

ViewBag.Title = "Index";

}

@section Header { <div class="view">

@foreach (string str in new[] { "Home", "List", "Edit" })

{

@Html.ActionLink(str, str, null, new { style = "margin: 5px" })

}

466

</div>

}

@section Body { <div class="view">

This is a list of fruit names: @foreach (string name in Model)

{

<span><b>@name</b></span>

}

</div>

}

@section Footer { <div class="view">

This is the footer </div>

}

Мы считаем, что такой подход позволяет создавать более понятные представления и снижает вероятность того, что RenderBody захватит посторонний контент. Чтобы его применить, мы должны заменить вызов вспомогательного метода RenderBody на RenderSection("Body"), как показано в листинге 18-19.

Листинг 18-19: Определяем представление с помощью RenderSection("Body")

<!DOCTYPE html> <html>

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width" /> <style type="text/css">

div.layout { background-color: lightgray;

}

div.view {

border: thin solid black; margin: 10px 0;

}

</style>

<title>@ViewBag.Title</title>

</head>

<body>

@RenderSection("Header")

<div class="layout">

This is part of the layout </div>

@RenderSection("Body")

<div class="layout">

This is part of the layout </div>

@RenderSection("Footer")

<div class="layout">

This is part of the layout </div>

</body>

</html>

467

Тестирование секций

Вы можете проверить, определена ли в представлении какая-либо секция из макета. Это делается для того, чтобы предоставить контент по умолчанию для этой секции, если она отсутствует в представлении и мы по каким-то причинам не хотим ее там определять. Мы изменили файл _Layout.cshtml, чтобы проверить, определена ли в нем секция Footer, как показано в листинге 1820.

Листинг 18-20: Проверяем наличие секции Footer в представлении

@if (IsSectionDefined("Footer"))

{

@RenderSection("Footer")

}

else

{

<h4>This is the default footer</h4>

}

Вспомогательный метод IsSectionDefined возвращает true для заданного имени секции, если в текущем представлении определена эта секция. В этом примере с помощью вспомогательного метода мы выясняем, нужно ли предоставлять какой-либо контент по умолчанию, если окажется, что в представлении не определена секция Footer.

Визуализируем дополнительные секции

По умолчанию в представлении должны быть определены все секции, к которым в макете имеются вызовы RenderSection. Если секции отсутствуют, MVC Framework покажет пользователю исключение. Чтобы продемонстрировать это, мы добавили в файл _Layout.cshtml новый вызов RenderSection к секции под названием scripts, как показано в листинге 18-21 (это секция, которую Visual Studio добавляет в макет по умолчанию для проектов на шаблоне Basic, но которую мы удалили в самом начале).

Листинг 18-21: Добавляем в макет вызов RenderSection, для которого нет соответствующей секции в представлении

<!DOCTYPE html> <html>

<head>

<meta charset="utf-8" />

<meta name="viewport" content="width=device-width" /> <style type="text/css">

div.layout { background-color: lightgray;

}

div.view {

border: thin solid black; margin: 10px 0;

}

</style>

<title>@ViewBag.Title</title>

</head>

<body>

@RenderSection("Header")

<div class="layout">

This is part of the layout </div>

468

@RenderSection("Body")

<div class="layout">

This is part of the layout </div>

@if (IsSectionDefined("Footer"))

{

@RenderSection("Footer")

}

else

{

<h4>This is the default footer</h4>

}

@RenderSection("scripts")

<div class="layout">

This is part of the layout </div>

</body>

</html>

Если мы запустим приложение и движок Razor попытается визуализировать макет и представление, то увидим ошибку, показанную на рисунке 18-7.

Рисунок 18-7: Ошибка, которая появляется в случае отсутствия секции

Вы можете использовать метод IsSectionDefined, чтобы избежать вызовов RenderSection к секциям, не определенным в представлении, но для этого есть более элегантный подход: передавать дополнительное значение false в метод RenderSection, как показано в листинге 18-22.

Листинг 18-22: Делаем секцию необязательной

@RenderSection("scripts", false)

469

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

Используем частичные представления

В приложениях мы часто используем одни и те же фрагменты тегов Razor и HTML-разметки в нескольких представлениях. Чтобы не дублировать контент, можно использовать частичные представления. Они представляют собой отдельные файлы, которые содержат фрагменты кода с тегами и разметкой и могут быть включены в другие представления. В этом разделе мы покажем вам, как создавать и использовать частичные представления, объясним принципы их работы и продемонстрируем способы передачи в них данных представлений.

Создаем частичное представление

Для начала создадим частичное представление под названием MyPartial. Для этого кликните правой кнопкой мыши по папке /Views/Shared, выберите из контекстного меню Add - View и отметьте флажком опцию Create as Partial View, как показано на рисунке 18-8.

Рисунок 18-8: Создаем частичное представление

470

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]