RealSteel
RealSteel

Reputation: 1931

Dynamically Created Controls losing data after postback

Actually, I am Creating 1 TextBox on Pageload and adding that TextBox to Panel. Now, I have a LinkButton like Add Another.

I am entering Text in that TextBox and if needed I need to Create New TextBox,by clicking Add Another LinkButton.

Actually, I am able to get the count and recreate the TextBoxes. But,the Problem is that, My Entered text in the Previously Generated Textboxes is Missing.

Can Anyone,Suggest me a solution for this?

protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            if (!IsPostBack)
            {
                for (int i = 0; i < 5; i++)
                {
                    TableRow row = new TableRow();
                    for (int j = 0; j < 5; j++)
                    {
                        TableCell cell = new TableCell();
                        TextBox tb = new TextBox();                        
                        tb.ID = "TextBoxRow_" + i + "Col_" + j;                        
                        cell.Controls.Add(tb);                        
                        row.Cells.Add(cell);
                    }                    
                    Table1.Rows.Add(row);
                }
            }
        }
        catch (Exception ex)
        {
            throw;
        }        
    }

This is a Sample Code, the same code is written in Button_Click Also

 protected void ASPxButton1_Click(object sender, EventArgs e)
    {
 int k = Table1.Controls.Count;
}

I am getting a Count=0 on Button_Click.

Upvotes: 36

Views: 97199

Answers (7)

Jatin Phulera
Jatin Phulera

Reputation: 161

When you are working with dynamic controls they will not able to maintain its state during postback and their data lost Cause they dont have any viewstate to maintain their data.

You only need to maintain the created controls data into ViewState dynamically and loads the data into page at the time of postback and you done.

public Dictionary<Guid, string> UcList
{
    get { return ViewState["MyUcIds"] != null ? (Dictionary<Guid, string>)ViewState["MyUcIds"] : new Dictionary<Guid, string>(); }
    set { ViewState["MyUcIds"] = value; }
}

public void InitializeUC()
{
    int index = 1;
    foreach (var item in UcList)
    {
        var myUc = (UserControls_uc_MyUserControl)LoadControl("~/UserControls/uc_MyUserControl.ascx");
        myUc.ID = item.Value;
        pnlMyUC.Controls.AddAt(index, myUc);
        index++;
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
        LoadControl();
    else
        InitializeUC();
}

enter image description here

Upvotes: 1

Vivek
Vivek

Reputation: 5155

All you need to do is to re-instantiate / reinitialize dynamic controls before or within page load event each and every time during postback and add this control to page / forms / placeholders. Then, the posted data will automatically be assigned to the control by calling the LoadPostData method by the parent control.

check the article and how to write code for dynamic control - How to maintain dynamic control events, data during postback in asp.net

enter image description here

Upvotes: 20

Se&#231;kin
Se&#231;kin

Reputation: 2826

Just remove this line

 if (!IsPostBack)

Upvotes: 4

RealSteel
RealSteel

Reputation: 1931

This is My final answer after working a lot with Dynamic Controls

.aspx

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div style="text-align: center">
    <div style="background-color: Aqua; width: 250px;">
    <br />
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
        <ContentTemplate>
            <asp:PlaceHolder runat="server" ID="myPlaceHolder"></asp:PlaceHolder>
        </ContentTemplate>
        <Triggers>
            <asp:AsyncPostBackTrigger ControlID="btnAddTextBox" EventName="Click" />
        </Triggers>
    </asp:UpdatePanel>
    <br />
    </div>
    <br />
    <asp:Button ID="btnAddTextBox" runat="server"  Text="Add TextBox" OnClick="btnAddTextBox_Click" />
    <br /><br />
    <asp:UpdatePanel ID="UpdatePanel2" runat="server">
        <ContentTemplate>
            <asp:Button runat="server" ID="MyButton" Text="Get Values." OnClick="MyButton_Click" />
            <br /><br />
            <asp:Label runat="server" ID="MyLabel"></asp:Label>
        </ContentTemplate>
    </asp:UpdatePanel>
 </div>
</form>

.aspx.cs

static int myCount = 0;
    private TextBox[] dynamicTextBoxes;

    protected void Page_PreInit(object sender, EventArgs e)
    {
        Control myControl = GetPostBackControl(this.Page);

        if ((myControl != null))
        {
            if ((myControl.ClientID.ToString() == "btnAddTextBox"))
            {
                myCount = myCount + 1;
            }
        }
    }

    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);
        dynamicTextBoxes = new TextBox[myCount];
        int i;
        for (i = 0; i < myCount; i += 1)
        {
            TextBox textBox = new TextBox();
            textBox.ID = "myTextBox" + i.ToString();
            myPlaceHolder.Controls.Add(textBox);
            dynamicTextBoxes[i] = textBox;
            LiteralControl literalBreak = new LiteralControl("<br />");
            myPlaceHolder.Controls.Add(literalBreak);
        }
    }

    protected void btnAddTextBox_Click(object sender, EventArgs e)
    {
        // Handled in preInit due to event sequencing.
    }

    protected void MyButton_Click(object sender, EventArgs e)
    {
        MyLabel.Text = "";
        foreach (TextBox tb in dynamicTextBoxes)
        {
            MyLabel.Text += tb.Text + " :: ";
        }
    }

    public static Control GetPostBackControl(Page thePage)
    {
        Control myControl = null;
        string ctrlName = thePage.Request.Params.Get("__EVENTTARGET");
        if (((ctrlName != null) & (ctrlName != string.Empty)))
        {
            myControl = thePage.FindControl(ctrlName);
        }
        else
        {
            foreach (string Item in thePage.Request.Form)
            {
                Control c = thePage.FindControl(Item);
                if (((c) is System.Web.UI.WebControls.Button))
                {
                    myControl = c;
                }
            }
        }
        return myControl;
    }

