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

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

19.3. Использование встроенных вспомогательных методов

MVC Framework включает в себя несколько встроенных вспомогательных методов, предназначенных для создания форм HTML. В следующих разделах мы рассмотрим эти вспомогательные методы в действии и научимся их использовать.

Создаем элементы form

Одним из наиболее распространенных способов взаимодействия с пользователем в веб-приложении являются HTML-формы, которые можно создавать с помощью целого ряда вспомогательных методов. Чтобы продемонстрировать методы, предназначенные для работы с формами, мы внесли некоторые дополнения в наш пример проекта. Для начала мы создали новый класс Person.cs в папке Models. Содержимое этого файла показано в листинге 19-12 – тип Person будет нашей моделью представления, с помощью которой мы продемонстрируем связанные с формами вспомогательные методы, а типы Address и Role помогут нам продемонстрировать некоторые более сложные функции.

Листинг 19-12: Модель Person
using System;

namespace HelperMethods.Models
{
	public class Person
	{
		public int PersonId { get; set; }
		public string FirstName { get; set; }
		public string LastName { get; set; }
		public DateTime BirthDate { get; set; }
		public Address HomeAddress { get; set; }
		public bool IsApproved { get; set; }
		public Role Role { get; set; }
	}

	public class Address
	{
		public string Line1 { get; set; }
		public string Line2 { get; set; }
		public string City { get; set; }
		public string PostalCode { get; set; }
		public string Country { get; set; }
	}

	public enum Role
	{
		Admin,
		User,
		Guest
	}
}

Мы также добавили новые методы действия в контроллер Home, в которых будут использоваться объекты модели и которые показаны в листинге 19-13.

Листинг 19-13: Добавляем методы действий в контроллер 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());
		}

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

Это стандартный подход к работе с HTML-формами, который включает два метода. Здесь мы полагаемся на механизм связывания данных, предполагая, что MVC Framework создаст объект Person из данных формы и передаст его в метод действия с помощью атрибута HttpPost. (Атрибут HttpPost рассматривается в главе 16, а связывание данных - в главе 22).

Мы никак не обрабатываем данные формы, потому что хотим сосредоточиться на том, как генерировать элементы в представлении. Наш метод действия HttpPost просто вызывает метод View и передает в него объект Person, который он получил в качестве параметра; таким образом мы отображаем пользователю введенные им в форму данные.

Для начала мы создадим стандартную HTML-форму вручную, а затем покажем вам, как заменить различные ее части с помощью вспомогательных методов. Первоначальную версию формы вы можете увидеть в листинге 19-14; в нем показано содержимое представления CreatePerson.cshtml, которое мы создали в папке /Views/Home.

Листинг 19-14: Первоначальная версия формы HTML
@model HelperMethods.Models.Person

@{
	ViewBag.Title = "CreatePerson";
}

<h2>CreatePerson</h2>

<form action="/Home/CreatePerson" method="post">
	<div class="dataElem">
		<label>PersonId</label>
		<input name="personId" value="@Model.PersonId"/>
	</div>
	<div class="dataElem">
		<label>First Name</label>
		<input name="FirstName" value="@Model.FirstName"/>
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		<input name="lastName" value="@Model.LastName"/>
	</div>
	<input type="submit" value="Submit" />
</form>

Данное представление содержит стандартную форму, созданную вручную, в которой мы установили значение атрибута value элементов input, используя объект модели.

Подсказка

Обратите внимание, что мы установили атрибут name во всех элементах input так, чтобы он соответствовал свойству модели, которое отображается элементом input. Атрибут input используется стандартным механизмом связывания MVC Framework для того, чтобы выяснить, какие элементы input содержит значения для свойств типа модели во время обработки запроса post и, если вы не укажете атрибут name, форма не будет работать должным образом. В главе 22 мы подробно описываем механизм связывания данных, а также способы изменения его поведения.

