Click here to Skip to main content
Click here to Skip to main content

ASP.NET Enhanced Grid View with Custom Pagination

By , 17 May 2009
Rate this:
Please Sign up or sign in to vote.

Introduction

The ASP.NET grid view control is good but lacks some functionalities like pagination on the database level. The control does a pagination but it's on the UI level, and in many cases we need the pagination to occur at the database level. Therefore here is this custom control which is not fully completed yet, but it does the basic  trick so far of making pagination. The great about it is that it's not using any third party pagination controls. It uses the same control embedded within the grid view to do the whole work!

The Simple Idea of Pagination

To do pagination, you always need to have 3 factors: Index, PageSize, and Total Records. Index and Size are taken from the UI but Total Records are returned after making the pagination process on the database level. For example: I am querying employees on the database, all employees records stored about 455 records. I query the database for only 10 records and I specify which 10 records the database will get me. I am not going to explain the pagination mechanisms at the database level, I will only assume that 10 records are returned and the Total Records is equal to 455.

So when the results are returned, I should inform the EGridView of : Total Records = 10, and EmployeeCollection of records, the GridView already has PageIndex and PageSize.

What ASP.NET GridView Already Has ?

Now let's take a look at the properties that ASP.NET original GridView control is offering. Of course some of the properties are related to the datasource within the grid view but we are talking in general about the features the grid view has:

  • PageIndex: This property holds the index, but unfortunately it's used by the internal mechanism of UI pagination the control has, therefore we will not use it and use another one instead.
  • PageSize: This property holds the size we desire, so we can use this property fine since it's fixed most of the time (unless you wanted to change it at runtime which is fine too).

Now there are other properties within the grid view, but they are protected and can't be seen outside the GridView control. The important ones are:

  • VirtualCount: This holds the total number of records that the pagination is going to page, previously mentioned in my article or equivalent to TotalRecords, internally with the GridView Control, it gets its value from the number of entities within the bounded Collection (because it's UI level pagination) and you can't set this value or control outside to make your pagination.
  • CurrentPageIndex: This property is actually exposed as PageIndex, but I mentioned it because it's the real controller of the value since it's actually a property of the PagedDataSource instance within the GridView control.

Adding Two New Properties

So far, we have PageSize and we can use it but the other two members PageIndex and TotalRecords are not yet there, so we are going to add them to our EGridView, simply to hold their data and persistence we are going to use the view state. Below is the implementation of the two properties we want:

private Nullable<int> customPageIndex;
/// <summary>
/// Use CustomPageIndex instead of PageIndex for Pagination out of the grid
/// </summary>
public int CustomPageIndex
{
get
{ 
if (customPageIndex == null)
{
if (ViewState["CustomPageIndex"] == null)
CustomPageIndex = PageIndex;
else
{
CustomPageIndex = (int)ViewState["CustomPageIndex"];
}
}
return customPageIndex.Value;
}
set
{
customPageIndex = value;
ViewState["CustomPageIndex"] = value;
}
}
 
private Nullable<int> totalRecords;
/// <summary>
/// Gets or Sets the Total Records for pagination, 
/// its important to set the value of Total 
/// Records BEFORE binding the data to the grid. 
/// </summary>
public int TotalRecords
{
get
{
if (totalRecords == null)
{
if (ViewState["TotalRecords"] == null)
TotalRecords = PageIndex;
else
{
TotalRecords = (int)ViewState["TotalRecords"];
}
}
return totalRecords.Value;
}
set
{
totalRecords = value; 
ViewState["TotalRecords"] = value; 
}
}

Overriding Two Methods in the GridView

Now after we know the public and internal features, the grid view is offering for pagination. Let's come to coding, here I made it as simple as possible only two overrides we have to overcome the original UI pagination and replace our own: InitializePager and OnPageIndexChanged. Find the code for them below:

/// <summary>
/// Override it in order to set the value of VirtualCount and CurrentPageIndex
/// </summary>
/// <param name="row"></param>
/// <param name="columnSpan"></param>
/// <param name="pagedDataSource"></param>
protected override void InitializePager(GridViewRow row, int columnSpan, 
	PagedDataSource pagedDataSource)
{
if (pagedDataSource.IsPagingEnabled && (TotalRecords != pagedDataSource.VirtualCount))
{
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = TotalRecords;
pagedDataSource.CurrentPageIndex = CustomPageIndex; 
}

base.InitializePager(row, columnSpan, pagedDataSource); 
}
 
/// <summary>
/// Override it to avoid the popup message of not handling this event and 
/// to reset the selected index again.
/// </summary>
/// <param name="e"></param>
protected override void OnPageIndexChanging(GridViewPageEventArgs e)
{
//base.OnPageIndexChanging(e);
this.CustomPageIndex = e.NewPageIndex;
this.SelectedIndex = -1;
}

Now using the control is easy and we are all familiar with it. In ASP.NET you specify the PageSize and AllowPaging=true, and implement the event OnPageIndexChanged. Nothing new about all this in ASP.NET and in the page codebehind file, you use CustomPageIndex, PageSize and TotalRecords properties to make your pagination.

Points of Interest

Now there is an interesting point in the pagination mechanism that we should be aware of. When we are binding the returned Collection and TotalRecords from the database to the EGridView control, you should be careful to set the TotalRecords property before binding to the EGridView. An example is as follows:

//Correct using of binding to get the pagination
grdView.TotalRecords = AllEmployeesCount; // AllEmployeesCount of Type Int
grdView.DataSource = employees;// employees is a collection (just an example)
grdView.DataBind();

Now if you mistakenly make the binding, then set the TotalRecords property. There is no pagination that will occur since the Binding uses the value of VirtualCount which is set using our custom property TotalRecords.

Now in order to use the Custom Control, you have two options: either you put it in an assembly then use it, or put it in the AppCode folder of your web application and use it from there.

I will explain how to do the second one only. It is as follows:

  • Give it a simple namespace like CustomControls:
    namespace CustomControls
    {
    /// <summary>
    /// EGridView with tuned functionality to enable the manipulation 
    /// of Grid Pagination Control
    /// </summary>
    public class EGridView : GridView
    {...} 
  • Add the following lines in your web.config file in order to define the EGridView as a control to be seen in your design time pages:
    <system.web>
    <pages>
    <controls>
    ...
    <add tagPrefix="CC" namespace="CustomControls"/> 
    ...
    </controls>

Above we gave all controls within the namespace CustomControls a tag prefix for us to use in our ASP.NET pages.

And that's it!

Finally

I would like to say that this control is still under progress to be enhanced more and more. One idea is to inject a small text box between page numbers to specify the page number we want instead of moving 10 pages. I have a lot of other ideas, but they are still under progress and unfortunately, I don't currently have enough time to do them, but hopefully I will be able to do them in the future.

So any bug reports or ideas are welcome to be taken into consideration for its enhancement.

History

  • 17th May, 2009: Initial post

License

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

About the Author

Samer Abu Rabie
Engineer C4 Advanced Solutions
Jordan Jordan
Samer is a Computer and Digital Electronics Engineer who lives in Jordan, worked on a fair number of personal projects as part of fun or freelancing, mostly related to integration between hardware and software (e.g Security Systems, Sensors, Cameras, Bluetooth ... etc), which gave him a powerful knowledge in this area and the ability to invent various complex designs to adhere for external elements effect those systems.
 
Through his career path he worked on a fair number of enterprise projects with well known software companies, which showed him the various aspects of an enterprise applications.
 
You may contact Samer through his e-mail:SamerX@outlook.com or Messenger (IM) through SamerX@outlook.com as well.
Follow on   Twitter   LinkedIn

Comments and Discussions

 
GeneralMy vote of 4 PinmemberMember 330448410-Feb-11 0:29 
GeneralRe: My vote of 4 PinmemberMember 330448410-Feb-11 1:12 
GeneralMy vote of 1 Pinmembershakesperoo3@hotmail.com19-Oct-10 23:12 
GeneralA7eeeeeeeeeeeeeeeeeeee Pinmembershakesperoo3@hotmail.com19-Oct-10 23:11 
GeneralRe: A7eeeeeeeeeeeeeeeeeeee PinmemberSamer Abu Rabie20-Oct-10 1:26 
GeneralMy vote of 5 Pinmemberhansderks5-Aug-10 22:54 
QuestionGreat idea, but I can't get it to work...what am I doing wrong? Pinmemberdesertfoxaz19-May-09 12:40 
AnswerRe: Great idea, but I can't get it to work...what am I doing wrong? Pinmemberdesertfoxaz19-May-09 12:50 
Is there any reason why the line base.OnPageIndexChanging(e) is commented out in the OnPageIndexChanging event handler? I uncommented it and now the PageIndexChanging event in the page now gets executed, and I can see the pages of data change, but the pager still shows that the first page is selected, even though the data I see is not the first page.
 
I reordered the code in the OnPageIndexChanging event of your code to this:
 

protected override void OnPageIndexChanging(GridViewPageEventArgs e)
{
this.CustomPageIndex = e.NewPageIndex;
this.SelectedIndex = -1;
base.OnPageIndexChanging(e);
}
 
Now it appears to work!
 
Now I need to figure out why the event handler for the SelectedIndexChanging event doesn't work -- same thing, event handler doesn't get executed and grid disappears. Any ideas?

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 17 May 2009
Article Copyright 2009 by Samer Abu Rabie
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid