PDA

View Full Version : [FIXED] [V0.7] Textfield loose value on AjaxEvent if using MasterPage and EnableViewState=False



jchau
Nov 13, 2008, 2:23 PM
SVN Update at 11:18am CT for v0.7.0.20284, but I think this was already broken since yesterday.

If EnableViewState="False" at page level, and page is using a MasterPage, textfield's value is lost on AjaxEvent. This pretty much broke all the pages in the app. Our testers are having a busy morning today =(.

Page


<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Page.Master"
CodeBehind="TextField2.aspx.vb" Inherits="CooliteSandbox.TextField2" EnableViewState="true" %>

<%@ Register Assembly="Coolite.Ext.Web" Namespace="Coolite.Ext.Web" TagPrefix="ext" %>

<script runat="server">
Protected Sub btnAjaxClick(ByVal sender As Object, ByVal e As Coolite.Ext.Web.AjaxEventArgs)
Me.lblText.Text = Me.txtName.Text
End Sub
</script>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<ext:TextField runat="server" ID="txtName" AllowBlank="false" FieldLabel="Name">
</ext:TextField>
<ext:Label runat="server" ID="lblText">
</ext:Label>
<ext:Button runat="server" ID="btnAjax" Text="Ajax">
<AjaxEvents>
<Click OnEvent="btnAjaxClick">
</Click>
</AjaxEvents>
</ext:Button>
</asp:Content>




MasterPage


<%@ Master Language="VB" AutoEventWireup="false" CodeBehind="Page.master.vb" Inherits="CooliteSandbox.Page" %>

<%@ Register Assembly="Coolite.Ext.Web" Namespace="Coolite.Ext.Web" TagPrefix="ext" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<ext:ScriptManager ID="ScriptManager1" runat="server" AjaxViewStateMode="Exclude">
</ext:ScriptManager >

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>


</form>
</body>
</html>

geoffrey.mcgill
Nov 13, 2008, 3:01 PM
Hi jchau,

I rolled out of a change we made yesterday and committed to SVN. 


As part of Registering the controls to postback (or ajaxevent/postback), the .NET framework adds the control ID's to an Array which is force stored in ControlState/ViewState. We're researching to see if there's a way to get around this "feature".


If you SVN update, everything should be working again, and your ViewState size should still be reduced, although not as much as during the last commit. 

jchau
Nov 13, 2008, 4:49 PM
Got latest of SVN and verified MasterPage issue has been fixed. Viewstate is definitely more bloated, but I rather take a hit there than things breaking. Thanks for the fast response!

geoffrey.mcgill
Nov 13, 2008, 5:34 PM
The array that is added to ControlState (not ViewState) is added and managed by the .NET Framework. I'm hoping there's a way to work around that array, but at the moment we're only doing what is recomended (ie. required) by the .NET Framework. 

Because the array is added to ControlState, you can not avoid setting EnableViewState="false" at either the Page level or control level. 


The term "bloated" may be a bit strong, but that array does bother me and we're going to do our best to tighten things up even further. 

jchau
Nov 13, 2008, 6:23 PM
That's understandable. My page is probably on the extreme case because of the number of controls I have and MasterPage name mangling. I notice that not all control ids are stored in control state. For example, viewport and layouts are not in there. Is it because those don't render as html elements on the client side?

Edit: just noticed those ids are controls that postback. It all makes sense now =).



<String>__ControlsRequirePostBackKey__</String>

geoffrey.mcgill
Nov 13, 2008, 8:34 PM
Hi jchau,

I have some more information. Every control which posts back information to the server and requires it's LoadPostData Method to fire must be added to the ControlState "__ControlsRequirePostBackKey__" array.

The following simple sample demonstrates that both <asp:> and <ext:> controls participate in the ControlState. The sample runs with EnableViewState="true".

Example


<%@ Page Language="C#" %>

<%@ Register assembly="Coolite.Ext.Web" namespace="Coolite.Ext.Web" tagprefix="ext" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void Button1_Click(object sender, AjaxEventArgs e)
{
this.Label1.Text = this.TextField1.Text + " : " + DateTime.Now.ToLongTimeString();
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>ViewState and ControlState</title>
</head>
<body>
<form id="form1" runat="server">
<ext:ScriptManager ID="ScriptManager1" runat="server" />

<ext:TextField ID="TextField1" runat="server" />

<ext:Radio ID="Radio1" runat="server" />

<asp:RadioButton ID="RadioButton2" runat="server" />

<ext:Button runat="server" ID="Button1" Text="Submit">
<AjaxEvents>
<Click OnEvent="Button1_Click" />
</AjaxEvents>
</ext:Button>

<ext:Label runat="server" ID="Label1" />
</form>
</body>
</html>

If you decode the ViewState/ControlState from the above Page, you should get the following from ControlState. The ViewState is "basically" empty, just the default name/value string which is added with every <form runat="server">. With the sample above, if you set EnableViewState="false", you will get the exact same ViewState and ControlState. The ControlState can not be "turned off" like ViewState can.


<?xml version="1.0" encoding="utf-16"?>
<controlstate>
<HybridDictionary>
<DictionaryEntry>
<String>__ControlsRequirePostBackKey__</String>
<ArrayList>
<String>ScriptManager1</String> <--- We might be able to remove this node as well.
<String>TextField1</String>
<String>Radio1</String>
<String>RadioButton2</String> <--- Notice <asp:RadioButton> adds two nodes.
<String>RadioButton2</String>
<String>Button1</String>
</ArrayList>
</DictionaryEntry>
</HybridDictionary>
</controlstate>

I also found a property in the TabPanel that was unecessarily being added into ViewState, which helped tighten things up.

Hope this helps.

geoffrey.mcgill
Nov 13, 2008, 9:47 PM
For my own future reference (maybe other might find this interesting as well), the following blog posts provide great explainations of ViewState and RegisterRequiresPostBack, see

http://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx



http://weblogs.asp.net/infinitiesloop/archive/2007/10/25/understanding-what-page-registerrequirespostback-does.aspx

jchau
Nov 13, 2008, 11:19 PM
Great articles! Especially the second one. I will be passing them along to others.