When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, November 14, 2007

Resetting Scroll Position When Using MaintainScrollPositionOnPostback

By Scott Mitchell


Introduction


ASP.NET 2.0 added a number of built-in client-side enhancements that were missing from earlier versions. Many of these new features were detailed in an earlier article here on 4Guys, Client-Side Enhancements in ASP.NET 2.0. One of the least undocumented yet most helpful client-side enhancement, in my opinion, is MaintainScrollPositionOnPostback.

As its name implies, MaintainScrollPositionOnPostback ensures that the browser's scroll position is maintained across postbacks. Without MaintainScrollPositionOnPostback, when a user visits a web page that is "taller" than the browser window, they have to scroll down to see the content further down on the page. If the user then clicks on a Button or performs some other action that causes a postback, the browser reloads the page and, by default, returns to the home scroll position at the top of the page, requiring the user to scroll back down to the location they were viewing when the postback occurred. To have the user's scroll position remembered across postbacks, simply set MaintainScrollPositionOnPostback to True, which can be done on a page-by-page basis or applied to all pages by configuring this option through Web.config.

While MaintainScrollPositionOnPostback makes it easy to keep the visitor at the same scroll position across postbacks, there are scenarios where you may not want to return the user to their scroll position on postback, but instead return them to the top of the page. One such example is when displaying a pageable grid. When the user edits a record, you would want to keep them at the same scroll position, but when they change the page or delete a record, you may want to reset their scroll position to the top on postback. In this article we will examine a way to override the behavior of MaintainScrollPositionOnPostback on a case-by-case basis. Read on to learn more!

- continued -

A Review of MaintainScrollPositionOnPostback


Before we can look at how to optionally reset the scroll position on postback when using MaintainScrollPositionOnPostback, we need to first examine how MaintainScrollPositionOnPostback works underneath the covers. The Client-Side Enhancements in ASP.NET 2.0 article gives a pretty thorough explanation of the client-side script emitted by MaintainScrollPositionOnPostback, and I encourage you to read this article in its entirety. Let's sum up the most germane parts here.

A page that has MaintainScrollPositionOnPostback set to True adds two hidden form fields to the rendered markup. These form fields - __SCROLLPOSITIONX and __SCROLLPOSITIONY - track the vertical and horizontal scroll positions across postbacks:

<input type="hidden" name="__SCROLLPOSITIONX" id="__SCROLLPOSITIONX" value="0" />
<input type="hidden" name="__SCROLLPOSITIONY" id="__SCROLLPOSITIONY" value="0" />

In addition to the above form fields, when MaintainScrollPositionOnPostback is set to True the page also emits script that invokes the WebForm_SaveScrollPositionOnSubmit() function when the form is submitted. WebForm_SaveScrollPositionOnSubmit() sets the current browsers X and Y scroll positions to the __SCROLLPOSITIONX and __SCROLLPOSITIONY hidden form fields right before the browser submits the form. When the postback occurs, then, the browser's scroll values are sent in the form fields.

On postback, the ASP.NET page adds a call to the client-side function WebForm_RestoreScrollPosition(), which returns the browser's scroll position to the X and Y coordinates specified by the __SCROLLPOSITIONX and __SCROLLPOSITIONY form fields (which were assigned the browser's scroll position before the postback ensued). Consequently, the browser's scroll position is maintained across postbacks. The diagram below illustrates this interaction graphically.

Resetting the Scroll Position


There are a couple of techniques for resetting the scroll position on postback. The simplest and most blunt approach is to programmatically disable MaintainScrollPositionOnPostback on the page when you want to reset the scroll position. For example, imagine that you had a Button Web control on the page that, when clicked, should revert the scroll position to the top of the page. In the Button's Click event handler you could simply set Page.MaintainScrollPositionOnPostback to False. This will disable the MaintainScrollPositionOnPostback functionality, reverting the scroll position to the top.

The problem with this ham-fisted approach is that it turns off MaintainScrollPositionOnPostback for subsequent postbacks as well. That is, after clicking the Button and turning off MaintainScrollPositionOnPostback, imagine that the user then causes a postback through some other means, and that postback should maintain the scroll position. Since MaintainScrollPositionOnPostback was disabled, the scroll positions are no longer recorded on postback so the scroll position is not maintained.

Rather than turn off MaintainScrollPositionOnPostback, a more elegant solution is to inject a bit of client-side script that resets the values of __SCROLLPOSITIONX and __SCROLLPOSITIONY sent from the server to 0. This reset needs to happen before the browser calls the WebForm_RestoreScrollPosition() function. This can be accomplished by using the ClientScript.RegisterStartupScript method. RegisterStartupScript adds a chunk of JavaScript to the end of the page (right before the closing </form> element).

When MaintainScrollPositionOnPostback is set to True and the page has been posted back, the Page class calls RegisterStartupScript in the Render stage, which injects the following markup:

<script type="text/javascript">
<!--

theForm.oldSubmit = theForm.submit;

theForm.submit = WebForm_SaveScrollPositionSubmit;



theForm.oldOnSubmit = theForm.onsubmit;
theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;

theForm.oldOnLoad = window.onload;
window.onload = WebForm_RestoreScrollPosition;
// -->
</script>

