Skip to content

Overriding maintainScrollPositionOnPostBack with GridView Pager links

Recently, I was dealing with a large dataset in ASP.NET.  I was using the GridView control to display the data to the user.  The user was required to scroll down the page and use pagination links to view all of the data.  Paging events are triggered as PostBacks. If you are using the smart navigation features of ASP.NET, this causes some serious user experience issues.  Here’s how to fix it.

I’m using maintainScrollPositionOnPostBack=”true”, which is set in web.config. This option returns the user to the same vertical position on the page after a postback.  My GridView requires the user to scroll down the page. At the bottom they find the pagination links displayed by the GridView’s Pager. By default, when a user clicks to view a new page, they are promptly returned to the bottom of the list.   Clearly, this is not good for the user.

I found the following question on StackOverflow that gave code to reset the scroll position after a postback. However, it required modification to work with the GridView Pager.

Through examination of the generated HTML and rampant use of Response.Write(mycontrol.ToString()), I discovered that the Pager has the following DOM structure:

GridView Row
- GridView Cell
-- System.Web.UI.WebControls.PagerTable
--- Table Row
---- Table Cell
----- DataControlPagerLinkButton
---- Table Cell
----- DataControlPagerLinkButton
---- etc

The System.Web.UI.WebControls.PagerTable type is an internal class and relatively undocumented.  Thankfully, it can be cast to a normal ASP.NET Table.  The table contains a single TableRow control and each pagination link is contained within a TableCell in this row.  Each link is of type DataControlPagerLinkButton, which you can cast to a standard LinkButton.

Armed with this knowledge we can now fix the problem.  First up, we need a very small piece of JavaScript to scroll to the top of the window (courtesy StackOverflow):

// Scroll to the top of the Page
function ScrollToTop() {
  window.scrollTo(0,0);
}

We can then implement the RowDataBound event for our GridView and manipulate the Pager.  Here’s the code:

Protected Sub GridView1_RowDataBound(ByVal sender As Object, _
          ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs)
  If e.Row.RowType.Equals(DataControlRowType.Pager) Then
    Dim pTableRow As TableRow = _
             CType(e.Row.Cells(0).Controls(0).Controls(0), TableRow)
    For Each cell As TableCell In pTableRow.Cells
      For Each control As Control In cell.Controls
        If TypeOf control Is LinkButton Then
          Dim lb As LinkButton = CType(control, LinkButton)
          lb.Attributes.Add("onclick", "ScrollToTop();")
        End If
      Next
    Next
  End If
End Sub

So what does that all do?  Well:

If e.Row.RowType.Equals(DataControlRowType.Pager) Then

Checks that the current row of the GridView is in fact the Pager row.  Once we are inside the Pager, we can chain together a few calls to dig down the control hierarchy to extract the TableRow of the PagerTable:

Dim pTableRow As TableRow = _
  CType(e.Row.Cells(0).Controls(0).Controls(0), TableRow)

From there, we simply loop over each TableCell and then over each Control within that cell, checking that the current control is indeed a LinkButton.  Finally, we add a custom onclick attribute to call our JavaScript:

lb.Attributes.Add("onclick", "ScrollToTop();")

So there we are, that’s how you override the default behaviour of GridView Pager links when using the maintainScrollPositionOnPostBack  property, to offer your users a better experience.  I hope that helps!