Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
В прошлой теме был рассмотрен постраничный вывод. Для создания ссылок применялись встроенные хелперы:
@if (Model.PageViewModel.HasPreviousPage) { <a asp-action="Index" asp-route-page="@(Model.PageViewModel.PageNumber - 1)" class="btn btn-outline-dark"> <i class="glyphicon glyphicon-chevron-left"></i> Назад </a> } @if (Model.PageViewModel.HasNextPage) { <a asp-action="Index" asp-route-page="@(Model.PageViewModel.PageNumber + 1)" class="btn btn-outline-dark"> Вперед <i class="glyphicon glyphicon-chevron-right"></i> </a> }
Но, как правило, для создания постраничной навигации создаются какие-то специальные панельки, где можно увидеть ссылки с номерами страниц, по которым можно перейти к нужным страницы, еще какие-то элементы. Все эти элементы нередко должным образом стилизованы.
Нередко элементы навигации - ссылки размещаются в виде ненумерованного списка. В данном случае наша задача - создать компонент навигации наподобие следующего:
<ul class="pagination"> <li><a href="/?page=1">1</a></li> <li class="active"><a>2</a></li> <li><a href="/?page=3">3</a></li> </ul>
Для стилизации применяется класс bootstrap - pagination. Перед активной ссылкой располагаются ссылки на предыдущую и следующую страницу.
Вместо того, чтобы определять все необходимые ссылки и элементы напрямую в представлении, удобнее создать специальный tag-хелпер. Поэтому добавим в проект новую папку TagHelpers, а в эту папку добавим новый класс PageLinkTagHelper:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Routing; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using PagerApp.Models; namespace PagerApp.TagHelpers { public class PageLinkTagHelper : TagHelper { private IUrlHelperFactory urlHelperFactory; public PageLinkTagHelper(IUrlHelperFactory helperFactory) { urlHelperFactory = helperFactory; } [ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContext { get; set; } public PageViewModel PageModel { get; set; } public string PageAction { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext); output.TagName = "div"; // набор ссылок будет представлять список ul TagBuilder tag = new TagBuilder("ul"); tag.AddCssClass("pagination"); // формируем три ссылки - на текущую, предыдущую и следующую TagBuilder currentItem = CreateTag(PageModel.PageNumber, urlHelper); // создаем ссылку на предыдущую страницу, если она есть if (PageModel.HasPreviousPage) { TagBuilder prevItem = CreateTag(PageModel.PageNumber - 1, urlHelper); tag.InnerHtml.AppendHtml(prevItem); } tag.InnerHtml.AppendHtml(currentItem); // создаем ссылку на следующую страницу, если она есть if (PageModel.HasNextPage) { TagBuilder nextItem = CreateTag(PageModel.PageNumber + 1, urlHelper); tag.InnerHtml.AppendHtml(nextItem); } output.Content.AppendHtml(tag); } TagBuilder CreateTag(int pageNumber, IUrlHelper urlHelper) { TagBuilder item = new TagBuilder("li"); TagBuilder link = new TagBuilder("a"); if (pageNumber == this.PageModel.PageNumber) { item.AddCssClass("active"); } else { link.Attributes["href"] = urlHelper.Action(PageAction, new { page = pageNumber }); } item.AddCssClass("page-item"); link.AddCssClass("page-link"); link.InnerHtml.Append(pageNumber.ToString()); item.InnerHtml.AppendHtml(link); return item; } } }
Фреймворк MVC предоставляет ряд сервисов, и один из них - IUrlHelperFactory, который используется для создания ссылки и который мы можем получить в конструкторе.
Всю информацию о пагинации мы получаем через свойство PageModel
. Свойство PageAction
указывает на метод контроллера, на который будет создаваться
ссылка.
Для создания ссылки используется объект IUrlHelper, а для его получения нам нужен контекст представления, в котором вызывается tag-хелпер. Получить контекст представления мы можем через внедрение зависимости через атрибуты. В частности, чтобы получить контекст представления над свойством ставится атрибут ViewContext:
[ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContext { get; set; }
Чтобы избежать привязки к атрибутам тега, к свойству также применяется атрибут HtmlAttributeNotBound
.
В методе Process вначале получаем объект IUrlHelper для создания ссылки:
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
Далее создаем html-элемент ul. Затем нам надо создать максимум три ссылки, если позволяет количество страниц. Так как каждый элемент
списка ul создается одним и тем же способом, то весь механизм создания элемента списка с ссылкой вынесен в отдельный метод CreateTag()
.
Для стилизации ссылок применяются классы pagination, page-item и page-link фреймворка bootstrap, который подключается в приложении ASP.NET Core MVC по умолчанию.
Применим этот хелпер в представлении:
@using PagerApp.Models @model IndexViewModel @*подключаем все tag-хелперы*@ @addTagHelper *, PagerApp @{ ViewData["Title"] = "Список пользователей"; } <h1>Список пользователей</h1> <table class="table"> <tr><th>Имя</th><th>Возраст</th><th>Компания</th></tr> @foreach (User u in Model.Users) { <tr><td>@u.Name</td><td>@u.Age</td><td>@u.Company.Name</td></tr> } </table> <page-link page-model="Model.PageViewModel" page-action="Index"></page-link>
Так как название хелпера состоит из нескольких частей: PageLinkTagHelper, то при использовании все эти части разделяются дефисом
(суффикс TagHelper отбрасывается): page-link
. То же самое касается и свойств хелпера. Так, чтобы передать значение для свойства PageModel,
нам надо использовать атрибут page-model
.
Код контроллера остается тем же, что и в прошлой теме:
using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using PagerApp.Models; using System.Linq; using System.Threading.Tasks; namespace PagerApp.Controllers { public class HomeController : Controller { UsersContext db; public HomeController(UsersContext context) { this.db = context; } public async Task<IActionResult> Index(int page=1) { int pageSize = 3; IQueryable<User> source = db.Users.Include(x=>x.Company); var count = await source.CountAsync(); var items = await source.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync(); PageViewModel pageViewModel = new PageViewModel(count, page, pageSize); IndexViewModel viewModel = new IndexViewModel { PageViewModel = pageViewModel, Users =items }; return View(viewModel); } } }
Итоговый проект будет выглядеть следующим образом:
И при запуске проекта мы увидим набор стилизованных ссылок, по котором сможем перемещаться по страницам: