Un Pager per ASP.NET MVC
Se si è abituati a sviluppare applicazioni con ASP.NET e si passa successivamente a sviluppare con il Framework ASP.NET MVC, la prima cosa di cui si sente la mancanza sono i controlli, che in MVC mancano proprio.
Uno tra questi è il controllo Pager che, come fa ben intuire il nome, serve per gestire la paginazione in tutte quelle parti dei siti web in cui non è possibile mostrare l’elenco completo dei contenuti in un’unica pagina.
Per poter creare un controllo Pager riutilizzabile in tutte le applicazion MVC based, è necessario stabilire tutto ciò che serve per poter creare questo tipo di controllo, ossia:
- Numero totale di pagine (TotalCount);
- Numero di contenuti per pagina (PageSize);
- Pagina corrente (PageIndex);
- Parametro da utilizzare in querystring per comunicare al server la nuova pagina (ParameterName);
Dato che gli MVC ViewUserControl, come le MVC ViewPage, possono avere un Model da utilizzare all’interno del controllo, come prima cosa sarà necessario costruirne uno come il seguente:
public class PagerViewModel { public PagerViewModel(string parameterName, int totalCount, int pageSize, int pageIndex) { ParameterName = parameterName; TotalCount = totalCount; PageSize = pageSize; PageIndex = pageIndex; } public int PageIndex { get; set; } public int PageSize { get; set; } public int TotalCount { get; set; } public string ParameterName { get; set; } public int TotalPages { get { return (int) (TotalCount/(long) PageSize) + (TotalCount%(long) PageSize == 0 ? 0 : 1); } } public bool HasPreviousPage { get { return (PageIndex > 1); } } public bool HasNextPage { get { return (PageIndex*PageSize) <= TotalCount; } } public string PageActionLink(int pageIndex) { if (HttpContext.Current.Request.QueryString.Count > 0) { string q = string.Concat(HttpContext.Current.Request.Url.AbsolutePath, "?", HttpContext.Current.Request.QueryString.ToString(), "&", ParameterName + "=", pageIndex); if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString[ParameterName])) { string qs = HttpContext.Current.Request.QueryString.ToString(); string oldvalue = string.Concat(ParameterName, "=", HttpContext.Current.Request.QueryString[ParameterName]); string newvalue = string.Concat(ParameterName, "=", pageIndex); qs = qs.Replace(oldvalue, newvalue); return string.Concat(HttpContext.Current.Request.Url.AbsolutePath, "?", qs); } return q; } return string.Concat(HttpContext.Current.Request.Url.AbsolutePath, "?", ParameterName + "=", pageIndex); } public string GetPageUrl() { return HttpContext.Current.Request.Url.AbsolutePath + "?" + ParameterName + "=" + PageIndex; } }
Da qui, con una serie di istruzioni if, è facile creare la struttura per la paginazione, come mostrato dal markup seguente:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<PagerViewModel>" %> <%@ Import Namespace="imperugo.sample.mvc.pager.Models"%> <% if (Model.TotalPages > 1) { %> <div class="pnavigation"> <div class="pager"> <span class="pages"> <%= Model.PageIndex %> di <%= Model.TotalPages %> </span> <% if (Model.PageIndex > 1) { %> <a href="<%=Model.PageActionLink (1)%>" title="« First"> « First </a> <% } %> <% if (Model.PageSize - Model.PageSize > 0) { %> <a href="<%=Model.PageActionLink((Model.PageIndex - Model.PageSize) + 1)%>" title="<%=(Model.PageIndex - Model.PageSize) + 1%>"> ... </a> <% } %> <% if (Model.HasPreviousPage) { %> <a href="<%=Model.PageActionLink((Model.PageIndex - 1))%>" title="Previous" >«</a> <% } %> <% for (int page = Model.PageIndex; page < Math.Round((Model.TotalCount / Model.PageSize) + 0.5) && page < Model.PageIndex + Model.PageSize; page++) { %> <% if (page == Model.PageIndex) { %> <span class="current"> <%= Model.PageIndex %> </span> <% } else { %> <a href="<%=Model.PageActionLink(page)%>" title="<%=page.ToString()%>"> <%=page.ToString()%> </a> <% } %> <% } %> <% if (Model.HasNextPage) { %> <a href="<%=Model.PageActionLink ((Model.PageIndex + 1))%>" title="Next" >»</a> <% } %> <% if (Model.PageIndex + Model.PageSize <= (Math.Round((Model.TotalCount / Model.PageSize) + 0.5) - 1)) { %> <a href="<%=Model.PageActionLink((Model.PageIndex + Model.PageSize) + 1)%>" title="<%=(Model.PageIndex + Model.PageSize) + 1%>"> ... </a> <% } %> <% if (Model.PageIndex < Model.TotalPages) { %> <a href="<%=Model.PageActionLink(Model.TotalPages)%>" title="Last »"> Last » </a> <% } %> </div> </div> <% } >
Ora che si hanno a disposizione sia l’ MVC ViewUserControl che il suo Model, è necessario popolare quest’ultimo dal controller come mostrato di seguito:
[HandleError] public class HomeController : Controller { public ActionResult Index(string page) { int pageIndex = string.IsNullOrEmpty(page) ? 1 : int.Parse(page); const int PAGE_SIZE = 10; HomeModel hm = new HomeModel(); hm.News = GetNews(pageIndex, PAGE_SIZE); hm.NewsPage = new PagerViewModel("page", GetTotalNumber(), PAGE_SIZE, pageIndex); return View(hm); } .... }
L’ultimo snippet mostra come utilizzare l’ MVC ViewUserControl dalla View.
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <% for (int i = 0; i < Model.News.Count; i++) { %> <div><%= Model.News[i].Title %></div> <% } %> <div class="pager"> <% Html.RenderPartial("~/Views/Shared/PagerUserControl.ascx", Model.NewsPage); %> </div> </asp:Content>
Nello screeshot seguente è visibile il risultato raggiunto nell’esempio allegato.
Download esempio qui