Scott on Writing

Musings on technical writing...

Deleting the Last Record on the Last Page from a GridView with Custom Paging

In working on my upcoming Data Tutorials for MSDN, alert coder Amrinder S. wrote in voicing the following concern:

I have been waiting for tutorials showing how to do custom paging with the GridView. So up until now, I have been using the old DataGrid.

One thing that I noticed when I was working with the code is an issue with deleting and paging. Say for example, the GridView has 12 rows and Page Size is set to 10. If the user goes to Page 2 and deletes the two rows, the Grid will disappear from the page. After searching around I found the solution. An Deleted event handler has to be added to the ObjectDataSource control and the following line has to be added: e.AffectedRows = (int)e.ReturnValue;

The problem Amrinder unearthed has to do when implementing custom paging in a GridView using an ObjectDataSource that also supports deleting. The GridView provides two flavors of paging - custom paging and default paging. Default paging is the default paging implementation model and can be implemented by simply setting the GridView's AllowPaging property to True. While default paging is a breeze to implement, it's very inefficient since for each page of data being viewed, all of the database records are returned (even though only a potentially small subset of them are displayed to the end user). Custom paging solves this inefficiency, but requires that the page developer be able to grab the precise subset of records to display. See Custom Paging in ASP.NET 2.0 with SQL Server 2005 for more information and details on the differences between default and custom paging and for specifics on implementing custom paging...

As Amrinder points out, when deleting the last record from the last page of a GridView using custom paging, the GridView disappears, even if there are additional records in preceding pages. (This is not a problem with default paging however, as deleting the last record from the last page returns leaves you at the new last page.) This custom paging / deleting the last record in the last page thing can be fixed by simply creating a Deleted event handler for the ObjectDataSource and manually setting e.AffectedRows to some value greater than 0 (assuming the delete operation succeeded).

What in the world is the issue here?

I wondered the same thing myself and decided to find out exactly why this oddity occurs. Firing up Reflector I started digging through System.Web.... and here's what I found!

When the end user clicks the Delete button for a row, a postback occurs and the following sequence of steps transpire:

  1. The GridView tells its ObjectDataSource to go ahead and delete the record whose Delete button was clicked
    1. The ObjectDataSource invokes the Delete method
    2. The ObjectDataSource returns information about the operation just performed via an ObjectDataSourceEventArgs instance. This class contains an AffectedRows property that indicates how many records were affected by the operation. However, the ObjectDataSource does not set the AffectedRows property, though, meaning that a value of -1 is returned for this property
  2. The GridView runs a method after the delete completes. In this post-action method, it does two important things: first, if the AffectedRows value from the delete operation is greater than 0 it checks to see if the record deleted was the last record on the page. If so, it decrements the GridView's PageIndex property; regardless of the AffectedRows value, this post-action method sets the RequiresDataBinding property to True, which means that the data will be rebound to the GridView in the PreRender stage of the page lifecycle.
  3. In the PreRender stage, when it's determined that the GridView needs to be rebound, the data is re-retrieved from the data source
  4. The GridView is then rebound to the data. In its CreateChildControls method, the GridView checks to see if its PageIndex property is too large (i.e., if it's greater than the total number of pages provided by the data source). If so, the PageIndex property is decremented and then the data retrieved in Step 3 is bound to the grid.

The reason the GridView disappears after deleting the last record of the last page when using custom paging is because the ObjectDataSource fails to indicate that any rows were affected. Therefore, the GridView's PageIndex property is not updated until Step 4. That means that in Step 3, when the GridView re-retrieves the data, it's asking for the page of data whose last record was just deleted in Step 1! Namely, no data is coming back. Therefore, even though the PageIndex is decremented in Step 4, it's too late, as the data being bound to the GridView has already been retrieved and its empty.

To fix this problem we need to make sure that the PageIndex is updated BEFORE Step 3. This can be accomplished using either one of the following two approaches:

  • Manually set the e.AffectedRows property in the ObjectDataSource's Deleted event handler. Of course, only do so if the delete operation succeeded.
  • In the GridView's RowDeleted event handler, update the GridView's PageIndex if the delete occurred for a page of data that has only one record (namely, we just deleted the last record of the page). Again, you want to only do this if the delete actually succeeded. This can be accomplished using the following code:

protected void GridView1_RowDeleted(object sender, GridViewDeletedEventArgs e)
{
    // If we just deleted the last row in the GridView, decrement the PageIndex
    if (e.Exception == null && GridView1.Rows.Count == 1)
        // we just deleted the last row
        GridView1.PageIndex = Math.Max(0, GridView1.PageIndex - 1);
}

This latter technique is similar to the technique that must be used in ASP.NET 1.x when deleting from a pageable DataGrid...

It's unfortunate that this bug made its way out into production, but so it goes. At least there's a not-too-painful workaround. And the lesson to take away from this blog entry - Reflector is your friend. :-)