Upvotes: 3

RealSteel
RealSteel

Reputation: 1931

Actually, I have used Javascript for accomplishing my task. and it goes like this :

<form id="form1" runat="server" enctype="multipart/form-data" method="post">
        <span style="font-family: Arial">Click to add files</span>&nbsp;&nbsp;
        <input id="Button1" type="button" value="add" onclick="AddFileUpload()" />
        <br />
        <br />
        <div id="FileUploadContainer">
            <!--FileUpload Controls will be added here -->
        </div>
        <asp:HiddenField ID="HdFirst1" runat="server" Value="" />
        <br />
        <asp:Button ID="btnUpload" runat="server" Text="Upload" OnClick="btnUpload_Click" />
    </form>

Script :

 <script type="text/javascript">
        var counter = 0;

        function AddFileUpload() {

            var div = document.createElement('DIV');
            div.innerHTML = '<input id="file' + counter + '"name = "file' + counter + '"type="text"/><input id="file' + counter + '" name = "file' + counter + '" type="file" /><input id="Button' + counter + '" type="button" value="Remove" onclick = "RemoveFileUpload(this)" />';

            document.getElementById("FileUploadContainer").appendChild(div);
            counter++;
        }
        function RemoveFileUpload(div) {
            document.getElementById("FileUploadContainer").removeChild(div.parentNode);
        }

        function mydetails(div) {
            var info;
            for (var i = 0; i < counter; i++) {
                var dd = document.getElementById('file' + i).value;
                info = info + "~" + dd;
            }
            document.getElementById('<%= HdFirst1.ClientID %>').value = info;
        }
    </script>

and In the Upload_Click Button :

for (int i = 0; i < Request.Files.Count; i++)
        {           
           string strname = HdFirst1.Value;
           string[] txtval = strname.Split('~');
            HttpPostedFile PostedFile = Request.Files[i];
            if (PostedFile.ContentLength > 0)
            {
                string FileName = System.IO.Path.GetFileName(PostedFile.FileName);
               // string textname=
                //PostedFile.SaveAs(Server.MapPath("Files\\") + FileName);
            }
        }

Upvotes: 0

R.C
R.C

Reputation: 10565

When using dynamic controls, you must remember that they will exist only until the next postback.ASP.NET will not re-create a dynamically added control. If you need to re-create a control multiple times, you should perform the control creation in the PageLoad event handler ( As currently you are just creating only for first time the TextBox using Condition: !IsPostabck ). This has the additional benefit of allowing you to use view state with your dynamic control. Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the PageLoad event, ASP.NET will apply any view state information that it has after the PageLoad event handler ends.

So, Remove the Condition: !IsPostback, So that each time the page Loads, The TextBox control is also created. You will also see the State of Text box saved after PageLoad handler completes. [ Obviously you have not disabled ViewState!!! ]

Example:

protected void Page_Load(object sender, EventArgs e)
{

    TextBox txtBox = new TextBox();
    // Assign some text and an ID so you can retrieve it later. 

    txtBox.ID = "newButton";
    PlaceHolder1.Controls.Add(txtBox);

}

Now after running it, type anything in text box and see what happens when you click any button that causes postback. The Text Box still has maintained its State!!!

Upvotes: 14

Adil
Adil

Reputation: 148110

The dynamically generated control do not maintain state. You have to maintain it at your own. You can use some hidden field to keep the state of controls, which will be used on server side to extract the state. Asp.net uses hidden field to maintain the state between requests, you can see __VIEWSTATE in the source.

In ASP.NET pages, the view state represents the state of the page when it was last processed on the server. It's used to build a call context and retain values across two successive requests for the same page. By default, the state is persisted on the client using a hidden field added to the page and is restored on the server before the page request is processed. The view state travels back and forth with the page itself, but does not represent or contain any information that's relevant to client-side page display, Reference.

Upvotes: 7

Related Questions