Using a DataPager with the GridView Control - Implementing IPageableItemContainer
One of the new controls that shipped with ASP.NET 3.5 is the DataPager. It's a flexible control that renders the paging elements data-bound controls that implement the IPageableItemContainer interface (currently only the ListView control). The big change with the DataPager is that it is decoupled from the data-bound control it provides paging support for. It can be embedded somewhere within the data-bound control's control hierarchy (like contained within the LayoutTemplate of the ListView), but it doesn't have to - It can exist on its own outside of the data-bound control as well.
When I was writing my last post, I kind of wished the 3.5 GridView implemented the IPageableItemContainer interface. It sure would have made things simpler for me. So I thought I would take a shot at extending the GridView myself. Read on for the details.
This is a pretty simple interface - 2 properties, a method and an event. But I didn't even try to implement it on my own! Instead I opened Reflector and took a peek at the ListView's implementation.
Here is the specification of the IPageableItemContainer interface.
I implemented the MaximumRows getter to return the GridView's PageSize value and had the StartRowIndex return the PageSize multiplied by the PageIndex. For the TotalRowCountAvailable event, I followed the same pattern the other controls use for declaring events. It is a little weird if you haven't seen this syntax before, but it uses less memory and is the pattern the other web controls use so I followed it.
The SetPageProperties method is only mildly more difficult (again with the help of the ListView's implementation as a reference). When the SetPageProperties method is invoked, it is passed the new startRowIndex, the new pageSize (what the DataPager refers to as maxmimumRows) and a boolean value that is true if the control needs to be rebound after the properties are set. Armed with these new values, my SetPageProperties implementation updates the GridView's PageSize and PageIndex properties and raises the PageIndexChanging and PageIndexChanged events along the way.
After the interface is implemented, the only thing that remains is figuring out when my new GridView needs to raise the TotalRowCountAvailable event. It turns out the CreateChildControls method is where the ListView control raises this event (again, figured out that using Reflector and taking a look at how the ListView control does it). So I overrode the CreateChildControls method in my new GridView class and added logic that raises the TotalRowCountAvailable event. After the event is raised, I go ahead and make sure the GridView isn't rendering the pager rows. Note: my extended GridView doesn't support the standard GridView paging rows anymore, only the DataPager is supported. This is why I have made sure the pager rows are not visible.
Is This Really All That Useful?
I think it might be. Sometime in the next year, one of the projects I am working on will be converting from ASP.NET 2.0 to 3.5. If I had to guess I would say we have somewhere around 75 or so GridViews and a ton of GridView specific code for viewing, inserting, updating and deleting records that has already been written and tested. Having the GridView implement IPageableItemContainer gives me flexibility and provides me choices when we start the migration project - I can keep all of my GridView code, but completely change the way we present our paging elements.
I am not sure if we will actually go this route, but I figured I would post it - just in case someone else can improve or make use of it.
That's it. Enjoy!
P.S I have another vacation coming up. This time I am on to Augusta to watch the Masters and then some more traveling the following week. So things will probably go quiet around here for the next few weeks.