Мы отредактировали содержимое файла /Views/Shared/_Layout.cshtml, как показано в листинге 19-15, чтобы максимально упростить данный пример. Мы удалили теги Razor @Scripts и @Styles, которые будут описаны в главе 24.

Листинг 19-15: Упрощаем макет
<!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;
		}
	</style>
</head>
<body>
	@RenderBody()
</body>
</html>

Чтобы увидеть базовую функциональность формы, запустите приложение и перейдите по ссылке /Home/CreatePerson. HTML-форма с примерами данных показана на рисунке 19-6. Так как данные формы никак не используются в приложении, то после нажатия на кнопку Submit они будут просто отображаться пользователю.

Рисунок 19-6: Используем простую форму HTML в приложении

В листинге 19-16 показан код HTML, который приложение направило в браузер; мы будем его использовать, чтобы продемонстрировать изменения, вызванные применением вспомогательных методов.

Листинг 19-16: Код HTML, отправленный в браузер
<!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="/Home/CreatePerson" method="post">
		<div class="dataElem">
			<label>PersonId</label>
			<input name="personId" value="0" />
		</div>
		<div class="dataElem">
			<label>First Name</label>
			<input name="FirstName" />
		</div>
		<div class="dataElem">
			<label>Last Name</label>
			<input name="lastName" />
		</div>
		<input type="submit" value="Submit" />
	</form>
</body>
</html>

Примечание

Используя вспомогательные методы, не обязательно генерировать такие HTML-элементы, как form и input. Если хотите, вы можете закодировать их, используя статические HTML-теги, и заполнить значения с помощью объектов ViewData или ViewModel, как это cделали мы в данном разделе. В следующих разделах мы покажем, как с помощью вспомогательных методов создать чистый HTML-код без каких-либо специальных значений атрибутов. Это не означает, что вы обязаны их использовать, но с их помощью очень легко гарантировать, что HTML будет находиться в синхронизации с приложением, так что, например, изменения в конфигурации будут автоматически отражаться в формах. Вспомогательные методы нужно использовать для удобства, а не потому, что они создают особенный или специальный HTML-код, и вас никто не принуждает их использовать, если они не соответствуют вашему стилю разработки.

Создаем элементы form

Два из наиболее полезных (и наиболее часто используемых) вспомогательных метода - это Html.BeginForm и Html.EndForm. Они создают теги формы HTML и генерируют для нее допустимый атрибут action, основываясь на механизме маршрутизации приложения.

Существует 13 различных версий метода BeginForm, что позволяет нам очень точно указать, как должен быть сгенерирован элемент формы. Для нашего приложения потребуется самая базовая версия, которая не принимает аргументов. Она создает элемент формы, атрибут action которого гарантирует, что форма будет отправлена к тому же методу действия, который визуализировал текущее представление. В листинге 19-17 показано, как мы применили эту перегруженную версию BeginForm, а также вспомогательный метод EndForm (для EndForm есть только одно определение, и он просто закрывает элемент формы, добавляя в представление </form>).

Листинг 19-17: Используем вспомогательные методы BeginForm и EndForm
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@Html.BeginForm()
<div class="dataElem">
	<label>PersonId</label>
	<input name="personId" value="@Model.PersonId"/>
</div>
<div class="dataElem">
	<label>First Name</label>
	<input name="FirstName" value="@Model.FirstName"/>
</div>
<div class="dataElem">
	<label>Last Name</label>
	<input name="lastName" value="@Model.LastName"/>
</div>
<input type="submit" value="Submit" />
@{ Html.EndForm(); }

Обратите внимание, что мы должны были обработать вызов к вспомогательному методу EndForm как оператор C#, так как метод EndForm записывает свой тег непосредственно в вывод, а не возвращает результат, который можно добавить в представление, как это делает BeginForm.

