Introduction
If you need table paging functionality, the GridView's PagerBar does a pretty good job for you. Actually, a single click on the AllowPaging
property will adorn your table with a nice and fully functional numeric pager. Another click on Pager Settings -> Mode and your pager can change the look 3 times. You don't like any of those looks? Right click the grid, select Edit Template -> PagerTemplate and you are on your own. The problem is that once you template the pager, all of the nice PagerBar functionality is gone. No more clickable page numbers or previous/next buttons; you have to redo them in your template manually.
In this article, we will extend the PagerBar while preserving its functionality. We will add a drop-down that will enable page size changes, the number of rows displayed in one page. This example is simple enough to demonstrate the method and yet it is demanding. Besides extending the look of the PagerBar, we will also have to enable and handle the drop-down's AutoPostback
event.
Background
This work was inspired by a post of Phillip Williams' that can be found here. He recommended using the GridView RowCreated
event to add a link control to the PagerBar. Very useful information about paging in GridView control can be found in the well-written paper, "Custom Paging in GridView Control" by Francisco Santos Jr.
How we do it
The RowCreated
event is raised for each row created in the GridView control. We are interested in the pager row only, so we ignore all other rows. We still do this inside a shared method of our class in order to simplify the code at the user side (and have him pay for the convenience with a few CPU cycles).
If gridRow.RowType <> DataControlRowType.Pager Then Return
Before we insert the page size selector into the PagerBar, we have to make sure that the PagerBar is visible even if the whole table has fewer rows than the current page size. Otherwise, the user will not be able to make the page size smaller. We are currently handling the RowCreated
event. As it is too early in the control's life to handle PagerBar visibility, we therefore have to subscribe to the PreRender event of the grid:
Dim enoughRows As Boolean = ( grid.Rows.Count >= MINIMAL_PAGE_SIZE )
If enoughRows Then
AddHandler grid.PreRender,
New EventHandler( AddressOf MakeSurePagerIsVisible)
End If
Once we've grabbed the grid PreRender
event, we have to pay attention to the Position settings of the GridView pager. This is because the visibility of the TopPagerRow and BottomPagerRow are handled in GridView independently:
Private Shared Sub MakeSurePagerIsVisible(ByVal sender As Object,
ByVal e As System.EventArgs)
Dim grid As GridView = sender
Select Case grid.PagerSettings.Position
Case PagerPosition.Bottom
grid.BottomPagerRow.Visible = True
Case PagerPosition.Top
grid.TopPagerRow.Visible = True
Case PagerPosition.TopAndBottom
grid.BottomPagerRow.Visible = True
grid.TopPagerRow.Visible = True
End Select
End Sub
Finally, we can add the page size selection drop-down to the pager. A look into the rendered HTML tells us the pager is a table structure that we have to navigate in order to insert a cell at the end of the row. The table cell with the page size selector is created in the CreateSizer
function. Once we are in it, we add a label to describe the DropDown
. We should not forget to enable AutoPostBack
and to signup for the TextChanged
event:
sel.AutoPostBack = True
AddHandler sel.TextChanged,
New EventHandler( AddressOf PageSizeSelector_Clicked)
Navigation in the pager table happens in the GetPagerTableRow
function. This is the code that depends on the way the pager is rendered. This is dangerous because Microsoft might change the way the pager is rendered and then our code would break. Moreover, it hinders our code working with a templated pager if the template does not mimic the generated table structure. Alas, all of those improvements are left to you, dear reader.
The selected page size is stored in a cookie with a unique name that contains the page and control names. Therefore the page and the site can have multiple grids with page length controlled, and all of them can act independently.
Using the code
- Add the
GridViewPageSize
class to your project. A good place to put it is the App_Code folder. - Import the
Bsp.Software
namespace into your code behind the page with the GridView:
Imports Bsp.Software
- (Optional) Set the page size from the cookie, if available:
Protected Sub GridView_Load(ByVal sender As Object,
ByVal e As System.EventArgs) _
Handles GridView1.Load, GridView2.Load
Dim gv As Control = sender
If Not gv.Page.IsPostBack Then
GridViewPageSize.SetPageSize(Me, sender)
End If
End Sub
- Insert the
PageSize
selector into the pager at the RowCreated
event:
Protected Sub GridView_RowCreated(ByVal sender As Object,
ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
Handles GridView1.RowCreated, GridView2.RowCreated
GridViewPageSize.AddSizerToGridPager(sender, e.Row)
End Sub
History
- 20 June, 2007: The code and this paper were created and submitted for the CodeProject review.
- 21 June, 2007: The code was improved thanks to Phillip Williams. The original version did not handle situations when the page refresh event occurred right after the GridView page size changed. The complete
PageSizeSelector_Clicked
should be re-executed even when the cookie created during the preceding post-back already exists.