The .NET Framework simplifies the process of displaying data on a Web page thanks to the DataGrid server control. But although the control is easier to use than its "classic" ASP predecessor, implementing some of its more advanced capabilities can still be tricky. In a previous article, I showed you how to delete a record from a DataGrid and its underlying database. Now, I will take that a step further and show you what happens when you try to put deleting and paging in the same room and make them "play nice."
Using built-in event placeholders
The secret to getting all of our new event friends to work together is to tie the Delete button's command processing to the built-in DeleteCommand event. At first, I thought that this event was tied to processing commands in an editable DataGrid, but I later discovered that the DeleteCommand event is only a placeholder event and is not tied to any internal delete processing. Therefore, you can use it to wire up and process your custom delete event.
To start the process, change the LinkButton’s CommandName to Delete and add an OnDeleteCommand attribute to the <asp:datagrid> tag. These changes are shown in Listing A. Switch to the codebehind and make the changes shown in Listing B. Then compile and run the page. You will see that now the delete processing no longer relies on the ItemCommand event, clearing the way for the PageIndexChanged event to be processed.
To enable our pager to function properly, we need to handle the PageIndexChanged event and add some code. I found this part fairly perplexing. In my opinion, the DataGrid should handle this intrinsically because the code does not ever change from one situation to the next. Since Microsoft calls it "built-in" paging, the handler to change the page when the “built-in” pager is clicked should be built in as well. In a future article, I will explain how to encapsulate this functionality in a custom DataGrid control. For now, the workaround is fairly simple. Add the code in Listing C to process the event and wire up your pager.
Take a look at the parameters for the routine. When you deal with built-in events for the Framework, the event handler will typically require two arguments: sender and e. The sender argument is the value of the object that called the routine, and e is an instance or derivative of the EventArgs class that contains the extra information about the event that the handler may need to play with. In this case, e contains everything you need to change the Grid’s current page.
Just when you think you're finished…
At this point, our DataGrid is complete. Compile and execute the page, and you will see that everything works. Click back and forth between the pages, and you should see the changes execute properly. Now, jump to the last page, and start deleting every record on the page. When you delete the last row on the page, watch what happens.
You should receive a PageIndex error. I spent hours testing code, working with ideas, and experimenting with solutions to this problem, but to no avail. After a brief break, what I came up with was so simple that I kicked myself for not thinking of it sooner. Further, I was extremely surprised that there weren’t any resources that discussed it (a primary motivation for this article).
A little unconventional wisdom
Conventional development wisdom says that any page-change operation should execute after the item is deleted and the data is rebound to the Grid. For reasons I don’t fully understand yet, this is not the case here. My contacts at Microsoft were not able to give me an explanation for it. To solve the problem, you have to check the page count before you delete the data. In the last snippet of code in Listing D, the DeleteCommand event handler is updated.
Up to this point, I think the code has been fairly self-explanatory, and I've assumed that you can see what is going on and why it works that way without a whole lot of jabbering from me. But I want to be very specific about what is going on now, so that you can fully understand the solution and how simple it is. First, you want to see how many items are on the last page. To do this, you use the Mod operator on the Item Count and the Page Size. Since the Mod operator returns only the remainder, you won’t have any excess data to deal with. If there is only one item left on the page, the placeholder variable Result will equal 1.
Because the CurrentPageIndex property of the DataGrid is a zero-based index, and the PageCount property is a 1-based index, you have to subtract 2 from the page count to move backward a page after the delete, not just 1. This fact is not well documented, and I wasted more than an hour trying to figure out why subtracting 1 didn’t work. It wasn’t until a fellow moderator in the DataGrid forums on www.asp.net informed me of the index base differences that I figured it out.
Wrapping it up
Once you've ironed out a few wrinkles, the process of combining paging and deleting functionality in a Grid is relatively straightforward: You change the page index before you delete the data and then you delete the data, grab it again, rebind it, and display it. Compile your page again and delete every item on the last page again. This time, after you confirm the delete, the page will jump back one, to the new last page of data.