ASP.NET MVC – Pagination View User Control

Each website, content management system, blog and so on need "pagination". A never ending site with "foo-entries" is not very professional. Thats why i created for my ASP.NET MVC sample (a kigg / dotnetnuke similar page) a specific"Pagination View User Control"

In almost every "List" View I implemented my control:

image

image

The advantages of such an control:

- look and feel is on each page the same 
- changes are very easy to implement

In my sampel I use this CSS design.

Structure

image 

A typical MVC View User Control

Code

Pagination.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Pagination.ascx.cs" Inherits="Mvc2.Views.Shared.Pagination" %>
<ul class="pagination-clean">
    <% if (ViewData.HasPreviousPage)
        { %>
          <li class="previous"><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", (ViewData.PageIndex - 1).ToString())%>">« Previous</a></li>
     <% }
       else
        { %>
          <li class="previous-off">« Previous</li>
     <% } %>

     <%for (int page = 1; page <= ViewData.TotalPages; page++)
        {
        if (page == ViewData.PageIndex)
            { %>
              <li class="active"><%=page.ToString()%></li>
         <% }
        else
            { %>
              <li><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", page.ToString())%>"><%=page.ToString()%></a></li>
         <% }
        } 

       if (ViewData.HasNextPage)
            { %>
              <li class="next"><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", (ViewData.PageIndex + 1).ToString())%>">Next »</a></li>
         <% }
       else
            { %>
               <li class="next-off">Next »</li>
         <% } %>
</ul> 

Pagination.ascx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Mvc2.Views.Shared
{
    public class PaginationViewData
    {
        public int PageIndex { get; set; }
        public int TotalPages { get; set; }
        public int PageSize { get; set; }
        public int TotalCount { get; set; }
        public string PageActionLink { get; set; }
        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 1);
            }
        }

        public bool HasNextPage
        {
            get
            {
                return (PageIndex * PageSize) <= TotalCount;
            }
        }
    }

    public partial class Pagination : System.Web.Mvc.ViewUserControl<PaginationViewData>
    {
        public Pagination()
        {

        }
    }
}

The ViewData is strongly typed by the PaginationViewData class.

How to use – Helper "PagedList"

It is very easy to use, if you are already use the PageList class:

using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Collections.Generic;

namespace Mvc2.Helpers
{
    public class PagedList<T> : List<T>
    {
        public PagedList(IQueryable<T> source, int index, int pageSize)
        {
            this.TotalCount = source.Count();
            this.PageSize = pageSize;
            this.PageIndex = index;
            this.AddRange(source.Skip((index - 1) * pageSize).Take(pageSize).ToList());

            int pageResult = 0;
            for (int counter = 1; pageResult < this.TotalCount; counter++)
            {
                pageResult = counter * this.PageSize;
                this.TotalPages = counter;
            }
        }

        public int TotalPages
        {
            get;
            set;
        }

        public int TotalCount
        {
            get;
            set;
        }

        public int PageIndex
        {
            get;
            set;
        }

        public int PageSize
        {
            get;
            set;
        }

        public bool HasPreviousPage
        {
            get
            {
                return (PageIndex > 1);
            }
        }

        public bool HasNextPage
        {
            get
            {
                return (PageIndex * PageSize) <= TotalCount;
            }
        }
    }

    public static class Pagination
    {
        public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index, int pageSize)
        {
            return new PagedList<T>(source, index, pageSize);
        }

        public static PagedList<T> ToPagedList<T>(this IQueryable<T> source, int index)
        {
            return new PagedList<T>(source, index, 10);
        }
    }
}

The original code wrote Rob Conery – in my version is the first page the number 1, not 0 – a user could confused by the link to page number 0 ;)

How to use- in the view page

I render the control by using the in-build "Html.RenderUserControl" helper:

    <%=Html.RenderUserControl("~/Views/Shared/Pagination.ascx", new Mvc2.Views.Shared.PaginationViewData()
      {
          PageIndex = ViewData.EntryList.PageIndex,
          TotalPages = ViewData.EntryList.TotalPages,
          PageActionLink = Url.Action("List","Entry", new { category = ViewData.Category, page = "{page}"}),
          TotalCount = ViewData.EntryList.TotalCount,
          PageSize = ViewData.EntryList.PageSize
      }, null)%>