С точки зрения дизайна решение просто ужасное, но это не имеет значения, потому что метод EndForm используется редко. Более распространенный подход показан в листинге 19-18, где вызов к вспомогательному методу BeginForm заключается в выражение using. В конце блока using среда выполнения .NЕТ вызывает для объекта, который возвращается методом BeginForm, метод Dispose, который и вызывает метод EndForm. (Чтобы увидеть, как это работает, загрузите исходный код MVC Framework и рассмотрите класс System.Web.Mvc.Html.FormExtensions).

Листинг 19-18: Создаем самозакрывающуюся форму
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@using (Html.BeginForm())
{
	<div class="dataElem">
		<label>PersonId</label>
		<input name="personId" value="@Model.PersonId"/>
	</div>
	<div class="dataElem">
		<label>First Name</label>
		<input name="FirstName" value="@Model.FirstName"/>
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		<input name="lastName" value="@Model.LastName"/>
	</div>
	<input type="submit" value="Submit" />
}

Этот подход, известный как самозакрывающаяся форма (self-closing form), мы чаще всего используем в своих проектах – нам нравится то, что форма содержится в блоке кода и становится ясно, какие элементы будут находиться между открывающим и закрывающим тегами формы.

Остальные 12 версий метода BeginForm позволяют изменять различные аспекты элемента формы. В этих перегруженных версиях есть много повторов, так как они указывают различные детали, касающиеся создания формы. В таблице 19-4 мы перечислили наиболее важные версии, которые вы будете использовать в приложениях регулярно. Другие перегруженные версии метода BeginForm нужны для совместимости с версиями MVC Framework, которые были выпущены до того, как в C# появилась поддержка создания динамических объектов.

Таблица 19-4: Перегруженные версии вспомогательного метода BeginForm
Перегруженная версия Описание
BeginForm() Создает форму, которая отправляет данные в метод действия, который ее сгенерировал.
BeginForm(action, controller) Создает форму, которая отправляет данные в метод действия и контроллер, указанные в параметрах.
BeginForm(action, controller, method) Как и предыдущие перегруженные версии, но позволяет указать значение атрибута method, используя значение из перечисления System.Web.Mvc.FormMethod.
BeginForm(action, controller, method, attributes) Как и предыдущие перегруженные версии, но позволяет задавать атрибуты элемента формы с помощью объекта, свойства которого используются в качестве имен атрибутов.
BeginForm(action, controller, routeValues, method, attributes) Как и предыдущие перегруженные версии, но позволяет вам указать значения для сегментов переменных маршрутов в конфигурации маршрутизации в приложении с помощью объекта, свойства которого соответствуют переменным маршрутизации.

Мы показали вам простейший вариант метода BeginForm, который полностью подходит для нашего приложения. В листинге 19-19 показана самая сложная версия, в которой мы указали дополнительную информацию для создания элемента формы.

Листинг 19-19: Используем самую сложную перегруженную версию метода BeginForm
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@using (Html.BeginForm("CreatePerson", "Home",
	new { id = "MyIdValue" }, FormMethod.Post,
	new { @class = "personClass", data_formType = "person" }))
{
	<div class="dataElem">
		<label>PersonId</label>
		<input name="personId" value="@Model.PersonId"/>
	</div>
	<div class="dataElem">
		<label>First Name</label>
		<input name="FirstName" value="@Model.FirstName"/>
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		<input name="lastName" value="@Model.LastName"/>
	</div>
	<input type="submit" value="Submit" />
}

В этом примере явно указаны некоторые детали, такие как имя действия и контроллера, которые в противном случае были бы выведены MVC Framework автоматически. Мы также уточнили, что форма должна быть отправлена с помощью метода HTTP POST, который использовался бы в любом случае.

Самые интересные аргументы - те, которые устанавливают значения для переменных маршрута и задают атрибуты для элемента form. С помощью аргумента значения маршрута мы указали значение переменной сегмента id в стандартном маршруте, который был добавлен Visual Studio в файл /App_Start/RouteConfig.cs при создании проекта. Мы также определили атрибуты class и data (атрибуты data - это пользовательские атрибуты, которых можно добавлять к элементам, чтобы они обрабатывали контент HTML). Вот тег формы HTML, который генерирует этот вызов к BeginForm:

<form action="/Home/CreatePerson/MyIdValue" class="personClass" data-formType="person"
	method="post">

Как видите, значение атрибута id было добавлено к целевому URL, а атрибуты class и data - к элементу формы. Обратите внимание, что в нашем вызове к BeginForm мы указали атрибут data_formType, но в итоге получили атрибут data-formType. Нельзя указывать в динамическом объекте имена свойств с дефисами, поэтому мы используем символ подчеркивания, который на выходе автоматически преобразуется в дефис, аккуратно обходя несоответствие между синтаксисом C# и HTML. (И, конечно, мы должны поставить префикс @ перед именем свойства class, чтобы использовать зарезервированное ключевое слово C# в качестве имени свойства для атрибута класса).

Определяем маршрут, который будет использоваться формой

Когда вы используете метод BeginForm, MVC Framework будет искать в конфигурации маршрутизации первый маршрут, с помощью которого она сможет сгенерировать ссылку на запрашиваемое действие или контроллер – в общем, выбор маршрута платформа полностью берет на себя. Если вы хотите указать конкретный маршрут, можете использовать вспомогательный метод BeginRouteForm. Чтобы продемонстрировать его работу, мы добавили новый маршрут в файл /App_Start/RouteConfig.cs, как показано в листинге 19-20.

Листинг 19-20: Добавляем новый маршрут в файл RouteConfig.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace HelperMethods
{
	public class RouteConfig
	{
		public static void RegisterRoutes(RouteCollection routes)
		{
			routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
			routes.MapRoute(
				name: "Default",
				url: "{controller}/{action}/{id}",
				defaults: new
				{
					controller = "Home",
					action = "Index",
					id = UrlParameter.Optional
				}
				);
			routes.MapRoute(
				name: "FormRoute",
				url: "app/forms/{controller}/{action}"
				);
		}
	}
}

Если мы вызовем метод BeginForm при такой конфигурации маршрутизации, то получим элемент form с атрибутом action, который содержит URL, созданный по стандартному маршруту. В листинге 19-21 с помощью метода BeginRouteForm мы указали, что нужно использовать новый маршрут.

Листинг 19-21: Указываем маршрут для создания URL
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post,
	new { @class = "personClass", data_formType = "person" }))
{
	<div class="dataElem">
		<label>PersonId</label>
		<input name="personId" value="@Model.PersonId"/>
	</div>
	<div class="dataElem">
		<label>First Name</label>
		<input name="FirstName" value="@Model.FirstName"/>
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		<input name="lastName" value="@Model.LastName"/>
	</div>
	<input type="submit" value="Submit" />
}

Теперь мы получаем тег form, атрибут action которого содержит URL, соответствующий нашему новому маршруту:

<form action="/app/forms/Home/CreatePerson" class="personClass"
	data-formType="person" method="post">

Подсказка

Для метода BeginRouteForm есть целый ряд перегруженных версий, которые позволяют указывать детали элемента form, как и для метода BeginForm. Они повторяют структуру версий BeginForm. Более подробную информацию можно узнать из документации API.

Создаем элементы input

Элемент HTML form совершенно бесполезен без элементов input. В таблице 19-5 показаны базовые вспомогательные методы для создания элементов ввода, а также приводятся примеры генерируемого ими кода HTML. Для всех этих вспомогательных методов первый аргумент присваивает значения атрибутам id и name элемента input, а второй присваивает значение атрибуту value.

Таблица 19-5: Базовые вспомогательные методы для создания элементов ввода
Элемент HTML Пример
Чекбокс Html.CheckBox("myCheckbox", false) Вывод: <input id="myCheckbox" name="myCheckbox" type="checkbox" value="true" /> <input name="myCheckbox" type="hidden" value="false" />
Скрытое поле Html.Hidden("myHidden", "val") Вывод: <input id="myHidden" name="myHidden" type="hidden" value="val" />
Переключатель Html.RadioButton("myRadiobutton", "val", true) Вывод: <input checked="checked" id="myRadiobutton" name="myRadiobutton" type="radio" value="val" />
Пароль Html.Password("myPassword", "val") Вывод: <input id="myPassword" name="myPassword" type="password" value="val" />
Текстовая область (многострочное текстовое поле) Html.TextArea("myTextarea", "val", 5, 20, null) Вывод: <textarea cols="20" id="myTextarea" name="myTextarea" rows="5"> val</textarea>
Текстовое поле Html.TextBox("myTextbox", "val") Вывод: <input id="myTextbox" name="myTextbox" type="text" value="val" />

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

Примечание

Обратите внимание, что вспомогательный метод для чекбокса (Html.CheckBox) визуализирует два элемента input. Он визуализирует чекбокс и скрытый элемент ввода с таким же названием. Это необходимо потому, что браузеры не отправляют значения чекбокса, если он не был отмечен. Наличие скрытого элемента управления гарантирует, что в таких случаях MVC Framework получит значение из скрытого поля.

В листинге 19-22 показано, как мы использовали базовые вспомогательные методы для создания элементов ввода.

Листинг 19-22: Используем базовые вспомогательные методы для создания элементов ввода
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}

<h2>CreatePerson</h2>

@using (Html.BeginRouteForm("FormRoute", new {}, FormMethod.Post,
	new {@class = "personClass", data_formType = "person"}))
{
	<div class="dataElem">
		<label>PersonId</label>
		@Html.TextBox("personId", @Model.PersonId)
	</div>
	<div class="dataElem">
		<label>First Name</label>
		@Html.TextBox("firstName", @Model.FirstName)
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		@Html.TextBox("lastName", @Model.LastName)
	</div>
	<input type="submit" value="Submit" />
}

Элементы HTML input, которые генерирует это представление, показаны в листинге 19-23. Вывод очень похож на наш первоначальный элемент form, но здесь уже появились некоторые намеки на MVC Framework – например, атрибуты data, которые добавляют валидацию формы (валидацию мы рассматривали в главе 2 и вернемся к этой теме в главе 23).

Листинг 19-23: Элементы input, созданные с помощью базовых вспомогательных методов ввода
<form action="/app/forms/Home/CreatePerson" class="personClass" data-formtype="person"
	method="post">
	<div class="dataElem">
		<label>PersonId</label>
		<input data-val="true" data-val-number="The field PersonId must be a number."
			data-val-required="The PersonId field is required." id="personId"
			name="personId" type="text" value="0" />
	</div>
	<div class="dataElem">
		<label>First Name</label>
		<input id="firstName" name="firstName" type="text" value="" />
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		<input id="lastName" name="lastName" type="text" value="" />
	</div>
	<input type="submit" value="Submit" />
</form>

Подсказка

Чтобы создать атрибуты data, которые поддерживают валидацию форм для всего приложения, установите параметру UnobtrusiveJavaScriptEnabled значение false в файле Web.config. Отключить эту функцию для отдельных представлений можно вызовом Html.EnableClientValidation(false) в блоке кода Razor. Пример этого вы сможете увидеть в главе 23, где мы отключим атрибуты data, чтобы создавать элементы HTML с помощью более продвинутых вспомогательных методов.

Создаем элемент input из свойства модели

Вспомогательные методы, которые мы использовали в предыдущем разделе, неплохо справляются со своими обязанностями, но мы все еще должны гарантировать, что значение первого аргумента соответствует значению модели, которую мы передаем в качестве второго аргумента. В противном случае MVC Framework не сможет восстановить объект модели из данных формы, поскольку атрибуты name и значения forms элементов input не будут совпадать.

Для каждого из методов, перечисленных в таблице 19-5, существует альтернативная перегруженная версия, которая принимает строковый аргумент single, который мы использовали в листинге 19-24.

Листинг 19-24: Создаем элемент input с помощью имени свойства модели
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@using (Html.BeginRouteForm("FormRoute", new { }, FormMethod.Post,
	new { @class = "personClass", data_formType = "person" }))
{
	<div class="dataElem">
		<label>PersonId</label>
		@Html.TextBox("PersonId")
	</div>
	<div class="dataElem">
		<label>First Name</label>
		@Html.TextBox("firstName")
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		@Html.TextBox("lastName")
	</div>
	<input type="submit" value="Submit" />
}

Аргумент string используется для поиска в ViewData, ViewBag и ViewModel данных, которые используются для создания элемента input. Так, например, если вы вызываете @Html.TextBox("DataValue"), MVC Framework попытается найти какие-либо данные, которые соответствуют ключу DataValue. Проверяются следующие адреса:

  • ViewBag.DataValue;
  • @Model.DataValue.

Первое найденное значение используется для установки значения атрибута value генерируемого элемента HTML. (Последний адрес, @Model.DataValue, проверяется, только если модель представления содержит свойство или поле под названием DataValue.)

Если указать строку вида DataValue.First.Name, поиск станет более сложным. MVC Framework будет проверять различные адреса, в который First и Name будут записаны по-разному, например:

  • ViewBag.DataValue.First.Name
  • ViewBag.DataValue["First"].Name
  • ViewBag.DataValue["First.Name"]
  • ViewBag.DataValue["First"]["Name"]

Напомним, что будет использовано первое найденное значение, на котором поиск будет остановлен. Очевидно, это решение сделано для оптимизации производительности, но, как правило, ViewBag содержит немного значений, так что их проверка не занимает много времени.

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

Для каждого из базовых вспомогательных методов ввода, которые мы описали в таблице 19-5, имеются соответствующие строго типизированные версии. Они показаны в таблице 19-6 вместе с примерами кода HTML, который они генерируют.

Эти вспомогательные методы используются только в строго типизированных представлениях. (Для краткости мы опустили из таблицы некоторые вспомогательные методы, которые генерируют атрибуты валидации форм на стороне клиента.)

Таблица 19-6: Строго типизированные вспомогательные методы ввода
Элемент HTML Пример
Чекбокс Html.CheckBoxFor(x => x.IsApproved) Вывод: <input id="IsApproved" name="IsApproved" type="checkbox" value="true" /> <input name="IsApproved" type="hidden" value="false" />
Скрытое поле Html.HiddenFor(x => x.FirstName) Вывод: <input id="FirstName" name="FirstName" type="hidden" value="" />
Переключатель Html.RadioButtonFor(x => x.IsApproved, "val") Вывод: <input id="IsApproved" name="IsApproved" type="radio" value="val" />
Пароль Html.PasswordFor(x => x.Password) Вывод: <input id="Password" name="Password" type="password" />
Текстовая область Html.TextAreaFor(x => x.Bio, 5, 20, new{}) Вывод: <textarea cols="20" id="Bio" name="Bio" rows="5">Bio value</textarea>
Текстовое поле Html.TextBoxFor(x => x.FirstName) Вывод: <input id="FirstName" name="FirstName" type="text" value="" />

Строго типизированные вспомогательные методы ввода работают с лямбда-выражениями. Значение, которое передается в выражение, - это объект модели представления, и вы можете выбрать поле или свойство, которое будет использоваться для установки атрибута value. В листинге 19-25 показано, как мы использовали этот вид вспомогательных методов в представлении CreatePerson.cshtml.

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

Сгенерированный ими HTML ничем не отличается, но мы предпочитаем использовать строго типизированные вспомогательные методы потому, что они снижают риск возникновения ошибки из-за опечатки в имени свойства.

Создаем элементы select

В таблице 19-7 показаны вспомогательные методы, которые используются для создания элементов select. С их помощью можно создать элемент, позволяющий выбрать один пункт из раскрывающегося списка, или элемент множественного выбора, который позволяет выбрать несколько пунктов. Как для других элементов форм, для этих вспомогательных методов существуют слабо и строго типизированные версии.

