нижнему регистру и отделяется символом переноса (что похоже на шашлык):
<item-create></item-create>
Для настройки таблицы и ее заголовков применяется вспомогательная функция HTML, посредством которой получаются значения DisplayName
, связанные с каждым свойством. Для DisplayName
будет выбираться значение атрибута Display
или DisplayName
, и если он не установлен, то будет использоваться имя свойства. В следующем разделе применяется блок кода Razor для отображения информации о производителе на основе ранее установленной переменной уровня представления:
<table class="table">
<thead>
<tr>
@if (showMake)
{
<th>
@Html.DisplayNameFor(model => model.MakeId)
</th>
}
<th>
@Html.DisplayNameFor(model => model.Color)
</th>
<th>
@Html.DisplayNameFor(model => model.PetName)
</th>
<th></th>
</tr>
</thead>
В последнем разделе производится проход по записям и их отображение с использованием вспомогательной функции HTML по имени DisplayFor()
. Эта вспомогательная функция HTML ищет шаблон отображения с именем, соответствующим типу свойства, и если шаблон не обнаруживается, то разметка создается стандартным образом. Для каждого свойства объекта также выполняется поиск шаблона отображения, который применяется при его наличии. Например, если Car
имеет свойство DateTime
, то для него будет использоваться показанный ранее в главе шаблон DisplayTemplate
.
В следующем блоке также задействованы специальные вспомогательные функции дескрипторов item-edit
, item-details
и item-delete
, которые были добавлены ранее. Обратите внимание, что при передаче значений открытому свойству специальной вспомогательной функции имя свойства указывается с применением "шашлычного" стиля в нижнем регистре и добавляется к дескриптору в виде атрибута:
<tbody>
@foreach (var item in Model)
{
<tr>
@if (showMake)
{
<td>
@Html.DisplayFor(modelItem => item.MakeNavigation.Name)
</td>
}
<td>
@Html.DisplayFor(modelItem => item.Color)
</td>
<td>
@Html.DisplayFor(modelItem => item.PetName)
</td>
<td>
<item-edit item-id="@item.Id"></item-edit> |
<item-details item-id="@item.Id"></item-details> |
<item-delete item-id="@item.Id"></item-delete>
</td>
</tr>
}
</tbody>
</table>
При наличии частичного представления _CarListPartial
представление Index
будет небольшим. Создайте в каталоге ViewsCars
новый файл представления по имени Index.cshtml
. Удалите весь сгенерированный код и добавьте следующую разметку:
@model IEnumerable<Car>
@{
ViewData["Title"] = "Index";
}
<h1>Vehicle Inventory</h1>
<partial name="Partials/_CarListPartial" model="@Model"/>
Частичное представление _CarListPartial
вызывается со значением модели содержащего представления (IEnumerable<Car>
), которое передается с помощью атрибута model
. В итоге модель частичного представления устанавливается в объект, переданный вспомогательной функции дескриптора <partial>
.
Чтобы взглянуть на представление Index
, модифицируйте метод Index()
класса CarsController
, как показано ниже:
[Route("/[controller]")]
[Route("/[controller]/[action]")]
public IActionResult Index()
=> View(_repo.GetAllIgnoreQueryFilters());
Запустив приложение и перейдя по ссылке https://localhost:5001/Cars/Index
, вы увидите список автомобилей (рис. 31.4).
В правой части списка отображаются специальные вспомогательные функции дескрипторов.
Представление ВуMake
похоже на Index
, но настраивает частичное представление так, что информация о производителе отображается только в заголовке страницы. Создайте в каталоге ViewsCars
новый файл представления по имени ВуMake.cshtml
. Удалите весь сгенерированный код и добавьте следующую разметку:
@model IEnumerable<Car>
@{
ViewData["Title"] = "Index";
}
<h1>Vehicle Inventory for @ViewBag.MakeName</h1>
@{
var mode = new ViewDataDictionary(ViewData) {{"ByMake", true}};
}
<partial name="Partials/_CarListPartial" model="Model" view-data="@mode"/>
Отличия заметить легко. Здесь создается экземпляр ViewDataDictionary
, содержащий свойство ByMake
из ViewBag
, который затем вместе с моделью передается частичному представлению, что позволяет скрыть информацию о производителе. Метод действия для этого представления должен получить все автомобили с указанным значением MakeId
и установить ViewBag
в MakeName
с целью отображения в пользовательском интерфейсе. Оба значения берутся из маршрута. Добавьте в класс CarsController
новый метод действия по имени ByMake()
:
[HttpGet("/[controller]/[action]/{makeId}/{makeName}")]
public IActionResult ByMake(int makeId, string makeName)
{
ViewBag.MakeName = makeName;
return View(_repo.GetAllBy(makeId));
}
Запустив приложение и перейдя по ссылке https://localhost:5001/Cars/l/VW
, вы увидите список, показанный на рис. 31.5.
Создайте в каталоге ViewsCars
новый файл представления по имени Details.cshtml
. Удалите весь сгенерированный код и добавьте следующую разметку:
@model Car
@{
ViewData["Title"] = "Details";
}
<h1>Details for @Model.PetName</h1>
@Html.DisplayForModel()
<div>
<item-edit item-id="@Model.Id"></item-edit>
<item-delete item-id="@Model.Id"></item-delete>
<item-list></item-list>
</div>
Вспомогательная функция @Html.DisplayForModel()
использует созданный ранее шаблон отображения (Car.cshtml
) для вывода детальной информации об автомобиле.
Прежде чем обновлять метод действия Details()
, добавьте вспомогательный метод по имени GetOne()
, который будет извлекать одиночную запись Car
:
internal Car GetOneCar(int? id) => !id.HasValue ? null : _repo.Find(id.Value);
Модифицируйте метод действия Details()
следующим образом:
[HttpGet("{id?}")]
public IActionResult Details(int? id)
{
if (!id.HasValue)
{
return BadRequest();
}
var car = GetOneCar(id);
if (car == null)
{
return NotFound();
}
return View(car);
}
Маршрут для метода действия Details()
содержит необязательный параметр маршрута id
с идентификатором автомобиля, значение которого присваивается параметру id
метода. Обратите внимание, что у параметра маршрута есть вопросительный знак с маркером. Это указывает на необязательность параметра, почти как вопросительный знак в типе int?
делает переменную int
допускающей значение null
. Если параметр не был предоставлен или оболочка службы не может отыскать автомобиль с идентификатором, заданным в параметре маршрута, тогда метод возвращает ошибку NotFound
. В противном случае метод отправляет найденную запись Car
представлению Details
. Запустив приложение и перейдя по ссылке https://localhost:5001/Cars/Details/1
, вы увидите экран, показанный на рис. 31.6.