Главная страница   /   20.2. Использование шаблонных вспомогательных методов (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

20.2. Использование шаблонных вспомогательных методов

Для начала мы рассмотрим шаблонные вспомогательные методы Html.Editor и Html.EditorFor. Метод Editor принимает аргумент string, определяющий свойство, для которого требуется элемент editor; он проводит поиск соответствующего свойства в ViewBag и объекте модели (данный процесс был описан в главе 18).

Метод EditorFor является его строго типизированным эквивалентом, в котором свойство модели, необходимое для элемента editor, указывается с помощью лямбда-выражения.

В листинге 20-4 показано, как вспомогательные методы Editor и EditorFor используются в представлении CreatePerson. Как мы уже упоминали в главе 19, мы предпочитаем использовать строго типизированные вспомогательные методы, так как они снижают риск возникновения ошибки из-за опечатки в имени свойства; в этом листинге мы использовали оба типа, просто чтобы показать, что вы можете смешивать и сочетать методы так, как считаете нужным.

Листинг 20-4: Используем методы Editor и EditorFor
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
	Html.EnableClientValidation(false);
}
<h2>CreatePerson</h2>
@using (Html.BeginRouteForm("FormRoute", new {}, FormMethod.Post,
	new {@class = "personClass", data_formType = "person"}))
{
	<div class="dataElem">
		<label>PersonId</label>
		@Html.Editor("PersonId")
	</div>
	<div class="dataElem">
		<label>First Name</label>
		@Html.Editor("FirstName")
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		@Html.EditorFor(m => m.LastName)
	</div>
	<div class="dataElem">
		<label>Role</label>
		@Html.EditorFor(m => m.Role)
	</div>
	<div class="dataElem">
		<label>Birth Date</label>
		@Html.EditorFor(m => m.BirthDate)
	</div>
	<input type="submit" value="Submit" />
}

Editor и EditorFor создают идентичные элементы HTML; единственное различие между ними – это способ записи свойства, для которого создаются элементы editor. Вы можете увидеть результат применения этих методов, запустив приложение и перейдя по ссылке Home/CreatePerson, как показано на рисунке 20-1.

Рисунок 20-1: Используем методы Editor и EditorFor в форме

Не считая свойства BirthDate, эта форма по виду не отличается от формы, которую мы создали в главе 19. Тем не менее, изменения в ней довольно существенные; их можно увидеть, открыв страницу в другом браузере. На рисунке 20-2 показана та же страница в браузере Opera (www.opera.com).

Рисунок 20-2: Отображение формы, созданной с помощью вспомогательных методов Editor и EditorFor

Обратите внимание, что элементы для свойств PersonId и BirthDate выглядят по-другому. У элемента PersonId появились стрелки (которые позволяют увеличивать и уменьшать значение) а элемент BirthDate теперь позволяет выбрать дату.

В спецификации HTML5 определены различные типы элементов input, которые используются для редактирования общих типов данных, таких как числа и даты. Методы Editor и EditorFor выбирают один из этих новых типов, основываясь на типе свойства, которое мы хотим отредактировать. В листинге 20-5 показан код HTML, который был создан для формы на рисунках 20-1 и 20-2.

Листинг 20-5: Элементы HTML input, созданные вспомогательными методами Editor и EditorFor
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width" />
	<title>CreatePerson</title>
	<link href="/Content/Site.css" rel="stylesheet" />
	<style type="text/css">
		label {
			display: inline-block;
			width: 100px;
		}

		.dataElem {
			margin: 5px;
		}
	</style>
</head>
<body>
	<h2>CreatePerson</h2>
	<form action="/app/forms/Home/CreatePerson" class="personClass"
		data-formtype="person" method="post">
		<div class="dataElem">
			<label>PersonId</label>
			<input class="text-box single-line" id="PersonId" name="PersonId"
				type="number" value="0" />
		</div>
		<div class="dataElem">
			<label>First Name</label>
			<input class="text-box single-line" id="FirstName" name="FirstName"
				type="text" value="" />
		</div>
		<div class="dataElem">
			<label>Last Name</label>
			<input class="text-box single-line" id="LastName" name="LastName"
				type="text" value="" />
		</div>
		<div class="dataElem">
			<label>Role</label>
			<input class="text-box single-line" id="Role" name="Role"
				type="text" value="Admin" />
		</div>
		<div class="dataElem">
			<label>Birth Date</label>
			<input class="text-box single-line" id="BirthDate" name="BirthDate"
				type="datetime" value="01/01/0001 00:00:00" />
		</div>
		<input type="submit" value="Submit" />
	</form>