As you can see, the WebForm_SaveScrollPositionOnSubmit() function is called prior to posting back, and the WebForm_RestoreScrollPosition() function is called on load. What we need to do is inject script before these function calls that resets __SCROLLPOSITIONX and __SCROLLPOSITIONY to 0. User "guinness" provides the script to reset the __SCROLLPOSITIONX and __SCROLLPOSITIONY hidden form fields in a post to microsoft.public.dotnet.framework.aspnet titled Reset Scroll Position (modified slightly by myself for readability):

function ResetScrollPosition()
{
   var scrollX = document.getElementById('__SCROLLPOSITIONX');
   var scrollY = document.getElementById('__SCROLLPOSITIONY');

   if(scrollX && scrollY)
   {
      scrollX.value = 0;
      scrollY.value = 0;
   }
}

In order to reset the scroll position, we need to add the above JavaScript to the rendered page's output and then call it before the call to WebForm_RestoreScrollPosition(). The following code adds a function (ResetScrollPosition) to the outputted markup and then injects a line of script that invokes this function. The server-side code uses the RegisterClientScriptBlock method to register the ResetScrollPosition function, which adds the function to the top of the form. As noted earlier, RegisterStartupScript adds a call to ResetScrollPosition at the bottom of the page.

The code for the server-side ResetScrollPosition() method follows. This code, and a complete working demo, is available for download at the end of this article.

Private Sub ResetScrollPosition()
    If Not ClientScript.IsClientScriptBlockRegistered(Me.GetType(), "CreateResetScrollPosition") Then
       'Create the ResetScrollPosition() function
       ClientScript.RegisterClientScriptBlock(Me.GetType(), "CreateResetScrollPosition", _
                        "function ResetScrollPosition() {" & vbCrLf & _
                        " var scrollX = document.getElementById('__SCROLLPOSITIONX');" & vbCrLf & _
                        " var scrollY = document.getElementById('__SCROLLPOSITIONY');" & vbCrLf & _
                        " if (scrollX && scrollY) {" & vbCrLf & _
                        "    scrollX.value = 0;" & vbCrLf & _
                        "    scrollY.value = 0;" & vbCrLf & _
                        " }" & vbCrLf & _
                        "}", True)

       'Add the call to the ResetScrollPosition() function
       ClientScript.RegisterStartupScript(Me.GetType(), "CallResetScrollPosition", "ResetScrollPosition();", True)
    End If
End Sub

To reset scroll position on postback, simply call the server-side ResetScrollPosition() method from the appropriate event handler (be it the Click event handler of a Button, the PageIndexChanged event of the GridView, or some other event). Doing so results in a page with the following rendered markup:

<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
    <form name="form1" method="post" action="Default.aspx" id="form1">

   ... Markup omitted for brevity ...

<script type="text/javascript">
<!--
function ResetScrollPosition() {
  var scrollX = document.getElementById('__SCROLLPOSITIONX');
  var scrollY = document.getElementById('__SCROLLPOSITIONY');
  if (scrollX && scrollY) {
    scrollX.value = 0;
    scrollY.value = 0;
  }
}// -->
</script>

   ... Markup omitted for brevity ...

<input type="hidden" name="__SCROLLPOSITIONX" id="__SCROLLPOSITIONX" value="0" />
<input type="hidden" name="__SCROLLPOSITIONY" id="__SCROLLPOSITIONY" value="257" />

<script type="text/javascript">
<!--
ResetScrollPosition();

theForm.oldSubmit = theForm.submit;
theForm.submit = WebForm_SaveScrollPositionSubmit;

theForm.oldOnSubmit = theForm.onsubmit;
theForm.onsubmit = WebForm_SaveScrollPositionOnSubmit;

theForm.oldOnLoad = window.onload;
window.onload = WebForm_RestoreScrollPosition;
// -->
</script>
</form>
</body>
</html>

Note the inclusion of the ResetScrollPosition() JavaScript function at the top of the form and its call at the bottom of the form. As you can see, the __SCROLLPOSITIONX and __SCROLLPOSITIONY hidden form fields have non-zero values, but the call to ResetScrollPosition() sets them back to 0 before the WebForm_RestoreScrollPosition() method is called. You can rest assured that ResetScrollPosition() will always be called first so long as the server-side code that generates the script is called before the Page's Render event. All postback-related event handlers occur prior to the Render event in the Page's lifecycle.

The download at the end of this article includes the complete source code and a working version of this concept. In the demo, all pages have their MaintainScrollPositionAcrossPostback properties set to True (via a Web.config setting). The demo includes a page with a pageable and editable GridView showing 25 records per page. If you scroll down a ways and edit a record, the scroll position in maintained. If you click the Button titled "Maintain Position on Postback" at the bottom of the page, the position is maintained. There is another button at the bottom of the page named "Reset Position on Postback", and this Button's Click event handler injects the script to reset the scroll position. Furthermore, the GridView's PageIndexChanged event handler also resets the scroll position so that moving from one page to another in the GridView returns the user to the top of the page on postback.

Conclusion


In this article we looked at how to use MaintainScrollPositionOnPostback, but selectively reset the scroll position on certain postbacks. The technique involves setting the __SCROLLPOSITIONX and __SCROLLPOSITIONY hidden form values to 0 on postback prior to the page calling WebForm_RestoreScrollPosition().

Happy Programming!

  • By Scott Mitchell


    Attachments:


  • Download the Code Used in this Article


    Further Reading:


  • Client-Side Enhancements in ASP.NET 2.0
  • Reset Scroll Position (a USENET post)
  • Maintain Scroll Position on Postback in ASP.NET 2.0
  • Page.MaintainScrollPositionOnPostback Property (technical documentation)


  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article