The properties of the control and of the PagedList are almost the same – only the "PageActionLink" is a specific property. The "PageActionLink" is the action Link to your controller – "/Management/Tag/2" route to your "Management"-Controller and "Tag"-ActionMethod with the page parameter. The "page = {page}" parameter is only a template for the real page number, which will be replaced in my control:

<li><a href="<%=ViewData.PageActionLink.Replace("%7Bpage%7D", page.ToString())%>"><%=page.ToString()%></a></li>

The URL helper method encode the { and } to %7B and %7D. I can´t explain it very well in english – one quick look in the source code (pagination.ascx) is very helpful ;)

Feel free to use it.

PS: English blogging is hard :/ ;)

kick it on DotNetKicks.com

29 Comments so far »

  1. Troy Goode said

    am April 9 2008 @ 2:41 am

    Nice work, Robert. This is something I (and I’m sure many other MVC developers) will use often.

    Oh, and your English was fine. =)

  2. Troy Goode said

    am April 9 2008 @ 2:57 am

    Oh, and on another note, coincidentally I have made the same changes to Rob’s PagedList class as you have, but I think this is a bit better of a calculation for TotalPages:

    (excuse the formatting please)

    if( this.TotalCount > 0 )
    {
    this.TotalPages = (int)Math.Ceiling( (double)this.TotalCount / (double)this.PageSize );
    }
    else
    {
    this.TotalPages = 0;
    }

  3. Rob Conery's PagedList Class (Updated) said

    am April 9 2008 @ 3:34 am

    [...] April 8, 2008 9:33 PM Robert Muehsig has posted a great user control for the MVC framework that adds pagination links to the bottom of a paged list. In it he used a slightly customized version of Rob Conery’s PagedList class that Rob was kind [...]

  4. Code-Inside gibts jetzt auch auf englisch… | Code-Inside Blog said

    am April 9 2008 @ 7:54 am

    [...] Code-Inside: ASP.NET MVC – Pagination View User ControlCode-Inside International: ASP.NET MVC – Pagination View User Control [...]

  5. 47 ASP.NET MVC Resources to Rock Your Development - Craig Shoemaker said

    am April 24 2008 @ 7:14 pm

    [...] Pagination User Control: Robert Muehsig demonstrates how to build a pagination view user control. [...]

  6. ASP.NET MVC - Resources | Code-Inside Blog International said

    am April 25 2008 @ 7:34 am

    [...] Even my Pagination User Control is in this list (and in the podcast) [...]

  7. anonymous said

    am June 1 2008 @ 9:33 am

    Can you post your controller code to complete this blog post so we can see how you are interacting with that. Sure, I can “imagine” sort of what you’re doing such as adding a page param in your action like you said, and imagine up your controller based on your route but would like to see the actual action, so I have a little more clear context.

    Would be a big help.

  8. CK1 said

    am June 5 2008 @ 11:00 am

    Just wanted to say thanks – I’m new to MVC and this was a great help for paging! Cheers! :)

  9. Robert Muehsig said

    am June 5 2008 @ 11:03 pm

    The controller code:
    You just have to pass a PagedList to your Viewdata like that:
    ListViewData list = new ListViewData();
    list.EntryList = EntryManager.LoadEntryCollectionByCategory(category).ToPagedList(page ?? 1);

    Hope this helps :)

  10. Paul Linton said

    am June 10 2008 @ 10:20 am

    I think that when you changed your page numbers to have a base of one rather than zero you need to change HasNextPage to be
    get { return (PageIndex * PageSize) < TotalCount; }

    Eg change <= to <

  11. Marco Castro said

    am June 30 2008 @ 4:20 am

    I’m trying with MVC Preview 3 but at the view form the system do not find ViewData.EntryList. Where is it?

  12. Robert Muehsig said

    am July 1 2008 @ 12:30 pm

    You need a strongly typed ViewData class – EntryList is just a sample property in this ViewDataClass.
    Here is a nice blogpost about strongly typed ViewData classes:
    http://blog.codeville.net/2008/02/21/aspnet-mvc-making-strongly-typed-viewpages-more-easily/

  13. Rui Heh said

    am July 1 2008 @ 5:41 pm

    Hi there, great code!!! Just want to address one small issue, when pages exceeds the default total page and next is clicked, it won’t show the next set of pages.

    Here is what I did. Hope if someone else has the same problem can make use of it.

    public int StartIndex
    {
    get
    {
    if (PageIndex > TotalPages)
    {
    return PageIndex – (PageIndex % TotalPages) + 1;
    }
    else
    return 1;
    }
    }

    and then, change the for loop to
    for (int page = ViewData.Model.StartIndex; page <= (ViewData.Model.StartIndex + ViewData.Model.TotalPages – 1); page++)

    If it is still not cleared. Email me royheh@comcast.net

  14. Jahedur Rahman said

    am July 11 2008 @ 12:38 pm

    Nice Blog. :)

  15. A Tale of Valentica » Blog Archive » Pagination Class for ASP.NET MVC said

    am August 12 2008 @ 8:13 pm

    [...] looking for a pagination class to use in Asp.Net Mvc. I found ASP.NET MVC: PagedList<T> and ASP.NET MVC – Pagination View User Control. But I felt for an easier and customizable pagination class. I have developed many projects using [...]

  16. Silverlight: a generic Pagination Control at Guardian’s Home said

    am September 8 2008 @ 6:30 pm

    [...] how to do pagination in ASP.NET MVC (http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/ and http://code-inside.de/blog-in/2008/04/08/aspnet-mvc-pagination-view-user-control/), the tecnique seemed inetersting and I decided to use it in my pager [...]

  17. gonzalo said

    am January 7 2009 @ 5:49 pm

    Hi, I’m having a hard time trying to find the RenderUserControl function.

    It’s not in HtmlHelper class

    Cheers

  18. Robert Muehsig said

    am January 7 2009 @ 5:51 pm

    The “RenderUserControl” was in the Beta 3 days – maybe it has be renamed or you can find it in the MVCFuture bits (download @ codeplex.com/aspnet ).

  19. gonzalo said

    am January 8 2009 @ 8:23 pm

    I finally found the solution. It’s called RenderPartial now. It takes the control name and ViewData as arguments.

    Thanks for answering!

    Gonzalo

  20. Craig said

    am January 9 2009 @ 5:46 pm

    PagedList can use IEnumerable instead of IQueryable (more generic). Cheers!!

  21. Craig said

    am January 9 2009 @ 9:12 pm

    Nevermind, I see the benefit of having an IQueryable ctor, but IEnumerable is still a good option to have ;-)

  22. Buona said

    am February 6 2009 @ 3:20 pm

    Love the advice. Thank you.

  23. Josh said

    am May 7 2009 @ 7:27 am

    Hello, I have a question about what my view page should inherit from. Im getting the following error:
    Parser Error Message: ‘Mvc2.Views.Shared.Pagination’ is not allowed here because it does not extend class ‘System.Web.Mvc.ViewPage’.

    Source Error:


    Line 1: <%@ Page Title="List Checkups" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Mvc2.Views.Shared.Pagination" %>
    Line 2:
    Line 3: <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

    Is there something I am leaving out? Ive added the Inherits=”Mvc2.Views.Shared.Pagination” At the top of my page, yet I still get this error. I am new to MVC. I would really like to get this working. Thanks for any help!

  24. [ASP.NET MVC] Paginazione con View User Control - Zaragon blog said

    am May 8 2009 @ 12:41 pm

    [...] 2009, under ASP.NET Ecco un utile articolo completo di codice di esempio per la creazione di un Views User Control per la paginazione. :ASP.NET, ASP.NET [...]

  25. Rob Conery’s PagedList Class (Updated) « SquaredRoot said

    am June 9 2009 @ 4:30 am

    [...] Muehsig has posted a great user control for the MVC framework that adds pagination links to the bottom of a paged list. In it he used a slightly customized version of Rob Conery’s PagedList class that Rob was [...]

  26. Nisar Khan said

    am June 30 2009 @ 9:23 pm

    can anybody post the sample downloadble code for testing? please?
    thanks.

  27. Stefano said

    am August 6 2009 @ 7:55 am

    please … link a downloadble example thanks

  28. paolo izmoto said

    am August 20 2009 @ 3:35 pm

    Hello,

    This is very useful stuff.

    Thanks.

  29. j said

    am August 29 2009 @ 8:36 am

    I’m very new to mvc.  do you have a “test” solution that you can post? thanks!

Comment RSS · TrackBack URI

Leave a comment

Name: (Required)

eMail: (Required)

Website:

Comment: