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
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
Adding Two New Properties
So far, we have
PageSize and we can use it but the other two members
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;
public int CustomPageIndex
if (customPageIndex == null)
if (ViewState["CustomPageIndex"] == null)
CustomPageIndex = PageIndex;
CustomPageIndex = (int)ViewState["CustomPageIndex"];
customPageIndex = value;
ViewState["CustomPageIndex"] = value;
private Nullable<int> totalRecords;
public int TotalRecords
if (totalRecords == null)
if (ViewState["TotalRecords"] == null)
TotalRecords = PageIndex;
TotalRecords = (int)ViewState["TotalRecords"];
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:
OnPageIndexChanged. Find the code for them below:
protected override void InitializePager(GridViewRow row, int columnSpan,
if (pagedDataSource.IsPagingEnabled && (TotalRecords != pagedDataSource.VirtualCount))
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = TotalRecords;
pagedDataSource.CurrentPageIndex = CustomPageIndex;
base.InitializePager(row, columnSpan, pagedDataSource);
protected override void OnPageIndexChanging(GridViewPageEventArgs 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
AllowPaging=true, and implement the event
OnPageIndexChanged. Nothing new about all this in ASP.NET and in the page codebehind file, you use
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
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:
grdView.TotalRecords = AllEmployeesCount; grdView.DataSource = employees;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
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:
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!
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.
- 17th May, 2009: Initial post