If you don't want to read the whole thing and just go to the solution, click here.

I reached a stage in an ASP.Net project where a I needed to make some pages work faster. I used dotTrace to profile the speed of each form and I optimized the C# and SQL code as much as I could. Some pages still were very slow.

Now, I had the idea to look for Javascript profilers. Good idea, bad offer. You either end up with a makeshift implementation that hurts more than it helps, or with something commercial that you don't even like. FireFox has a few free options like FireBug or Venkman, but I didn't even like them and then the pages I was talking about were performing badly in Internet Explorer, not FireFox.

That got me thinking of the time when Firefox managed to quickly select all the items in a <select> element, while on Internet Explorer it scrolled to each item when selecting it, slowing the process tremendously. I then solved that issue by setting the select style.display to none, selecting all the items, then restoring the display. It worked instantly.

Can you guess where I am going with this?

Most ASP.Net applications have a MasterPage now. Even most other types of sites employ a template for all the pages in a web application, with the changing page content set in a div or some other container. My solution is simple and easy to apply to the entire project:

Step 1. Set the style.display for the page content container to "none".
Step 2. Add a function to the window.onload event to restore the style.display.

Now what will happen is that the content will be displayed in the hidden div, all javascript functions that create, move, change elements in the content will work really fast, as Internet Explorer will not refresh the visual content in the middle of the execution, then show the hidden div.

A more elegant solution would have been to disable the visual refresh of the element while the changes are taking place, then enable it again, but I don't think one can do that in Javascript.

This fix can be applied to pages in FireFox as well, although I don't know if it speeds anything significantly. The overall effect will be like the one in Internet Explorer table display. You will see the page appear suddenly, rather than see each row appear while the table is loaded. This might be nice or not nice, depending on personal taste.

Another cool idea would be to hide the div and replace it with a "Page loading" div or image. That would look even cooler.

Here is the code for the restoration of display. In my own project I just set the div to style="display:none", although it might be more elegant to also hide it using Javascript for the off chance that someone might view the site in lynx or has Javascript disabled.
function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+, NS6 and Mozilla
// By Scott Andrew
{
if (elm.addEventListener){
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent){
var r = elm.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be removed");
}
}

function initMasterPage() {
document.getElementById('contenuti').style.display='';
}

addEvent(window,'load',initMasterPage);

Ok, so I used a javascript script in my page by referencing the external file and it worked. I did the exact same thing with another file and it wasn't loading! After scratching my head bald I've decided to switch the places of the two tags and voila! the script that worked would not load! The one that did not work previously was purring nicely.

My calls looked like this:
<script type="text/javascript" src='script1.js'/>
<script type="text/javascript" src='script2.js'/>


After scratching my skull a little more (blood was dripping already) I realized that the script tags are atomic tags, they should have no ending tag. Why would they, the content is specified in the src attribute. But on the DOM page for the script element there is an obscure line saying: Start tag: required, End tag: required. I switched to <script></script> format and it worked.

Oh, you are wondering why the first script worked? Because somehow an atomic script tag is erroneous, but it doesn't return any error. Instead it is treated like a mistyped start tag and the atomic portion of it is ignored. The second script would not load since the browser expected a script end tag. Maybe he even interpreted the second tag as an end tag for all I know.

Apparently, the innerText property of Javascript elements is not available for FireFox or other browsers other than Internet Explorer. FireFox exposes something similar, but with the name textContent. Why would any one of these two butt-heads learn from the other and cooperate for the common good?

The functionality of this property is to expose the inner content of an element minus any html tags. With something like <div><span class="red">Red text<span></div> the div innerText/textContent property returns "Red text". It could also work when setting, stripping tags from the content before setting innerHTML, although it seems that for both implementations setting innerText or textContent is equivalent with setting innerHTML.

There are also links about javascript functions that would replace, improve or otherwise ease the developer's work by adding the same functionality.

I was asked to fix a bug and I soon found out that the "bug" was actually IE's regex split implementation! You see? When you split by a string, the resulting array does not contain any empty spaces found!

Ex: 'a,,b'.split(/,/) = ['a','b'] in IE and ['a','','b'] in FireFox.


Searching the web I found this very nice page from regular expression guru Steven Levithan: JavaScript split Inconsistencies & Bugs: Fixed!. You can also find there a link to a page that tests the issues with your browser's Javascript regex.

Bottom line! Use Steven's code to regex split in Javascript.

I was looking for ways of speeding up my web pages, considering that one utility page I built reached 500Kb and from that, only 170kb where actually content, the rest was Javascript. Bad Javascript, I accept, but it works, ya know?

So, after thinking and thinking I thought of a novel approach to this: how about googling for it? and I found this very nice and comprehensive article: Speed Up Your Javascript Load Time.

There isn't much else I can say about it.

Before Asp.Net Ajax was released I used to work with a library called AjaxPro (formerly Ajax.Net). It also wrapped specially decorated methods and sent them to the Page as javascript functions with a callback javascript function as the last parameter. In this library, by not using a callback you were saying that you want to execute the function synchronously, that you want to wait for a result. After all, that's a functionality included in the XmlHttpRequest object.

I was amazed to see that Asp.Net Ajax does not offer such an option. You NEED a callback function. So... how do you use a WebMethod as a javascript validation function, since the validators only accept a synchronous function?

The first idea I had was the easy way, to cycle inside the function until I had a result. Bad idea: Javascript itself is not really multitask, so it just took the CPU to 100% and that was the end of it: kill task. The second idea was the hard way: redo all code in the XmlHttpRequest wrapper and use the included synchronous functionality. Too complicated, although I found an article about how to do that. So here is the way I did it:
1. Get the validator object
2. Set a property on it to tell if the validator is inside an async call or not
3. Set a property to hold the last value that was validated
4. Set a property to hold the last result returned
5. Set a method of the validator as the call back function
6. If is in async return false
7. If the last value is the same with the current validating value, return last result
8. Execute the async validation function with the validator callback method as a parameter and return false (or "in async")

Now, the callback method just sets the result and clears the async flag and also updates the visual of the validator. By doing this I essentially don't allow postbacks during validation calls, which makes sense. I also had an idea of creating a special "in async" validator that would not allow postback and would display something nice, but the solution I am explaining keeps it local, with ValidationGroups and everything working just fine.

I will show the code in a few seconds, but first be warned that I am using a validator made by myself which expects null or true as valid and a string or false as invalid. If the result is a string, it displays it as the ErrorMessage. So, on with the code:
The function to get a reference to the validator (which in some cases, especially Ajax, is not the same as the span with the same id)
function getValidator(id)
{
if (typeof(Page_Validators)=='object')
for (c=0; c<Page_Validators.length; c++)
if (Page_Validators[c].id==id) return Page_Validators[c];
return false;
}


The preparing function, which can be reused for more validators. I couldn't find a better way to encapsulate this behaviour yet, please feel free to enlighten me with ideas
// parameters are the value to be validated 
// and the validator object
function prepareAsync(value,validator) {
if (!validator) {
validator.doReturn=true;
return 'Error in prepareAsync: validator not found!';
}
// it's validating
if (validator.inAsync) {
validator.doReturn=true;
return 'In async validation';
}
// it has validated this value before
if (validator.prevValue==value) {
validator.doReturn=true;
return validator.result;
}
// create the callBack function as a method
// of the validator object
if (!validator.callBack)
validator.callBack=function(res) {
validator.inAsync=false;
validator.result=res;
if (res==null) {
validator.isvalid=true;
} else
if (typeof(res)=='boolean') {
validator.isvalid=res;
} else {
// setting the validation message is
// as simple as changing the innerHTML
// of the validator span
validator.innerHTML=res;
validator.isvalid=false;
}
// that's an ASP.Net validator function
// since .NET 1.0 upwards
ValidatorUpdateDisplay(validator);
}
validator.inAsync=true;
validator.prevValue=value;
validator.doReturn=false;
}


and now a sample validation function:
// parameters are the value to be validated
// and the id of the validator
function ValidateProdotto(value,id) {
// get the validator object
var validator=getValidator(id);
// reuse this function to all validators in the page
var res=prepareAsync(value,validator);
// doReturn says if it has a result for us
if (validator.doReturn) return res;
// perform the actual validation
PageMethods.ValidateProdotto(value,validator.callBack);
// and return false, since we are in async now
return false;
}


Hope this helps somebody. This applies to short validations, but feel free to enhance my design with cancellations of running async operations in case the value is changed or with an array caching all the values tried and validated.

Ok, the why is something I could never truly understand. It's some lawyer thing. But the fact remains that Microsoft was legally bound to show that message on each ActiveX control in Internet Explorer, thus screwing everybody and all their Flash pages.

When you Google this you find a miriad solutions. Some of them rewrite the entire HTML, others just take all the objects and embeds and rewrite their innerHTML or their outerHtml. But sometimes, it just seems that none of them work. And here is the catch for all of them: in order to work, the function that does the replacing of the HTML must be in an external Javascript file. Yes, you read right, if the function is inside the page, it doesn't work. Weird, huh?

Anyway, here is the script I use. It works, apparently.

function fixFlash() {
//ediy v2
n=navigator.userAgent;
w=n.indexOf("MSIE");
if((w>0)&&(parseInt(n.charAt(w+5))>5)){
T=["object","embed","applet"];
for(j=0;j<2;j++){
E=document.getElementsByTagName(T[j]);
for(i=0;i<E.length;i++){
P=E[i].parentNode;
H=P.innerHTML;
P.removeChild(E[i]);
P.innerHTML=H;
}}}
}


For more information about other solutions and the legal issue between Microsoft and Eolas read this specialised blog: IE ActiveX Change "Click to activate and use this control"

Update:
Well, I noticed that the Flash file I wanted to use stopped working after using this fix. Luckily I had the source and so I found a fix. The next post details it.

It all started with my own library, a dll in which I wanted to include Javascript, CSS and ultimately images or flash files. I did it the only way I could in 1.1, mainly adding the resources to the project, setting them as Embedded Resource, then reading them and either put them in the page or write them in the application directory and link them in the page. As you can imagine, there were a lot of issues related to writing writes and so on.

But then .NET 2.0 and the AjaxControlToolkit arrived. This toolkit had this funny looking Tab thing, and it used images. So where did it get the images? I was surprised to see that the namespace of the TabContainer control was decorated with stuff like this:

[assembly: WebResource("AjaxControlToolkit.Tabs.tab.gif", "image/gif")]

then in the CSS files, stuff like

background-image:url(<%=WebResource("AjaxControlToolkit.Tabs.tab.gif")%>)

Could it be so easy? yes! And for the js files, they had this class called a ScriptControlBase and the only thing you needed to do to insert a javascript file was decorate the implementing class like this:

[ClientScriptResource("AjaxControlToolkit.TabPanel", "AjaxControlToolkit.Tabs.Tabs.js")]

But what was the underlying mechanism? Googling for WebResource.axd you get these informative links:
Using WebResource.axd for embedded resources
Accessing Embedded Resources through a URL using WebResource.axd

Working with Web Resources in ASP.NET 2.0

These three articles pretty much explain the basics, so I won't do anything but emphasize the more important points:
  • When you use the name of the resource, either when decorating the namespace or when getting the reference to it, use the project namespace and the folder in which the file is in, otherwise it will not work. So if you have the namespace MyControls.Web and you have the folder Images in which you embedded an Image.gif file, the name should be MyControls.Web.Images.Image.gif.
  • To programatically get the url for an embedded resource use Page.ClientScript.GetWebResourceUrl(Type type,string resourceName)
  • In order to get the contents of an embedded resource use code like this:
    Assembly assembly = GetType().Assembly;
    arr = assembly.GetManifestResourceNames();
    foreach (string name in arr)
    if (name==resourceName) {
    Stream s = assembly.GetManifestResourceStream(name);
    // do something with the stream
    break;
    }


But what is this WebResource.axd? It's an IHttpHandler, one that you can also implement quite easily. They are used to handle Ajax, file uploads, get access to all kinds of resources. Look it up. Somewhere in the near future I might write an article about these, too.

Update: in IE7 I noticed that the style property doesn't keep the inherited values or the CSS values, but only the inline values of style. 'currentStyle' keeps all values, therefore I used that too, in case style would not work.

Update: the same can be done in FireFox by using the document.defaultView.getComputedStyle(myObject, null) syntax equivalent to myObject.currentStyle in Internet Explorer. I have not updated my function to work with that, though.

Update: By adding a break in case of relative or absolute positioning I seemed to have fixed most of the issues regarding those types of positioned elements.

Whenever one wants to popup something with Javascript, the bigger problem arising is to find the absolute position of the element that you want the popup to cling to. Searching the web you will probably find a site like this: How to get an element’s position and area, you will try that solution and say "Wee! It works!" until you scroll something inside the page and everything turns to mush.

Analysing the code and the html you will see that it ignores completely the scrolling of various elements. Even worse, the offsetParent is one for Internet Explorer and another for FireFox. So here is my solution, which seems to work in most cases. I will work on it some more, but not in the near future and usually one doesn't need a popup in a popup. So here is the code:

function findPos(obj)
{
var curleft = 0;
var curtop = 0;
if (obj.offsetParent)
{
while (obj.offsetParent)
{
curleft += obj.offsetLeft-obj.scrollLeft;
curtop += obj.offsetTop-obj.scrollTop;
var position='';
if (obj.style&&obj.style.position)
position=obj.style.position.toLowerCase();
if (!position)
if (obj.currentStyle && obj.currentStyle.position)
position = obj.currentStyle.position.toLowerCase();
if ((position=='absolute')||(position=='relative')) break;
while (obj.parentNode!=obj.offsetParent) {
obj=obj.parentNode;
curleft -= obj.scrollLeft;
curtop -= obj.scrollTop;
}
obj = obj.offsetParent;
}
}
else {
if (obj.x)
curleft += obj.x;
if (obj.y)
curtop += obj.y;
}
return {left:curleft,top:curtop};
}

Yesterday I was trying to make one of my controls keep its scroll position. Since you can't set a scrollTop attribute (which I think it is dumb, but that's another issue) I used a HiddenField and some Javascript. Mainly one at submit that loaded the scrollTop value in the hidden field and one on load to re-set it.

Since the logic of my control was mainly in the Render method of the control, I wrote the RegisterStartupScriptBlock and RegisterOnSubmitStatement lines there. It worked like a charm, but then I decided to see if it works WITHOUT Ajax.Net by removing the update panel I have been using. It failed!

I wasted like two hours before I understood that the RegisterOnSubmitStatement did not add anything to the page. I moved it in the OnPreRender method of the control and it worked!

So, long story short: DO NOT use RegisterOnSubmitStatement in the Render method of controls, as I believe the onsubmit (and possibly ClientScriptBlocks) are rendered by the page before any of the controls on it.

Someone else talks about it here.

I've updated this page a few times, adding more optimizations, so get the last version.

I was asked to find a way to maintain the vertical scroll in a selection box (that is a select html element with a size bigger than 1). I checked to see what property was changing when I was scrolling the select and I noticed that scrollTop was the one. So I used
sel.scrollTop=value;
.

Well, this works fine in FireFox and apparently works fine in IE7, too. However, in Internet Explorer 7, if you click on the up/down arrows of the select scrollbar, the scroll resets to 0. Worst than that, in IE6 you can't even set the scrollTop property. You don't get an error, but it doesn't work.

One suggested solution for people that tried the same thing is to set the size attribute to the number of options, thus getting rid of the select scrollbar, and place the select in a div with fixed height and overflow auto. It will look like a select listbox, but the scroll will be from the div and easily changed. I didn't choose this solution, basically because I felt it was cheating.

So, I've applied another solution, one that changes the selected item so that the select element scrolls itself to a position as close to the desired vertical scroll position as possible. Then, I set the scrollTop property, so that it goes at that exact position in IE7 and FireFox. If one clicks the up/down scroll arrows in IE7, the scroll position resets to the one found by the selectedIndex, not 0. And it works in IE6, too.

Here is the code:
JS Code - vertical scroll a select element
function setSelectVerticalScroll(sel,y) {
if (!sel||(sel.options.length==0)) return;

// remember the selectedIndex (for single selection selects)
var selectedIndex=sel.selectedIndex;

// find the item that selected will yield
// the best match for the required scrollTop
var best=-1; var bestMatch=100000;

// try to guess the starting index based on select height
var optionHeight=parseInt(sel.size)
?parseInt(sel.offsetHeight)/(parseInt(sel.size)+0.0)
:parseInt(sel.offsetHeight);
var startIndex=parseInt(y/optionHeight);
if (startIndex>=sel.options.length) startIndex=sel.options.length-1;
var c=startIndex;
while (c<sel.options.length) {
var selected=sel.options[c].selected;
sel.options[c].selected=false;
sel.options[c].selected=true;
if (Math.abs(parseInt(sel.scrollTop)-y)<bestMatch) {
bestMatch=Math.abs(parseInt(sel.scrollTop)-y);
best=c;
}
sel.options[c].selected=selected;
// best match has been found, no point of going further
if (Math.abs(parseInt(sel.scrollTop)-y)>bestMatch) break;

// try to jump to the right index
var inc=parseInt((y-parseInt(sel.scrollTop))/optionHeight);
c+=(inc>0?inc:1);
}

// select best match, to force scrolling
if (best>=0) {
var selected=sel.options[best].selected;
sel.options[best].selected=false;
sel.options[best].selected=true;
sel.options[best].selected=selected;
}

// set the selection back
if (sel.selectedIndex!=selectedIndex)
sel.selectedIndex=selectedIndex;

// now this should have been enough,
// but it doesn't work in IE6 and it's bugged in IE7
sel.scrollTop=y;
}


Warning! This will not work if the select is hidden by way of display=none or visibility=hidden. Also, for large selects, it will look funny scrolling through all the options. Optimizations can be applied, that try to find the correct selectedIndex or stop after the scroll position has been found (like in this example) or that search the best scrollTop match by dividing the options in two parts rather than taking them one by one, etc.

Warning: this is only a partially working solution due to some Javascript issues described (and solved) here.

A requirement I had was to maintain the scroll position of ListBoxes on PostBack. The only solution I could find was to get the scroll through Javascript (the scrollTop property of the select) and restore it on page load, however, that would have meant a lot of custom controls, not to mention lots of work, to which I am usually against.

So, I used a ControlAdapter! The ControlAdapter is something new to the NET 2.0 framework. The Control in 2.0 looks for a ControlAdapter and delegates the usual methods (like OnLoad,OnInit,Render,etc) to the adapter. You tell the site to use an adapter for a specific type of control and possibly a specific browser type (by using a browser file), and it uses that adapter for all of the controls of the selected type and also the ones inherited from them. To disallow the "adaptation" of your control, override ResolveAdapter to always return null.

Ok, the code!
C# code
///<summary>
/// This class saves the vertical scroll of listboxes
/// Set Attributes["resetScroll"] to something when you want to reset the scroll
///</summary>
public class ListBoxScrollAdapter : ControlAdapter
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if ((Page != null) && (Control is WebControl))
        {
            WebControl ctrl = (WebControl) Control;
            string scrollTop = Page.Request.Form[Control.ClientID + "_scrollTop"];
            ScriptManagerHelper.RegisterHiddenField(Page, Control.ClientID + "_scrollTop", scrollTop);
            string script =
                string.Format(
                    "var hf=document.getElementById('{0}_scrollTop');var lb=document.getElementById('{0}');if(hf&&lb) hf.value=lb.scrollTop;",
                    Control.ClientID);
            ScriptManagerHelper.RegisterOnSubmitStatement(Page, Page.GetType(), Control.UniqueID + "_saveScroll",
                                                          script);
            if (string.IsNullOrEmpty(ctrl.Attributes["resetScroll"]))
            {
                script =
                    string.Format(
                        "var hf=document.getElementById('{0}_scrollTop');var lb=document.getElementById('{0}');if(hf&&lb) lb.scrollTop=hf.value;",
                        Control.ClientID);
                ScriptManagerHelper.RegisterStartupScript(Page, Page.GetType(), Control.ClientID + "_restoreScroll",
                                                          script, true);
            } else
            {
                ctrl.Attributes["resetScroll"] = null;
            }
        }
    }
}


Browser file content<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType ="System.Web.UI.WebControls.ListBox"
adapterType="Siderite.Web.WebAdapters.ListBoxScrollAdapter" />
</controlAdapters>
</browser>
</browsers>


Of course, you will ask me What is that ScriptManagerHelper? It's a little something that tries to get the ScriptManager class without having to reference the System.Web.Extensions library for Ajax. That means that if there is Ajax around, it will use ScriptManager.[method] and if it is not it will use ClientScript.[method]. To.Int(object) is obviously something that gets the integer value from a string.