</body>
</html>

Атрибут type указывает, какой элемент input должен быть отображен. Для свойств PersonId and BirthDate во вспомогательных методах указаны типы number и datetime, для других свойств типом по умолчанию является text. Мы видим эти типы только в Opera по той причине, функции HTML5 все еще довольно новые и не все браузеры их поддерживают (в том числе Internet Explorer 10, который мы используем для скриншотов в этой книге).

Как видите, с помощью шаблонных вспомогательных методов мы смогли создать элементы формы, соответствующие контенту. Хотя в данном примере они были не особенно полезны, так как не все браузеры отображают типы элементов input HTML5, а также некоторые свойства, такие как Role, отображаются не так, как нам хотелось бы. Далее мы продемонстрируем, как обеспечить MVC Framework дополнительную информацию и улучшить код HTML, генерируемый вспомогательными методами. Но прежде чем мы углубимся в детали, давайте рассмотрим другие шаблонные вспомогательные методы. В таблице 20-1 приведен полный список вспомогательных методов, которые мы рассмотрим по отдельности в следующих разделах.

Таблица 20-1: Шаблонные вспомогательные методы MVC
Вспомогательный метод Пример Описание
Display Html.Display("FirstName") Визуализирует нередактируемый элемент HTML для указанного свойства модели в соответствии с типом свойства и метаданными.
DisplayFor Html.DisplayFor(x => x.FirstName) Строго типизированная версия предыдущего метода.
Editor Html.Editor("FirstName") Отображает элемент editor (редактируемый элемент HTML) для указанного свойства модели в соответствии с типом свойства и метаданными.
EditorFor Html.EditorFor (x => x.FirstName) Строго типизированная версия предыдущего метода.
Label Html.Label("FirstName") Отображает HTML-элемент <label> для указанного свойства модели
LabelFor Html.LabelFor (x => x.FirstName) Строго типизированная версия предыдущего метода.

Создаем элементы label и display

Чтобы продемонстрировать другие вспомогательные методы, мы добавим в приложение новое представление, которое будет визуализировать нередактируемые элементы на основе данных, полученных из формы. Для начала мы обновили версию HttpPost действия CreatePerson контроллера Home, как показано в листинге 20-6.

Листинг 20-6: Указываем новое представление в контроллере Home
using System.Web.Mvc;
using HelperMethods.Models;

namespace HelperMethods.Controllers
{
	public class HomeController : Controller
	{
		public ActionResult Index()
		{
			ViewBag.Fruits = new string[] {"Apple", "Orange", "Pear"};
			ViewBag.Cities = new string[] {"New York", "London", "Paris"};
			string message = "This is an HTML element: <input>";
			return View((object) message);
		}

		public ActionResult CreatePerson()
		{
			return View(new Person {IsApproved = true});
		}

		[HttpPost]
		public ActionResult CreatePerson(Person person)
		{
			return View("DisplayPerson", person);
		}
	}
}

Мы создали представление DisplayPerson.cshtml в папке /Views/Home; содержимое этого файла показано в листинге 20-7.

Листинг 20-7: Содержимое файла DisplayPerson.cshtml
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "DisplayPerson";
}
<h2>DisplayPerson</h2>
<div class="dataElem">
	@Html.Label("PersonId")
	@Html.Display("PersonId")
</div>
<div class="dataElem">
	@Html.Label("FirstName")
	@Html.Display("FirstName")
</div>
<div class="dataElem">
	@Html.LabelFor(m => m.LastName)
	@Html.DisplayFor(m => m.LastName)
</div>
<div class="dataElem">
	@Html.LabelFor(m => m.Role)
	@Html.DisplayFor(m => m.Role)
</div>
<div class="dataElem">
	@Html.LabelFor(m => m.BirthDate)
	@Html.DisplayFor(m => m.BirthDate)
</div>

Чтобы увидеть вывод этого представления, запустите приложение, перейдите по ссылке /Home/CreatePerson, заполните форму и нажмите кнопку Submit. Результат показан на рисунке 20-3, и, как видите, мы сделали небольшой шаг назад, потому что вспомогательные методы Label и LabelFor используют имена свойств в качестве текста для меток.

Рисунок 20-3: Создаем нередактируемые элементы для объекта Person, используя вспомогательные методы

Вывод этих вспомогательных методов вы можете увидеть в листинге 20-8. Обратите внимание на то, что методы Display и DisplayFor не генерируют элементы HTML по умолчанию, они просто отображают значение свойства, с которым работают.

