Search code examples
asp.netevent-handlingpostbackviewstateservercontrols

Why do my dynamically added controls loose their values after Postback?


To ask my question I have created an aspx file containing a Button and a DataList with an SqlDataSource:

    <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />

    <asp:DataList ID="DataList1" runat="server" DataKeyField="a" 
    DataSourceID="SqlDataSource1" >
        <ItemTemplate>
            a:
            <asp:Label ID="aLabel" runat="server" Text='<%# Eval("a") %>' />
            <br />
            b:
            <asp:Label ID="bLabel" runat="server" Text='<%# Eval("b") %>' />
            <br />
        </ItemTemplate>
    </asp:DataList>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:probaConnectionString %>" 
    SelectCommand="SELECT [a], [b] FROM [PROBA_TABLE]"></asp:SqlDataSource>

In my code behind I add TextBoxes to the Items of the DataList. I add to every Item a TextBox in the Page_Load, and another TextBox in the Button Click eventhandler as well.

    public partial class _Default : System.Web.UI.Page
    {   
        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack)
            {
                foreach (DataListItem item in DataList1.Items)
                {
                    item.Controls.Add(new TextBox());
                }
            }
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            foreach (DataListItem item in DataList1.Items)
            {
                item.Controls.Add(new TextBox());
            }
        }

    }
}

This works fine except one thing. When I click the Button, the TextBoxes which were created in the Page_Load keep their Text value, but the TextBoxes which were created in the Button1_Click lose their Text values. My real problem is more complicated than this, but I think solving this would help me a lot.

My site after postback


Solution

  • Each control that should receive data from page ViewState should be instantiated in Init or Load event handlers, because ViewState is persisted to controls BEFORE Click, Change and the rest control events (those events are triggered when ViewState changes are detected, so ViewState must be read before Click event is fired).

    So the process should look like:

    1. OnInit (static controls get created)
    2. Static control content is deserialized from ViewState
    3. OnLoad (create dynamic controls, in your case textboxes that you created in last Postback)
    4. Dynamic control content is deserialized from ViewState
    5. Click, Change and other events are fired according to changes detected comparing POST data and ViewState data

    Suggestions:

    You can use hidden fields to save additional status information, and then in OnLoad you can read that info to recreate dynamically created controls.

    Also, you should explicitly set ID property of your textboxes so that values can be properly persisted back, don't rely on ASP.Net.