There is another thing, at the beginning I've inherited this adapter from a WebControlAdapter, but it resulted in showing all the options in the select (all the items in the ListBox) with empty text. The value was set as well as the number of options. It might be because in WebControlAdapter the Render method looks like this:
protected internal override void Render(HtmlTextWriter writer)
{
  this.RenderBeginTag(writer);
  this.RenderContents(writer);
  this.RenderEndTag(writer);
}

instead of just calling the control Render method.

I was looking for an answer to the problem of a grid inside an update panel. You see, since the rows and cells of a DataGrid or a GridView are special controls that can't be put inside panels, only in specific parent controls like tables and rows, there is no way to update only a row or a cell of a grid. If the grid is big, it takes a long time to render it entirely, it takes the CPU to 100%, it even blocks the animation of gifs. That results in ugly Ajax.

So, my first thought was: is there a way to update only what has changed? As I was saying in a previous post, a Page is rendered as its HTML string the first time it is loaded and then each Ajax postback makes it render like a list of tokens. The token format is this:

length|type|id|content|


For example 100|updatePanel|UpdatePanel1|<inner HTML of panel of 100 bytes>|

What if I would to insert my own tokens, then? Could I, let's say, change the innerHTML of a control outside of the UpdatePanel? And the answer is YES!

There are 20 token types:
  • updatePanel
  • hiddenField
  • arrayDeclaration
  • scriptBlock
  • expando
  • onSubmit
  • asyncPostBackControlIDs
  • postBackControlIDs
  • updatePanelIDs
  • asyncPostBackTimeout
  • childUpdatePanelIDs
  • panelsToRefreshIDs
  • formAction
  • dataItem
  • dataItemJson
  • scriptDispose
  • pageRedirect
  • error
  • pageTitle
  • focus


Most are not interesting, but 4 of them are!

type:updatePanel
If you add a token to the rendered page string that has the type updatePanel and the id is the UniqueID or ClientID of a control, the content will replace the innerHTML of that control, even if the control is not in an UpdatePanel.

type:hiddenField
If you add a token to the rendered page string that has the type hiddenField and the id is the UniqueID or ClientID of a control, the content will replace the value html property of that control. You can use it on hidden fields, but also on any type of input or html element that has a value. If the control does not exist, a hidden input will be created with that id and then the value will be set. You could read that value after a normal PostBack, let's say.

type:expando
If you add a token to the rendered page string that has the type expando a script will be executed in Javascript that looks like this:
id=content

Example: 5|expando|document.getElementById('TextBox1').style.backgroundColor|'red'|
This will result in the change of the background color of the control with id TextBox1 to red.

type:focus
If you add a token to the rendered page string that has the type focus and the content is a ClientID, then the focus will be set to that control provided that the focus.js script has been loaded. This script is loaded when you use Page.SetFocus. So, in order to set the focus to a control using this method, you must use SetFocus in PageLoad on any control you would like.

Why not use SetFocus, then, and be done with it? Well, because this, as all the methods above work on ANY control in the page, not just the ones in the update panel.

And now the code
using System;
using System.IO;
using System.Web.UI;
 
public partial class _Default : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Use SetFocus so that focus.js is loaded
        SetFocus(TextBox1);
    }
 
    // get the token for a javascript property change
    private string TokenizeProperty(string value, string property)
    {
        return string.Format("{0}|expando|{1}|{2}|", value.Length, property, value);
    }
 
    // get the token for a javascript value change
    private string TokenizeValue(string content, string controlID)
    {
        return string.Format("{0}|hiddenField|{1}|{2}|", content.Length, controlID, content);
    }
 
    // get the token for setting focus to a control through javascript
    private string TokenizeFocus(string controlID)
    {
        return string.Format("{0}|focus||{1}|", controlID.Length, controlID);
    }
 
    // get the token to replace the innerHTML through javascript
    private string TokenizeInnerHtml(string content, string controlID)
    {
        return string.Format("{0}|updatePanel|{1}|{2}|", content.Length, controlID, content);
    }
 
    protected override void Render(HtmlTextWriter writer)
    {
        // we only do this in the case of an Async Postback
 
        ScriptManager sm = ScriptManager.GetCurrent(this);
        if ((sm == null) || !sm.IsInAsyncPostBack)
        {
            base.Render(writer);
            return;
        }
 
        // Get the rendered page string 
        // (which should be a list of Ajax tokens)
 
        HtmlTextWriter tw = new HtmlTextWriter(new StringWriter());
        base.Render(tw);
        string content = tw.InnerWriter.ToString();
 
        // Get some meaningless text that changes over time
        string insert = DateTime.Now.ToLongTimeString();
 
        //Change the inner html of Panel2 and some 
        // table cell with the id 'testTD' with the string
        content += TokenizeInnerHtml(insert, Panel2.UniqueID);
        content += TokenizeInnerHtml(insert, "testTD");
 
        // Set value of TextBox2 to the string
        content += TokenizeValue(insert, TextBox2.UniqueID);
 
        // change the background color of TextBox2 to red
        string property = string.Format(
            "document.getElementById('{0}').style.backgroundColor",
            TextBox2.ClientID);
        string value = "'red'";
        content += TokenizeProperty(value, property);
 
        // Set focus to TextBox2
        content += TokenizeFocus(TextBox2.ClientID);
 
        // write the content with the extra tokens
        writer.Write(content);
    }
     
}



