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.