Click here to Skip to main content
15,888,351 members
Articles / Programming Languages / C#
Tip/Trick

C# paging helper class

Rate me:
Please Sign up or sign in to vote.
2.00/5 (1 vote)
7 Jan 2012CPOL 33.6K   7   5
It's common to extract a single page from a set of records. This utility simplifies the maths involved.

A common way to extract a page from a set of records by checking whether the index of that record is between the index of the first and last items on that page.


While not difficult to do it's easy to accidentally get wrong, if you don't crunch the numbers properly.


This PagingLocation class allows a paging location to be set (like a set of co-ordinates) and then passed to the data access tier to tell it which page to extract.


It includes an IsInPage(int) function which will tell you if the index you provide is within the specified page.


It also has an AbsoluteTotal property which holds the total number of items found in all pages. This is used by the UI to calculate how many pages to let the user choose from.


Here's a crude example of how it's used:


C#
void Page_Load(object sender, EventArgs e)
{
  int pageIndex = 2;
  int pageSize = 10;
  PagingLocation location = new PagingLocation(pageIndex, pageSize);

  ArrayList page = GetPage(location);

  grid.DataSource = page;
  grid.VirtualItemCount = location.AbsoluteTotal;
  grid.DataBind();
}

ArrayList GetPage(PagingLocation location)
{
  ArrayList list = GetAllData();

  location.AbsoluteTotal = list.Count;

  for (int i = 0; i < list.Count; i++)
  {
    if (location.IsInPage(i))
        page.Add(list[i]);
  }
}

Here's a real world example of it being used by a data access component:


C#
protected virtual IEntity[] GetPage(IObjectSet objectSet, PagingLocation location)
{
    int i = 0;
    
    List<IEntity> list = new List<IEntity>();
    
    // Loop through each index in the object set
    for (i = 0; i < objectSet.Count; i++)
    {
        // If it's not in the current page then skip it
        if (location.IsInPage(i))
        {
            // Add the entity to the collection
            list.Add((IEntity)objectSet[i]);
        }
    }
    
    location.AbsoluteTotal = i;
    
    return list.ToArray();
}

http://code.google.com/p/sitestarter/source/browse/trunk/Src/App/SoftwareMonkeys.SiteStarter.Data.Db4o/Db4oDataIndexer.cs#791[^]


Here's the PagingLocation class (with the logging code removed):


C#
using System;
using SoftwareMonkeys.SiteStarter.Diagnostics;

namespace SoftwareMonkeys.SiteStarter.Entities
{
    /// <summary>
    /// Holds the coordinates to a specific page on an index.
    /// </summary>
    public class PagingLocation : IPagingLocation
    {
        private int pageIndex;
        /// <summary>
        /// Gets/sets the current page index.
        /// Note: This is 0 based so PageIndex=(PageNumber-1)
        /// </summary>
        public int PageIndex    
        {
            get { return pageIndex; }
            set { pageIndex = value; }
        }
       
        private int pageSize;
        /// <summary>
        /// Gets/sets the size of each page.
        /// </summary>
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; }
        }
       
        private int absoluteTotal;
        /// <summary>
        /// Gets/sets the absolute total count of all matching items,
        /// including those on ALL pages, not just the specified one.
        /// </summary>
        public int AbsoluteTotal
        {
            get { return absoluteTotal; }
            set { absoluteTotal = value; }
        }
       
        /// <summary>
        /// Empty constructor.
        /// </summary>
        public PagingLocation()
        {
        }
               
        /// <summary>
        /// Sets the page index and page size of the current location.
        /// </summary>
        /// <param name="pageIndex">The index of the current page.</param>
        /// <param name="pageSize">The size of each page.</param>
        public PagingLocation(int pageIndex, int pageSize)
        {
                PageIndex = pageIndex;
                PageSize = pageSize;
        }
       
       
        /// <summary>
        /// Checks whether the specified position is within the specified page.
        /// </summary>
        /// <param name="i">The 0 based index of item to check.</param>
        /// <returns>A bool value indicating whether the specified
        ///   index position is within the specified page.</returns>
        public bool IsInPage(int i)
        {
                // Create the return flag
                bool isInPage = false;
                   
                // Calculate the position of the first item on the page
                int first = (pageIndex * pageSize); // 0 based
               
                // Calculate the position of the last item on the page
                int last = ((pageIndex * pageSize) + pageSize) -1;
                // -1 to make it the last of the page, instead of first item on next page
               
               
                // The position is in the current page if it is between or equal
                // to the first and last items on the page
                isInPage = i >= first
                        && i <= last;
     
                return isInPage;
        }
    }
}

http://code.google.com/p/sitestarter/source/browse/trunk/Src/App/SoftwareMonkeys.SiteStarter.Entities/PagingLocation.cs[^]


To ensure it works properly here are a bunch of unit tests: http://code.google.com/p/sitestarter/source/browse/trunk/Src/App/SoftwareMonkeys.SiteStarter.Entities.Tests/PagingLocationTests.cs[^]

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
SoftwareMonkeys
Australia Australia
Founder of www.softwaremonkeys.net

Comments and Discussions

 
GeneralRe: Good tip. Now I'm creating a RavenDB provider for the data m... Pin
SoftwareMonkeys19-Jan-12 22:18
SoftwareMonkeys19-Jan-12 22:18 
GeneralRe: Use the System.Linq library. Then you can turn this: ... Pin
James Hurburgh11-Jan-12 18:27
James Hurburgh11-Jan-12 18:27 
GeneralReason for my vote of 2 There are much simpler and more obvi... Pin
James Hurburgh9-Jan-12 19:50
James Hurburgh9-Jan-12 19:50 
GeneralRe: My mistake I figured it was all fairly self explanatory so I... Pin
SoftwareMonkeys9-Jan-12 23:52
SoftwareMonkeys9-Jan-12 23:52 
Generalthis is all I can say: http://i0.kym-cdn.com/photos/images/o... Pin
Seishin#8-Jan-12 1:44
Seishin#8-Jan-12 1:44 
this is all I can say: http://i0.kym-cdn.com/photos/images/original/000/126/314/3cd8a33a.png?1306264975

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.