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">&#8201;<%= Model.PageIndex %> di <%= Model.TotalPages %>&#8201;</span>
        <% if (Model.PageIndex > 1) { %>
        <a href="<%=Model.PageActionLink (1)%>" title="&laquo; First">&#8201;&laquo; First&#8201;</a>
        <% } %>
        <% if (Model.PageSize - Model.PageSize > 0) { %>
            <a href="<%=Model.PageActionLink((Model.PageIndex - Model.PageSize) + 1)%>" title="<%=(Model.PageIndex - Model.PageSize) + 1%>">&#8201;...&#8201;</a>
        <% } %>
        <% if (Model.HasPreviousPage) { %>  
            <a href="<%=Model.PageActionLink((Model.PageIndex - 1))%>" title="Previous" >&laquo;</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">&#8201;<%= Model.PageIndex %>&#8201;</span>
            <% } else { %>
                <a href="<%=Model.PageActionLink(page)%>" title="<%=page.ToString()%>">&#8201;<%=page.ToString()%>&#8201;</a>
            <% } %>
        <% } %>
              
        <% if (Model.HasNextPage) { %>  
            <a href="<%=Model.PageActionLink ((Model.PageIndex + 1))%>" title="Next" >&raquo;</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%>">&#8201;...&#8201;</a>
        <% } %> 
        <% if (Model.PageIndex < Model.TotalPages) { %>
        <a href="<%=Model.PageActionLink(Model.TotalPages)%>" title="Last &raquo;">&#8201;Last &raquo;&#8201;</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.

MVC Pager

Download esempio qui


Comments