Update: Recreated the code completely. Now it has both PageIndex and ItemCount.
Also: Actually there is a way to get only the rows that you need in SQL Server 2005. It is a function called Row_Number and that returns the index number of a row based on a certain ordering. Then you can easily filter by it to take items from 20 to 30, for example. In this case, another interesting property of the PagedDataSource is CurrentPageIndex, to set the displayed page number in the pager.
Now, for the actual blog entry.
Why would anyone want to change the PageCount, you ask? Well, assume you have a big big table, like hundreds of thousands of rows, and you want to page it. First you must put it in a DataTable from the SQL server, so that takes time, then the table set a datasource to the GridView, then it implements the paging.
Wouldn't it be nicer to only get the data that you need from the SQL Server, then change the PageCount to show the exact page count that should have been? However, the PageCount property of the GridView is read-only. One quick solution is to get only the data you need, then fill the resulting DataTable with empty rows until you get the real row count. However, adding empty rows to DataTables is excruciatingly slow, so you don't really gain anything, and the Grid works with a big table anyway.
So this is what you do:
First of all determine how much of the data to gather.
Afterwards you need to trick the GridView into creating a Pager that shows the real row count (and possibly page index). Unfortunately you can't do this from outside the GridView. You need to inherit the GridView control and add your stuff inside. After you do this, you need to override the InitializePager method, which is just about the only protected virtual thing related to Paging that you can find in the GridView.
public class MockPagerGrid : GridView
private int? _mockItemCount;
private int? _mockPageIndex;
/// Set it to fool the pager item Count
public int MockItemCount
if (_mockItemCount == null)
if (ViewState["MockItemCount"] == null)
MockItemCount = Rows.Count;
MockItemCount = (int) ViewState["MockItemCount"];
_mockItemCount = value;
ViewState["MockItemCount"] = value;
/// Set it to fool the pager page index
public int MockPageIndex
if (_mockPageIndex == null)
if (ViewState["MockPageIndex"] == null)
MockPageIndex = PageIndex;
MockPageIndex = (int) ViewState["MockPageIndex"];
_mockPageIndex = value;
ViewState["MockPageIndex"] = value;
///Initializes the pager row displayed when the paging feature is enabled.
///<param name="columnSpan">The number of columns the pager row should span. </param>
///<param name="row">A <see cref="T:System.Web.UI.WebControls.GridViewRow"></see> that represents the pager row to initialize. </param>
///<param name="pagedDataSource">A <see cref="T:System.Web.UI.WebControls.PagedDataSource"></see> that represents the data source. </param>
protected override void InitializePager(GridViewRow row, int columnSpan, PagedDataSource pagedDataSource)
if (pagedDataSource.IsPagingEnabled && (MockItemCount != pagedDataSource.VirtualCount))
pagedDataSource.AllowCustomPaging = true;
pagedDataSource.VirtualCount = MockItemCount;
pagedDataSource.CurrentPageIndex = MockPageIndex;
base.InitializePager(row, columnSpan, pagedDataSource);
protected override int CreateChildControls
(System.Collections.IEnumerable dataSource, bool dataBinding)
PageIndex = MockPageIndex;
return base.CreateChildControls(dataSource, dataBinding);
What, what, whaaat? What is a PagedDataSource? Inside the GridView, the paging is done with a PagedDataSource, a wrapper around a normal DataSource, which has some of the GridView paging properties like PageSize, PageCount, etc. Even if the PageCount is also a read-only property, you have the AllowCustomPaging property and then the VirtualCount and CurrentPageIndex properties that you can set.
In other words: the pager is initialized at databinding. Set MockItemCount and MockPageIndex before MockPagerGrid.DataBind();
Update: People keep asking me to provide a code sample. Let's try together. First, let's see a classic GridView use example:
As you can see, we provide a data source programatically, then set the pageindex (let's assume we took it from the URL string) and then call DataBind(). In this situation, we would load the entire data source (say, 10000 rows) then give it to the grid, which would only render something like 20 rows. Very inefficient.
Now, let's replace the original GridView control with the with MockPagerGrid. The code would look like this:
This gets the rows for the second page, sets the mock ItemCount and PageIndex to the total number of rows and the page we want and then calls DataBind(). In this situation getDataSource would load only the 20 rows of page 2, would display it, then the pager would show that it is on page 2 out of 500.
This is a very simple example. It assumes you already know the total number of rows returned. A more complete example would look like this:
// starting with an arbitrary page index
// do operations on the database that would return the rows for the page
// with that index, having the size of the page size of the grid
// and also get the total number of rows in the data source
// set the returned rows as the data source
// set the page index
// set the total row count
// CustomDataSource would only have two properties: Rows and TotalRowCount
// The sql for getDataSource(index,size) would be something like
// SELECT COUNT(*) FROM MyTable -- get the total count
// SELECT * FROM MyTable WHERE RowIndex>=@index*@size
// AND RowIndex<(@index+1)*@size
// for convenience, I assumed that there is a column called RowIndex in
// the table that is set to the row index
Hopefully, this will help people use this code.