The Antidote to ASP.NET Smart Navigation, Part Deux

December 20, 2004

In The Antidote to ASP.NET Smart Navigation, I mentioned an article that contained a clever solution to the scrolling problem with long ASP.NET forms and postbacks. Well, I recently located an even better version of that solution from Scott Mitchell, aka the founder of 4GuysFromRolla. I refactored it a bit into this:

''' <summary>
''' automatically preserves postback scroll position
''' </summary>
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
  RegisterHiddenField("scrollLeft", Convert.ToString(Request.Form("scrollLeft")))
  RegisterHiddenField("scrollTop", Convert.ToString(Request.Form("scrollTop")))

  Dim sb As New System.Text.StringBuilder(1000)
  Dim nl As String = Environment.NewLine
  With sb
    .Append("<script language = ""javascript"">")
    .Append(String.Concat(nl, "<!--", nl))
    .Append("function SmartScroller_GetCoords() {")
    .Append(String.Concat(nl, "var scrollX, scrollY;", nl))
    .Append("if (document.all) {")
    .Append(String.Concat(nl, "if (!document.documentElement.scrollLeft)", nl))
    .Append("scrollX = document.body.scrollLeft;")
    .Append(String.Concat(nl, "else", nl))
    .Append("scrollX = document.documentElement.scrollLeft;")
    .Append(String.Concat(nl, "if (!document.documentElement.scrollTop)", nl))
    .Append("scrollY = document.body.scrollTop;")
    .Append(String.Concat(nl, "else", nl))
    .Append("scrollY = document.documentElement.scrollTop; }")
    .Append(String.Concat(nl, "else {", nl))
    .Append("scrollX = window.pageXOffset; scrollY = window.pageYOffset; }")
    .Append(String.Concat(nl, nl))
    .Append("document.getElementById('scrollLeft').value = scrollX;")
    .Append(nl)
    .Append("document.getElementById('scrollTop').value = scrollY;")
    .Append(String.Concat(nl, "}", nl))

    .Append(String.Concat(nl, "function SmartScroller_Scroll() {", nl))
    .Append("var x = document.getElementById('scrollLeft').value;")
    .Append(String.Concat(nl, "var y = document.getElementById('scrollTop').value;", nl))
    .Append("window.scrollTo(x, y); }")

    .Append(String.Concat(nl, nl, "window.onload = SmartScroller_Scroll;"))
    .Append(String.Concat(nl, "window.onscroll = SmartScroller_GetCoords;", nl))
    .Append("window.onclick = SmartScroller_GetCoords; window.onkeypress = SmartScroller_GetCoords;")
    .Append(String.Concat(nl, "// -->", nl))
    .Append("</script>")
  End With

  RegisterClientScriptBlock("scrollCode", sb.ToString)
End Sub

Works great! Of course, you can insert this script any number of ways: in an inherited base page, as a server control, or by directly inserting it into a single page.

Posted by Jeff Atwood
15 Comments

I cant catch the onclick event. I test width window.onclick=??.. and window.document.click=??.. but the function never runs

Henry C on July 7, 2005 3:16 AM

I'm not sure; this has always worked for us. The only problem we've seen is when other JavaScript on the page happened to use the same variable names. Does this work if you isolate it so there is no (or very little) other JavaScript running on the page?

Jeff Atwood on July 7, 2005 5:52 AM

excelent, thx

minhauzen on July 19, 2005 3:03 AM

awesome! some of the methods used are deprecated in .net 2, but this works very nicely once you fix them.

specifically, you'll need to change:

RegisterClientScriptBlock("scrollCode", sb.ToString)
to
ClientScript.RegisterClientScriptBlock(Me.GetType(), "scrollCode", sb.ToString)

and

RegisterHiddenField("scrollLeft", Convert.ToString(Request.Form("scrollLeft")))
RegisterHiddenField("scrollTop", Convert.ToString(Request.Form("scrollTop")))
to
ClientScript.RegisterHiddenField("scrollLeft", Convert.ToString(Request.Form("scrollLeft")))
ClientScript.RegisterHiddenField("scrollTop", Convert.ToString(Request.Form("scrollTop")))

cheers!

Chris on March 14, 2006 3:37 AM

Works Great !

Thanks

Bikram on August 17, 2006 12:11 PM

I tested this code in both C# and VB.
This code is working fine for VB but not for C#.
Is there any changes required for c#.

Rama on January 31, 2007 4:02 AM

The code works fine but it flickers, sometimes it goes top and then scroll down, did any one have a fix for that.

Sammy Boy on July 9, 2007 9:33 AM

Its very nice Post and its working for me,it solves the problem with smartnavigation.

Rajasekhar on August 23, 2007 11:48 AM

Hey, you're stepping on my onload :)


var oldEvtR = window.onload;
window.onload = function() { if (oldEvtR) oldEvtR(); SmartScroller_Scroll(); };

is nicer because it won't block other onloads.

(*untested aircode!)

Jim on September 10, 2008 2:40 AM

Nice stuff to read.

Bharath Reddy VasiReddy on October 29, 2008 3:43 AM

ya this is implemented and working as expected thanks a lot

arunkumardct@hotmail.com

arun on December 1, 2008 11:50 AM

Excellent!!

Maria on December 2, 2008 6:33 AM

This doesn't appear to work in Netscape (i'm using 7.02) - is it supposed to?

Thnx

gordon on February 6, 2010 9:30 PM

Thanks much for the post. Works great...

Here's the C# version :

private void Page_PreRender(object sender, EventArgs e)
{
ClientScript.RegisterHiddenField("scrollLeft", Convert.ToString(Request.Form["scrollLeft"]));
ClientScript.RegisterHiddenField("scrollTop", Convert.ToString(Request.Form["scrollTop"]));

StringBuilder sb = new StringBuilder(1000);
String nl = Environment.NewLine;

sb.Append(@"script language = ""javascript""");
sb.Append(String.Concat(nl, "!--", nl));
sb.Append("function SmartScroller_GetCoords() {");
sb.Append(String.Concat(nl, "var scrollX, scrollY;", nl));
sb.Append("if (document.all) {");
sb.Append(String.Concat(nl, "if (!document.documentElement.scrollLeft)", nl));
sb.Append("scrollX = document.body.scrollLeft;");
sb.Append(String.Concat(nl, "else", nl));
sb.Append("scrollX = document.documentElement.scrollLeft;");
sb.Append(String.Concat(nl, "if (!document.documentElement.scrollTop)", nl));
sb.Append("scrollY = document.body.scrollTop;");
sb.Append(String.Concat(nl, "else", nl));
sb.Append("scrollY = document.documentElement.scrollTop; }");
sb.Append(String.Concat(nl, "else {", nl));
sb.Append("scrollX = window.pageXOffset; scrollY = window.pageYOffset; }");
sb.Append(String.Concat(nl, nl));
sb.Append("document.getElementById('scrollLeft').value = scrollX;");
sb.Append(nl);
sb.Append("document.getElementById('scrollTop').value = scrollY;");
sb.Append(String.Concat(nl, "}", nl));

sb.Append(String.Concat(nl, "function SmartScroller_Scroll() {", nl));
sb.Append("var x = document.getElementById('scrollLeft').value;");
sb.Append(String.Concat(nl, "var y = document.getElementById('scrollTop').value;", nl));
sb.Append("window.scrollTo(x, y); }");

sb.Append(String.Concat(nl, nl, "window.onload = SmartScroller_Scroll;"));
sb.Append(String.Concat(nl, "window.onscroll = SmartScroller_GetCoords;", nl));
sb.Append("window.onclick = SmartScroller_GetCoords; window.onkeypress = SmartScroller_GetCoords;");
sb.Append(String.Concat(nl, "// --", nl));
sb.Append("/script");

ClientScript.RegisterClientScriptBlock(this.GetType(), "scrollCode", sb.ToString());
}

Anon on February 6, 2010 9:30 PM

testing

Anon on February 6, 2010 9:30 PM

The comments to this entry are closed.