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;
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;
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:
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);
}
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 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:
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 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:
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