Листинг 20-8: HTML, созданный представлением DisplayPerson
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width" />
	<title>DisplayPerson</title>
	<link href="/Content/Site.css" rel="stylesheet" />
	<style type="text/css">
		label {
			display: inline-block;
			width: 100px;
		}

		.dataElem {
			margin: 5px;
		}
	</style>
</head>
<body>
	<h2>DisplayPerson</h2>
	<div class="dataElem">
		<label for="PersonId">PersonId</label>
		100
	</div>
	<div class="dataElem">
		<label for="FirstName">FirstName</label>
		Adam
	</div>
	<div class="dataElem">
		<label for="LastName">LastName</label>
		Freeman
	</div>
	<div class="dataElem">
		<label for="Role">Role</label>
		Admin
	</div>
	<div class="dataElem">
		<label for="BirthDate">BirthDate</label>
		01/01/0001 00:00:00
	</div>
</body>
</html>

Хотя в данный момент польза от этих вспомогательных методов не очевидна, далее мы покажем вам, как можно изменить их поведение и сделать их вывод таким, каким вы хотели бы его видеть.

Используем шаблонные вспомогательные методы для целой модели

Мы использовали шаблонные вспомогательные методы, которые генерируют вывод для одного свойства, но MVC Framework также определяет методы, которые работают с целыми объектами; этот процесс известен как формирование шаблонов (scaffolding). Вспомогательные методы для моделей показаны в таблице 20-2.

Таблица 20-2: Вспомогательные методы для моделей
Вспомогательный метод Пример Описание
DisplayForModel Html.DisplayForModel() Визуализирует нередактируемые элементы для объекта модели.
EditorForModel Html.EditorForModel() Визуализирует редактируемые элементы для объекта модели.
LabelForModel Html.LabelForModel() Визуализирует HTML-элемент <label> со ссылкой на объект модели.

В листинге 20-9 показано, как с помощью вспомогательных методов LabelForModel и EditorForModel можно упростить представление CreatePerson.cshtml.

Листинг 20-9: Применяем вспомогательные методы для моделей в представлении CreatePerson
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
	Html.EnableClientValidation(false);
}

<h2>CreatePerson: @Html.LabelForModel()</h2>

@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post,
	new { @class = "personClass", data_formType = "person" }))
{
	@Html.EditorForModel()
	<input type="submit" value="Submit" />
}

Результат применения вспомогательных методов для моделей показан на рисунке 20-4. Напомним еще раз, что пока вывод вспомогательных методов не вполне соответствует нашим ожиданиям. Метод LabelForModel сгенерировал не очень хорошие метки; хотя сейчас отображается больше свойств объекта модели Person, чем мы определили вручную в предыдущих примерах, но отображаются они не все (например, нет свойства Address) и не лучшим способом (например, свойство Role лучше отображать как элемент select, а не input).

Рисунок 20-4: Создаем редактируемые элементы для объекта модели Person с помощью вспомогательных методов для моделей

Часть проблемы заключается в том, что сгенерированный этими методами HTML не соответствует стилям CSS, которые мы добавили в файл /Views/Shared/_Layout.cshtml в главе 19. Ниже приведен пример кода HTML, сгенерированного для свойства FirstName:

<div class="editor-label">
	<label for="FirstName">FirstName</label>
</div>
<div class="editor-field">
	<input class="text-box single-line" id="FirstName" name="FirstName"
		type="text" value="" />
</div>

Чтобы привести в порядок наше представление, мы изменим стили так, чтобы они соответствовали значениям атрибутов CSS class, которые были добавлены к элементам div и input вспомогательными методами. В листинге 20-10 показаны изменения, которые мы внесли в файл _Layout.cshtml.

Листинг 20-10: Изменяем стили CSS, определенные в файле _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<link href="~/Content/Site.css" rel="stylesheet"/>
<style type="text/css">
	label { display: inline-block; width: 100px;}
	.dataElem { margin: 5px;}
	h2 > label {width: inherit;}
	.editor-label, .editor-field {float: left;}
	.editor-label, .editor-label label, .editor-field input {height: 20px;}
	.editor-label {clear: left;}
	.editor-field { margin-left: 10px; margin-top: 10px;}
	input[type=submit] { float: left; clear: both; margin-top: 10px;}
	.column { float: left; margin: 10px;}
</style>
</head>
<body>
	@RenderBody()
</body>
</html>

Эти новые стили приводят страницу в соответствие с макетом, который мы использовали в предыдущих примерах, как показано на рисунке 20-5. (Мы также добавили некоторые стили, которые понадобятся нам позже в этой главе).

Рисунок 20-5: Применяем стили к элементам, используя классы, определенные вспомогательными методами