Of course, that doesn't solve my initial problem, of speeding up the Ajax rendering of large grids. That's because, even if I would solve the ViewState issues and the quirks that are bound to appear, I still can't change the innerHTML property of tables or table rows, as it is a readonly property.

So where am I to use this? It's easy: first of all, put a button (and only a button) inside an UpdatePanel. Any click on that button will trigger an Ajax postback, but will send a minimal amount of data. Then, put outside the UpdatePanel a Panel. Now you can override the Render of the page and on every Ajax postback, add whatever HTML you want to that panel. If you want to do it from javascript, put the button in a div with style="display:none" and then trigger the button click whenever you want to cause the postback. I am certain that for large readonly grids, that is a way faster method than the putting the grid inside the updatepanel.

To do this the traditional Atlas way you would have had to declare a web service, and then to set a javascript onclick event on the button, that would have executed a WebService method that returned a string, and manually change the innerHTML of the panel.

I wanted to create this Javascript fly that would... well... fly on the screen. So the first thing I did is create an empty html, put a script tag in it, add some init function to the body and then write the code.
First problem: how to get maximum height and width of the page in both IE and Mozilla. I found a way, then I added a more complex html code, like a DOCTYPE. Well, amazingly (duh!) it didn't work. Finally, after trying several options, I found this code to be working in both browsers and in both doctypes (or lack of). Please report any issues with it, so I can fix it. Thank you.

function maxHeight() {
var h=0;
if (window.document.innerHeight>h)
h=window.document.innerHeight;
if (window.document.documentElement.clientHeight>h)
h=window.document.documentElement.clientHeight;
if (window.document.body.clientHeight>h)
h=window.document.body.clientHeight;
return h;
}
function maxWidth() {
var w=0;
if (window.document.innerWidth>w)
w=window.document.innerWidth;
if (window.document.documentElement.clientWidth>w)
w=window.document.documentElement.clientWidth;
if (window.document.body.clientWidth>w)
w=window.document.body.clientWidth;
return w;
}

Internet Explorer has a lot of "features" that are completely useless. One of them is the infamous "Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus.". So what?! Just return a false value! Why do you have to throw an error?
Anyway, I've stumbled upon a bug accidentally while reviewing a html control on DynamicDrive. This is the basic setup:
<style>
.div {
display:none;
}
</style>
<script>
function loadGoogle() {
document.getElementById('div').style.display='';
document.getElementById('iframe').src='http://www.google.com';
return false;
}
</script>
<div class=div id=div style="">
<iframe id=iframe src="" ></iframe>
</div>
<a href="#" onclick="loadGoogle()">Click me!</a>


And it returns an error. Why? Because the javascript on Google tries to focus something:
document.f.q.focus();
But the display is cleared before changing the src. For all purposes, the div has the display set to an empty string (and you can check it with an alert right after it is set). The funny thing is, and that might come as a surprise, that if you move the display:none to the style attribute of the div, the script above doesn't return any error!

So, bottom line: attribute set in style tag or css cannot be changed dynamically without an error, while a control attribute can. What's up with that?! (Bug found on IE7.0). If you encounter this weird error, try moving the display attribute (I couldn't replicate the bug with the visibility attribute) in the control style attribute.