DefaultButton, UpdatePanel and System.Web

Last week I've encountered a very weird problem when I tried to use the new DefaultButton property of an Asp.Net Panel in an UpdatePanel. I used two Panels, each one in a different UpdatePanel, and set the DefaultButton.
Something like this:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">  
    <ContentTemplate>
        <asp:Panel ID="Panel1" runat="server" Height="50px" Width="125px" DefaultButton="Button1">
            <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
            <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
        </asp:Panel>
    </ContentTemplate>
</asp:UpdatePanel>

<asp:UpdatePanel ID="UpdatePanel2" runat="server">  
    <ContentTemplate>
        <asp:Panel ID="Panel2" runat="server" Height="50px" Width="125px" DefaultButton="Button2">
            <asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
            <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" />
        </asp:Panel>
    </ContentTemplate>
</asp:UpdatePanel>  

But when I tried to use the default button (by entering some text in the text box and pressing enter) in the second panel after I used it in the first panel, weird things started to happen.
Sometimes no button has been pressed, and sometimes the button from the first panel was pressed.

After a little digging I found the problem: The code which enables the DefaultButton property in System.Web caused it.

When you add the default button property to a panel, the following code is rendered in the div tag:

<div id="Panel1"  
    onkeypress="javascript:return WebForm_FireDefaultButton(event, 'Button1')" >

This is a JavaScript function which is in an Embedded Resource called WebForms.js in the System.Web assembly. The function simply checks if the key that was pressed was "enter", and clicks the button if so.

The problem with this function and Ajax was a global variable it used to determine if the button has already been clicked, probably to prevent an unnecessary post back. It looks like this (thank you Reflector):

var __defaultFired = false;  
function WebForm_FireDefaultButton(event, target) {  
    if (!__defaultFired && event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
        var defaultButton;
        if (__nonMSDOMBrowser) {
            defaultButton = document.getElementById(target);
        }
        else {
            defaultButton = document.all[target];
        }
        if (defaultButton && typeof(defaultButton.click) != "undefined") {
            __defaultFired = true;
            defaultButton.click();
            event.cancelBubble = true;
            if (event.stopPropagation) event.stopPropagation();
            return false;
        }
    }
    return true;
}

So when I pressed "enter" the second time, in the second panel, defaultFired was true, so the default button was not clicked. (Why sometimes the first button was pressed? Because it appears first in the html, it is considered by the browser, as the default button of the page). This happens because the script expect to be reloaded after the button has been clicked, and when it does, the __defaultFired will be initialized again to false. This does not happen in Ajax, the whole page is not reloading, and so the __defaultFired stays true.

I tried to fix this problem with the following JavaScript code:

var prm = Sys.WebForms.PageRequestManager.getInstance();

prm.add_endRequest(resetDefaultButton);

function resetDefaultButton(sender,args) {  
    __defaultFired = false;
}

I simply reset the __defaultFired to false every time an Ajax request is finished.
It worked like a charm.

And so, I went home and tried to recreate the problem (for this post). But it didn't happen! The default button worked great!

I started to analyze what can cause this to work in my personal computer and not at work. I fired up the reflector and to my surprise I found that in my computer the function looks like this:

function WebForm_FireDefaultButton(event, target) {  
    if (event.keyCode == 13 && !(event.srcElement && (event.srcElement.tagName.toLowerCase() == "textarea"))) {
        var defaultButton;
        if (__nonMSDOMBrowser) {
            defaultButton = document.getElementById(target);
        }
        else {
            defaultButton = document.all[target];
        }
        if (defaultButton && typeof(defaultButton.click) != "undefined") {
            defaultButton.click();
            event.cancelBubble = true;
            if (event.stopPropagation) event.stopPropagation();
            return false;
        }
    }
    return true;
}

As you can see , __defaultButton is missing!

What the &%$#$ is happening here?

Searched the web , came up with nothing. Until I found this post which describes a security update to the .Net framework.
I entered the link for downloading the fix and to my surprise, saw the title:

NET Framework 2.0 SYSTEM.WEB.DLL and MSCOREE.DLL Security Update for Windows 2000, Windows Server 2003 and Windows XP

Could it be that the assembly was updated in my personal computer by windows update, and updated the script? It sound correct, because at work we do not receive updates . Our development network is an internal network which is not exposed to the web, and therefore not to windows update.

Before I ran to install it, I was lucky to read the fine print. It causes problems in some operating systems, like windows 2000 sp4, which we use in my company.

For now, I don't know what updated the assembly. It could have been an update from a long time ago, which I wasn't aware of.
What else have been changed?
What else would work different?
What updates I should download in order to make the version of the .Net framework at work the newest and most updated?
Why the version of the assembly stayed the same even though it has been changed?

I couldn't find where the updates are documented in MSDN or Microsoft.

Any suggestions?

Yossi Shmueli

Keeping it green since 1995

comments powered by Disqus