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 View blog reactions
« Is DoEvents Evil? The Last Configuration Section Handler.. »
I canīt catch the onclick event. I test width window.onclick=??.. and window.document.click=??.. but the function never runs
Henry C on July 7, 2005 02:16 PMI'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 04:52 PMexcelent, thx
minhauzen on July 19, 2005 02:03 AMThis doesn't appear to work in Netscape (i'm using 7.02) - is it supposed to?
Thnx
gordon on September 15, 2005 09:13 AMawesome! 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 03:37 PMWorks Great !
Thanks
Bikram on August 17, 2006 11:11 AMI 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#.
The code works fine but it flickers, sometimes it goes top and then scroll down, did any one have a fix for that.
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());
}
testing
Anon on August 3, 2007 09:54 AMIts very nice Post and its working for me,it solves the problem with smartnavigation.
Rajasekhar on August 23, 2007 10:48 PMHey, 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!)
| Content (c) 2008 Jeff Atwood. Logo image used with permission of the author. (c) 1993 Steven C. McConnell. All Rights Reserved. |