posted on Tuesday, May 30, 2006 5:36 PM

Feedback

# re: Deleting the Last Record on the Last Page from a GridView with Custom Paging 5/31/2006 2:20 PM AsbjørnM

Is MS informed about this so it will be fixed in sp1?

# re: Deleting the Last Record on the Last Page from a GridView with Custom Paging 5/31/2006 3:00 PM Scott Mitchell

Scott Guthrie knows about it, so I assume MS knows about it. But whether or not it's officially slated to be fixed in the next SP... beats me.

# re: Deleting the Last Record on the Last Page from a GridView with Custom Paging 6/3/2006 2:31 PM Manuel Abadia

Scott,

I also found this annoying behaviour of the GridView and posted about it:

http://www.manuelabadia.com/blog/PermaLink,guid,eaa3eed8-f997-43c4-8c30-78c2f72d0c86.aspx

At the end of the post I pointed out another GridView bug that is more complex to reproduce.

I hope both bugs will be fixed in SP1.

# re: Deleting the Last Record on the Last Page from a GridView with Custom Paging 6/13/2006 1:46 PM Michael

How about the records deleted by other webuser?
Step 1:
Webuser1: open the page and have 3 pages
Webuser2: open the page and have 3 pages
Step 2:
Webuser2: delete all records in third page.
Step 3:
Webuser1: click on the 3rd page, gets blank.

How to fix this?

# Scott Mitchell 的ASP.NET 2.0数据教程之二十五:: 大数据量时提高分页的效率 11/23/2006 5:25 AM ISFcn

??:????: Scott Mitchell,????ASP/ASP.NET????,?4GuysFromRolla.com????,?1998??????? ??Web???Scott???????????,???,??,???????Sams????????,24?????ASP.NET 2.0????????mitchell@4guysfromrolla.com,?????????http://ScottOnWriting.NET?????

# Scott Mitchell 的ASP.NET 2.0数据教程之二十五:: 大数据量时提高分页的效率 3/26/2007 9:51 AM heker2007

????

# 执行自定义分页和删除的bug解决 4/10/2007 10:41 PM baikangwang

????????Delete?,GridView??????????:

1. ????.
2. ?????PageIndex?PageSize????.
3. ??PageIndex??????????????.???,GridView?PageIndex????.
4. ?????????????GridView????.

Title:  
Name:  
Url:
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments   

Add To Your Reader

My Links

Archives

Post Categories

 

I am a Microsoft MVP for ASP.NET.
I am an ASPInsider.
<May 2008>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Comment Stats

DayTotal% of Total
Sunday 1866.8%
Monday 37913.9%
Tuesday 45316.7%
Wednesday 50418.5%
Thursday 53519.7%
Friday 49418.2%
Saturday 1666.1%
Total 2717100.0%

Hour1Total% of Total
12:00 AM 652.4%
1:00 AM 682.5%
2:00 AM 622.3%
3:00 AM 742.7%
4:00 AM 572.1%
5:00 AM 1033.8%
6:00 AM 1084.0%
7:00 AM 1585.8%
8:00 AM 1716.3%
9:00 AM 1475.4%
10:00 AM 1716.3%
11:00 AM 1816.7%
12:00 PM 1886.9%
1:00 PM 1696.2%
2:00 PM 1605.9%
3:00 PM 1324.9%
4:00 PM 1073.9%
5:00 PM 923.4%
6:00 PM 913.3%
7:00 PM 963.5%
8:00 PM 833.1%
9:00 PM 782.9%
10:00 PM 792.9%
11:00 PM 772.8%
Total 2717100.0%

Comments by Blog Entry Date/Time

Day Entry MadeAvg.Total
Sunday 5.54144
Monday 5.22339
Tuesday 4.28419
Wednesday 7.67637
Thursday 6.90607
Friday 5.48411
Saturday 5.33160
Total 5.842717

Hour1 Entry MadeAvg.Total
12:00 AM 5.0035
1:00 AM 1.002
5:00 AM 0.000
7:00 AM 7.0035
8:00 AM 5.35107
9:00 AM 6.32278
10:00 AM 6.47246
11:00 AM 4.41181
12:00 PM 6.88330
1:00 PM 3.00111
2:00 PM 5.41222
3:00 PM 8.64285
4:00 PM 4.0589
5:00 PM 5.92154
6:00 PM 4.52113
7:00 PM 9.67174
8:00 PM 9.80147
9:00 PM 5.05111
10:00 PM 5.4265
11:00 PM 4.5732
Total 5.842717

Learn More About Comment Stats
1 - All times GMT -8...


Blog Stats

Favorite Web Sites

My Books

My MSDN Articles