This is one posts of an oddball problem I've run into where I feel like I 'shoulda known' but just didn't for - way too long <g>. I have a form in my West Wind Web Store with a DataGrid on it. Yeah the form is pretty old and dates back to 1.1 but I hadn't changed over because the page is inherited and has 4 different variations all with different formatting for the datagrid. It didn't seem worth the effort to switch all of these grids to GridViews at the time. So, anyway there's a DataGrid and it has a pager on it. The page is at:
On the bottom of the grid is the all too common simple list of pages that you can click on to jump through the data using hte page buttons:
At first glance everything seems to work just fine. If you click on Page 2 or 3 or 4 and you click around things are fine. If you click on the last page that shows too. However, now if you click on any other page the data grid will ALWAYS go back to page 1. Now that's freaking odd.
The grid runs without ViewState off and so I use OnPageIndex changed to trap the page change and reassign the CurrentPageIndex. The code is trivial (in a base class as there are several different page templates for this particular page that use the same logic but different layouts):
protected virtual void dgItemList_OnPageIndexChanged(object sender, DataGridPageChangedEventArgs e)
this.dgItemList.CurrentPageIndex = e.NewPageIndex;
this.ShowGrid(); // rebind data here
Nothing that you wouldn't expect here.
So I hooked up the debugger and tried to see what the heck is going on. And oddly enough I can see that the Paging event indeed fires on all the page accesses EXCEPT when the last page is active and the page is changed. So I checked the HTML a little closer and made sure the __doPostBack() links and they look fine they contain EXACTLY the same data that other requests hold.
I turned Page tracing on to see if the EventTarget is being returned to the server and it is indeed showing up:
I've stepped through all the code of the base page, the master page and the main page (which only has a couple of lines of directives) - but I can't see anything that could possibly account for the paging event not firing.
So in desperation I turned ViewState back on the page and the DataGrid and sure enough it works. But why is this happening?
What I THINK is happening is that the grid without ViewState is pointing at the pager on the last page, which has fewer items than a full page typically has. So let's say PageSize is 15 and the last page has only 5 items. So when the control count points at the pager asCtl04, it points at a position that is invalid in the new re-rendered page because it's sitting at Page 1 - IOW the Ctl ID referenced in the EventTarget isn't there anymore now. Without ViewState the pager can't keep track of that last page item because when Page 1 (or which ever other page) binds it'll have all 15 items and Ctl04 in that page is going to point at garbage - certainly not a pager.
Ouch that REALLY bites. Talk about brittle design that breaks because of the dependency of the number of items on the page!
I've never noticed this before but I suspect have a whole bunch of DataGrid pages that I have exhibit this particular behavior because I generally run with Page ViewState off and certainly turn it off for DataGrids. So I checked a few other pages that also use a DataGrid and sure enough the same behavior is occurring there as well. Bummer - time to start checking old code and fix it up.
A quick check for sanity shows that the GridView does not have this problem and it works fine for paging without ViewState. The page 'control' on the bottom of the page is not dependent on the number of items rendered on any particular page and so setting the page index does not blow up in this way. I guess it's time to update all those old DataGrids which is going to take some time for no appreciable benefit other than the fixing this bug - grumble, grumble.
Other Posts you might also like