Таблица 19-7: Вспомогательные методы HTML, которые визуализируют элементы выбора
Элемент HTML Пример
Раскрывающийся список Html.DropDownList("myList", new SelectList(new [] {"A", "B"}), "Choose") Вывод: <select id="myList" name="myList"> <option value="">Choose</option> <option>A</option>

<option>B</option> </select>

Раскрывающийся список Html.DropDownListFor(x => x.Gender, new SelectList(new [] {"M", "F"})) Вывод: <select id="Gender" name="Gender"> <option>M</option> <option>F</option> </select>
Список множественного выбора Html.ListBox("myList", new MultiSelectList(new [] {"A", "B"})) Вывод: <select id="myList" multiple="multiple" name="myList"> <option>A</option>

<option>B</option> </select>

Список множественного выбора Html.ListBoxFor(x => x.Vals, new MultiSelectList(new [] {"A", "B"})) Вывод: <select id="Vals" multiple="multiple" name="Vals"> <option>A</option>

<option>B</option> </select>

Вспомогательные методы select принимают параметры SelectList или MultiSelectList. Разница между этими классами заключается в том, что для MultiSelectList есть опции конструктора, которые позволяют указать, что при первоначальной загрузке страницы необходимо выбрать более одного пункта.

Оба эти классы работают с последовательностью объектов IEnumerable. В таблице 19-7 мы создали внутренние массивы, которые содержат пункты списка, но SelectList и MultiSelectList будут извлекать значения для пунктов списка из объектов, в том числе из объекта модели. Как видите, мы создали элемент select для свойства Role модели Person в листинге 19 - 26.

Листинг 19-26: Создаем элемент select для свойства Person.Role
@model HelperMethods.Models.Person
@{
	ViewBag.Title = "CreatePerson";
}
<h2>CreatePerson</h2>
@using (Html.BeginRouteForm("FormRoute", new {}, FormMethod.Post,
	new {@class = "personClass", data_formType = "person"}))
{
	<div class="dataElem">
		<label>PersonId</label>
		@Html.TextBoxFor(m => m.PersonId)
	</div>
	<div class="dataElem">
		<label>First Name</label>
		@Html.TextBoxFor(m => m.FirstName)
	</div>
	<div class="dataElem">
		<label>Last Name</label>
		@Html.TextBoxFor(m => m.LastName)
	</div>
	<div class="dataElem">
		<label>Role</label>
		@Html.DropDownListFor(m => m.Role,
			new SelectList(Enum.GetNames(typeof (HelperMethods.Models.Role))))
	</div>
	<input type="submit" value="Submit" />
}

Мы определили свойство Role, используя значение из перечисления Role, определенного в том же классе. Поскольку объекты SelectList и MultiSelectList работают на объектах IEnumerable, мы должны применить метод Enum.GetNames, чтобы использовать Role enum в качестве источника для элемента select. В листинге 19-27 показан код HTML, который создает наше обновленное представление, в том числе элемент select.

Листинг 19-27: Код HTML, который создает представление CreatePerson
<!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 data-val="true" data-val-number="The field PersonId must be a number." data-valrequired="
The PersonId field is required."
				id="PersonId" name="PersonId" type="text" value="0" />
		</div>
		<div class="dataElem">
			<label>First Name</label>
			<input id="FirstName" name="FirstName" type="text" value="" />
		</div>
		<div class="dataElem">
			<label>Last Name</label>
			<input id="LastName" name="LastName" type="text" value="" />
		</div>
		<div class="dataElem">
			<label>Role</label>
			<select data-val="true" data-val-required="The Role field is required."
				id="Role" name="Role">
				<option selected="selected">Admin</option>
				<option>User</option>
				<option>Guest</option>
			</select>
		</div>
		<input type="submit" value="Submit" />
	</form>
</body>
</html>