locked
Dynamically add controls while keeping info after postback? RRS feed

  • Question

  • User1143295775 posted

    Let's say I have a bunch of controls that I want to "repeat" on the page. The user can click "Add" to add another set of controls.

    I still want the input to be kept (that the user has put in) after the postback that will be triggered when the user clicks "Add". 

    What is the best way to do this? I would like to use a repeater but then you have to (as far as I know) store the information in ViewState and then re-populate all the controls with the old data.

    I am using ASP Web Forms.

    Se picture for example: https://imgur.com/a/sm7IC4x

    Tuesday, January 19, 2021 10:30 PM

All replies

  • User475983607 posted

    Yeah, this question has been asked many times over the years.  The problem you have to solve is state management.  Dynamic controls are not remembered by the framework because they are not part of the markup.  It is up to you write code that remembers which dynamic controls need to persist between posts.  Add the controls early in the page life cycle (Page_Init or Page_Load) so the framework can find the controls. and assign values.  Just google this...  there are tons of blogs.... See this forum FAQs; https://forums.asp.net/t/1360420.aspx.

    I recommend using standard data bound controls to create dynamic controls.  That's what data bounds controls are for.  And you get automatic state management rather than building your own.  It is a lot easier.

    Tuesday, January 19, 2021 11:14 PM
  • User-1545767719 posted

    I would like to use a repeater but then you have to (as far as I know) store the information in ViewState and then re-populate all the controls with the old data.

    Do you mean the Repeater class in the System.Web.UI,WebControls? Can you provide us with some more details as to how you want to use it including a sample code?

    Wednesday, January 20, 2021 2:54 AM
  • User1143295775 posted

    Yes! I want to have the repeater in the markup and then DataBind it to a list which represents my items. The problem is that the ViewState "resets" when I rebind the repeater.

    Wednesday, January 20, 2021 7:19 AM
  • User1143295775 posted

    Yeah, this question has been asked many times over the years.  The problem you have to solve is state management.  Dynamic controls are not remembered by the framework because they are not part of the markup.  It is up to you write code that remembers which dynamic controls need to persist between posts.  Add the controls early in the page life cycle (Page_Init or Page_Load) so the framework can find the controls. and assign values.  Just google this...  there are tons of blogs.... See this forum FAQs; https://forums.asp.net/t/1360420.aspx.

    I recommend using standard data bound controls to create dynamic controls.  That's what data bounds controls are for.  And you get automatic state management rather than building your own.  It is a lot easier.

    But which data bound control should I use? The problem is not to persist the added controls - the problem is that the user input is removed when I rebind the control to the datasource. 

    Wednesday, January 20, 2021 7:21 AM
  • User-1545767719 posted

    The problem is that the ViewState "resets" when I rebind the repeater.

    Can you provide me with a minimum (must be minimum, please) sample code which I can copy & paste in my environment and reproduce the issue?

    Wednesday, January 20, 2021 7:52 AM
  • User1143295775 posted

    vt1222

    The problem is that the ViewState "resets" when I rebind the repeater.

    Can you provide me with a minimum (must be minimum, please) sample code which I can copy & paste in my environment and reproduce the issue?

    Here is code behind:

    namespace WebApplication1
    {
    	public partial class WebForm1 : System.Web.UI.Page
    	{
    
    		[Serializable]
    		class Item
    		{
    			public string ID = Guid.NewGuid().ToString();
    		}
    
    		private List<Item> Stuff { get { if (ViewState["Items"] == null) { Stuff = new List<Item>(); } return (List<Item>)ViewState["Items"]; } set { ViewState["Items"] = value; } }
    
    
    		protected void Page_Load(object sender, EventArgs e)
    		{
    			
    
    			if (!IsPostBack)
    			{
    				rpr.DataSource = Stuff;
    				rpr.DataBind();
    			}
    
    
    			
    		}
    
    		protected void Unnamed_Click(object sender, EventArgs e)
    		{
    			Stuff.Add(new Item());
    			rpr.DataSource = Stuff;
    			rpr.DataBind();
    		}
    
    	}
    }

    And aspx:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    	<title></title>
    </head>
    <body>
    	<form id="form1" runat="server">
    		<asp:ScriptManager runat="server"></asp:ScriptManager>
    		<div>
    			<asp:UpdatePanel runat="server">
    				<ContentTemplate>
    
    					<asp:Panel runat="server">
    
    						<asp:Button runat="server" Text="Add" ID="btn1" OnClick="Unnamed_Click" />
    						<asp:ImageButton runat="server" ID="btn2" />
    
    						<asp:Repeater runat="server" ID="rpr">
    							<ItemTemplate>
    								<br />
    								Name:
    								<asp:TextBox runat="server" />
    								Phone number:
    								<asp:TextBox runat="server"></asp:TextBox>
    								<asp:Button runat="server" Text="Remove" ID="btn111" />
    
    							</ItemTemplate>
    						</asp:Repeater>
    
    					</asp:Panel>
    
    				</ContentTemplate>
    			</asp:UpdatePanel>
    
    		</div>
    	</form>
    </body>
    </html>
    

    Wednesday, January 20, 2021 8:02 AM
  • User-1545767719 posted

    Thank you for posting the sample code. Please let me know how to reproduce and see the problem 'The problem is that the ViewState "resets" when I rebind the repeater.'

    Wednesday, January 20, 2021 8:37 AM
  • User1143295775 posted

    Thank you for posting the sample code. Please let me know how to reproduce and see the problem 'The problem is that the ViewState "resets" when I rebind the repeater.'

    1. Click Add
    2. Write something in the textbox.
    3. Click add again
    4. The textboxes are now empty :(
    Wednesday, January 20, 2021 8:42 AM
  • User-1545767719 posted

    vt1222

    • Click Add
    • Write something in the textbox.
    • Click add again
    • The textboxes are now empty :(

    Thank you for replay. I understand the issue.

    The cause is not the ViewState reset. It is because the ViewState is not loaded to the text boxes is overwritten when the GridView is bound to the data source (i.e., List<Item>) by clicking the Add button.

    The postback also occurs when you click any of the ImageButton or Remove button or Add button. At that time the ViewSate is loaded to the text boxes as expected. Please confirm it.

    But it is not the case when the GridView is bound to the data source. Since no data are bound to the text boxes they become empty as you observed.

    Try the following. You will able to understand the above explanation.

    .aspx

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeBehind="WebForm15.aspx.cs" 
        Inherits="WebApplication1.WebForm15" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server"></asp:ScriptManager>
    		<div>
    			<asp:UpdatePanel runat="server">
    				<ContentTemplate>
    
    					<asp:Panel runat="server">
    
    						<asp:Button runat="server" Text="Add" ID="btn1" OnClick="Unnamed_Click" />
    						<asp:ImageButton runat="server" ID="btn2" />
    
    						<asp:Repeater runat="server" ID="rpr">
    							<ItemTemplate>
    								<br />
                                    <asp:TextBox ID="TextBox1" runat="server" Text='<%#Eval("Id") %>'></asp:TextBox>
    								Name:
    								<asp:TextBox runat="server" Text='<%#Eval("Name")%>'></asp:TextBox>
    								Phone number:
    								<asp:TextBox runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:TextBox>
    								<asp:Button runat="server" Text="Remove" ID="btn111" />
    
    							</ItemTemplate>
    						</asp:Repeater>
    
    					</asp:Panel>
    
    				</ContentTemplate>
    			</asp:UpdatePanel>
    
    		</div>
        </form>
    </body>
    </html>

    .aspx.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace WebApplication1
    {
        public partial class WebForm15 : System.Web.UI.Page
        {
            [Serializable]
            class Item
            {
                public string ID { get; set; } = Guid.NewGuid().ToString();
                public string Name { get; set; } = "aaa";
                public string PhoneNumber { get; set; } = "123";
            }
    
            private List<Item> Stuff
            {
                get
                {
                    if (ViewState["Items"] == null)
                    {
                        Stuff = new List<Item>();
                    }
                    return (List<Item>)ViewState["Items"];
                }
    
                set
                {
                    ViewState["Items"] = value;
                }
            }
    
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    rpr.DataSource = Stuff;
                    rpr.DataBind();
                }
            }
    
            protected void Unnamed_Click(object sender, EventArgs e)
            {
                Stuff.Add(new Item());
                rpr.DataSource = Stuff;
                rpr.DataBind();
            }
    
        }
    }

    Wednesday, January 20, 2021 12:43 PM
  • User1143295775 posted

    Thank you, but I dont want to populate the textboxes from code. The user populates the textboxes and I want them (the textboxes) to keep their values when the user clicks "Add" (I dont want them to be cleared). I also dont want to manually save the values in ViewState and then re-populate the textboxes. 

    Wednesday, January 20, 2021 1:40 PM
  • User-1545767719 posted

    vt1222

    I dont want to populate the textboxes from code. The user populates the textboxes and I want them (the textboxes) to keep their values when the user clicks "Add" (I dont want them to be cleared). I also dont want to manually save the values in ViewState and then re-populate the textboxes. 

    Who said it?

    You do not understand what I meant in my reply above. My reply above is NOT solution to your problem but only the explanation as to why "store the information in ViewState and then re-populate all the controls with the old data" is not possible.

    Although I understand that you need to know "What is the best way to do this?" nobody knows the best way because the information you provided in your question is not enough to consider it.

    I believe it is your job to find the best way considering the explanation I gave you.

    Wednesday, January 20, 2021 2:05 PM
  • User1143295775 posted

    vt1222

    I dont want to populate the textboxes from code. The user populates the textboxes and I want them (the textboxes) to keep their values when the user clicks "Add" (I dont want them to be cleared). I also dont want to manually save the values in ViewState and then re-populate the textboxes. 

    Who said it?

    You do not understand what I meant in my reply above. It is NOT solution to your problem but only the explanation as to why "store the information in ViewState and then re-populate all the controls with the old data" is not possible.

    Although I understand that you need to know "What is the best way to do this?" nobody knows the best way because the information you provided in your question is not enough to consider it.

    I believe it is your job to find the best way considering the explanation I gave you.

    I appreciate that you are trying to help, but if you are going to respond snarky - you can keep it for yourself. I asked: How can I do XXXX instead of YYYY, and your reply is basically "do YYYY".

    Wednesday, January 20, 2021 2:11 PM
  • User-1545767719 posted

    I asked: How can I do XXXX instead of YYYY, and your reply is basically "do YYYY".

    I told you nobody knows how you can do XXXX because nobody knows XXXX.

    Wednesday, January 20, 2021 2:15 PM
  • User475983607 posted

    vt1222

    Thank you, but I dont want to populate the textboxes from code. The user populates the textboxes and I want them (the textboxes) to keep their values when the user clicks "Add" (I dont want them to be cleared). I also dont want to manually save the values in ViewState and then re-populate the textboxes. 

    Build a data driven solution where the user's records are stored in the database.  The programming pattern is  illustrated in every every data bound control tutorial dating back the early 2000s.   Don't worry if the doc is old as Web Forms is old.

    • The user enters data into an input form and clicks a submit button.
    • The submit button's click handlers adds the new record to the database.
    • The same click handler executes a query to get a new result.  The results set contains the newly added record.
    • The same click handler data binds the results set to the data bound control.

    The last three bullets can be separate method that the click handler calls.  Usually a data access layer or business layer depending on how your application is designed.

    Wednesday, January 20, 2021 2:21 PM
  • User1143295775 posted

    vt1222

    I asked: How can I do XXXX instead of YYYY, and your reply is basically "do YYYY".

    I told you nobody knows how you can do XXXX because nobody knows XXXX.

    If a user puts in "Donny" in the first textbox and then presses "Add" I want "Donny" to persist in the first textbox and another textbox spawned underneath. And instead of 1 textbox - there might be 10 or 20, so it's not a good solution to add them from code behind.

    My question is just what's the best way to do it. 

    Wednesday, January 20, 2021 2:23 PM
  • User-1545767719 posted

    If a user puts in "Donny" in the first textbox and then presses "Add" I want "Donny" to persist in the first textbox and another textbox spawned underneath. And instead of 1 textbox - there might be 10 or 20, so it's not a good solution to add them from code behind.

    My question is just what's the best way to do it. 

    @mgebhard gave you a plan based on the assumption that a database is used in your application. I agree with it. But I do not know if it is the best for you as I don't even know if you have a database. That is why I told you it is your job to consider your best.

    Do you know what I mean?

    Wednesday, January 20, 2021 2:44 PM
  • User1143295775 posted

    vt1222

    If a user puts in "Donny" in the first textbox and then presses "Add" I want "Donny" to persist in the first textbox and another textbox spawned underneath. And instead of 1 textbox - there might be 10 or 20, so it's not a good solution to add them from code behind.

    My question is just what's the best way to do it. 

    @mgebhard gave you a plan based on the assumption that a database is used in your application. I agree with it. But I do not know if it is the best for you as I don't even know if you have a database. That is why I told you it is your job to consider your best.

    Do you know what I mean?

    Yes, but it exactly that I want to avoid - to store the values and then repopulate the controls. If I catch the click event inside Load and add a new item to the collection/repeater and rebinds it works as I want it to. ASP automatically repopulates the fields via ViewState. If I however do the same inside the Click-event/method I have to manually keep track of the values. I am wondering if there is another way. I would use the "catch click event inside Load" if it didnt have it's drawbacks and is kind of hacky. 

    Wednesday, January 20, 2021 2:55 PM
  • User475983607 posted

    @mgebhard gave you a plan based on the assumption that a database is used in your application. I agree with it. But I do not know if it is the best for you as I don't even know if you have a database. That is why I told you it is your job to consider your best.

    Do you know what I mean?

    Databases persist data.  If a database is not used then where is the data persisted?  Cache?  when is the data persisted?

    Yes, but it exactly that I want to avoid - to store the values and then repopulate the controls. If I catch the click event inside Load and add a new item to the collection/repeater and rebinds it works as I want it to. ASP automatically repopulates the fields via ViewState. If I however do the same inside the Click-event/method I have to manually keep track of the values. I am wondering if there is another way. I would use the "catch click event inside Load" if it didnt have it's drawbacks and is kind of hacky. 

    Why do you want to avoid saving data in the database?  What problem are you trying to solve or avoid?  Quite frankly, the steps remain the same regardless of the data source.  The problem with a cache is the added complexity of synchronizing the data later.

    A lot of forum posters have gone down your path and they just end up with inefficient complex code.

    Basic example.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebFormsDb.Databound.Default" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server"></asp:ScriptManager>
            <div>
                <asp:UpdatePanel runat="server">
                    <ContentTemplate>
                        <asp:Panel runat="server">
                            <div>
                                Name:
                                <asp:TextBox ID="Name" runat="server" Text='<%#Eval("Name") %>'></asp:TextBox>
                                Phone:
                                <asp:TextBox ID="PhoneNumber" runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:TextBox>
                                <asp:Button runat="server" Text="Add" ID="Add" OnClick="Add_Click" />
                            </div>
                            <asp:Repeater runat="server" ID="rpr" OnItemCommand="rpr_ItemCommand">
                                <HeaderTemplate>
                                    <table border="1">
                                        <tr>
                                            <th>Name</th>
                                            <th>Phone Number</th>
                                            <th></th>
                                        </tr>
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <tr>
                                        <td>
                                            <asp:Label runat="server" Text='<%#Eval("Name")%>'></asp:Label>
                                        </td>
                                        <td>
                                            <asp:Label runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:Label>
                                        </td>
                                        <td>
                                            <asp:LinkButton ID="Delete"
                                                runat="server"
                                                CommandName="Delete"
                                                CommandArgument='<%#Eval("Id") %>'>Delete</asp:LinkButton>
                                        </td>
                                    </tr>
                                </ItemTemplate>
                                <FooterTemplate>
                                    </table>
                                </FooterTemplate>
                            </asp:Repeater>
                            </table>
                        </asp:Panel>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace WebFormsDb.Databound
    {
        public class Contact
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string PhoneNumber { get; set; }
        }
        public partial class Default : System.Web.UI.Page
        {
            private readonly string ConnectionString;
            public Default()
            {
                ConnectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
            }
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if(!Page.IsPostBack)
                {
                    rpr.DataSource = GetContacts();
                    rpr.DataBind();
                }
            }
    
            protected void Add_Click(object sender, EventArgs e)
            {
                string name = Name.Text;
                string phoneNumber = PhoneNumber.Text;
                AddContact(name, phoneNumber);
                rpr.DataSource = GetContacts();
                rpr.DataBind();
            }
    
            protected void rpr_ItemCommand(object source, RepeaterCommandEventArgs e)
            {
                int Id = int.Parse(e.CommandArgument.ToString());
                DeleteContact(Id);
                rpr.DataSource = GetContacts();
                rpr.DataBind();
            }
    
            protected List<Contact> GetContacts()
            {
                List<Contact> results = new List<Contact>();
                string sql = "SELECT Id, [Name], PhoneNumber FROM dbo.Contact;";
    
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    SqlCommand command = new SqlCommand(sql, connection);
                    command.Connection.Open();
                    SqlDataReader reader = command.ExecuteReader();
                    while (reader.Read())
                    {
                        results.Add(new Contact()
                        {
                            Id = (int)reader[0],
                            Name = (string)reader[1],
                            PhoneNumber = (string)reader[2]
                        });
                    }
                }
                return results;
            }
    
            protected bool AddContact(string Name, string PhoneNumber)
            {
                string sql = "INSERT INTO Contact VALUES(@Name, @PhoneNumber)";
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    SqlCommand command = new SqlCommand(sql, connection);
                    command.Parameters.AddWithValue("@Name", Name);
                    command.Parameters.AddWithValue("@PhoneNumber", PhoneNumber);
                    connection.Open();
                    int rowAffected = command.ExecuteNonQuery();
                    connection.Close();
    
                    return rowAffected == 1;
                }
            }
    
            protected bool DeleteContact(int Id)
            {
                string sql = "DELETE FROM dbo.Contact WHERE Id = @Id";
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    SqlCommand command = new SqlCommand(sql, connection);
                    command.Parameters.AddWithValue("@Id", Id);
                    connection.Open();
                    int rowAffected = command.ExecuteNonQuery();
                    connection.Close();
    
                    return rowAffected == 1;
                }
            }
    
        }
    }

    Wednesday, January 20, 2021 4:02 PM
  • User475983607 posted

    A Cache example which shows the Web Forms programming pattern is the same regardless of the data store used.

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="CacheDataSource.aspx.cs" Inherits="WebFormsDb.Databound.CacheDataSource" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager runat="server"></asp:ScriptManager>
            <div>
                <asp:UpdatePanel runat="server">
                    <ContentTemplate>
                        <asp:Panel runat="server">
                            <div>
                                Name:
                                <asp:TextBox ID="Name" runat="server" Text='<%#Eval("Name") %>'></asp:TextBox>
                                Phone:
                                <asp:TextBox ID="PhoneNumber" runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:TextBox>
                                <asp:Button runat="server" Text="Add" ID="Add" OnClick="Add_Click" />
                            </div>
                            <asp:Repeater runat="server" ID="rpr" OnItemCommand="rpr_ItemCommand">
                                <HeaderTemplate>
                                    <table border="1">
                                        <tr>
                                            <th>Name</th>
                                            <th>Phone Number</th>
                                            <th></th>
                                        </tr>
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <tr>
                                        <td>
                                            <asp:Label runat="server" Text='<%#Eval("Name")%>'></asp:Label>
                                        </td>
                                        <td>
                                            <asp:Label runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:Label>
                                        </td>
                                        <td>
                                            <asp:LinkButton ID="Delete"
                                                runat="server"
                                                CommandName="Delete"
                                                CommandArgument='<%#Eval("Id") %>'>Delete</asp:LinkButton>
                                        </td>
                                    </tr>
                                </ItemTemplate>
                                <FooterTemplate>
                                    </table>
                                </FooterTemplate>
                            </asp:Repeater>
                            </table>
                        </asp:Panel>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    
    using Microsoft.Extensions.Caching.Memory;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace WebFormsDb.Databound
    {
        public class ContactCache
        {
            public Guid Id { get; set; }
            public string Name { get; set; }
            public string PhoneNumber { get; set; }
        }
    
        public partial class CacheDataSource : System.Web.UI.Page
        {
            private List<ContactCache> Contacts
            {
                get
                {
                    if (Session["Contacts"] == null)
                    {
                        Session["Contacts"] = new List<ContactCache>();
                    }
                    return (List<ContactCache>)Session["Contacts"];
                }
                set
                {
                    Session["Contacts"] = value;
                }
            }
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                {
                    Contacts = AddTestData();
                    rpr.DataSource = GetContacts();
                    rpr.DataBind();
                }
            }
    
    
            protected void Add_Click(object sender, EventArgs e)
            {
                string name = Name.Text;
                string phoneNumber = PhoneNumber.Text;
                AddContact(name, phoneNumber);
                rpr.DataSource = GetContacts();
                rpr.DataBind();
            }
    
            protected void rpr_ItemCommand(object source, RepeaterCommandEventArgs e)
            {
                Guid Id = Guid.Parse(e.CommandArgument.ToString());
                DeleteContact(Id);
                rpr.DataSource = GetContacts();
                rpr.DataBind();
            }
    
            protected List<ContactCache> GetContacts()
            {
                return Contacts;
            }
    
            protected void AddContact(string Name, string PhoneNumber)
            {
                Contacts.Add(new ContactCache() { Id = Guid.NewGuid(), Name = Name, PhoneNumber = PhoneNumber });
            }
    
            protected void DeleteContact(Guid Id)
            {
                ContactCache result = Contacts.SingleOrDefault(c => c.Id == Id);
                if (result != null)
                {
                    Contacts.Remove(result);
                }
            }
    
            protected List<ContactCache> AddTestData()
            {
                List<ContactCache> results = new List<ContactCache>();
    
                if (Contacts.Count() == 0)
                {
                    results = new List<ContactCache>()
                    {
                        new ContactCache()
                        {
                            Id = Guid.NewGuid(),
                            Name="Hello World",
                            PhoneNumber = "1-800-111-1111"
                        },
                        new ContactCache()
                        {
                            Id = Guid.NewGuid(),
                            Name="Foo Bar",
                            PhoneNumber = "1-800-222-2222"
                        }
                    };
    return results; } return Contacts; } } }

    Wednesday, January 20, 2021 9:26 PM
  • User-1545767719 posted

    vt1222

    Yes, but it exactly that I want to avoid - to store the values and then repopulate the controls. If I catch the click event inside Load and add a new item to the collection/repeater and rebinds it works as I want it to. ASP automatically repopulates the fields via ViewState. If I however do the same inside the Click-event/method I have to manually keep track of the values. I am wondering if there is another way. I would use the "catch click event inside Load" if it didnt have it's drawbacks and is kind of hacky. 

    > Yes, but it exactly that I want to avoid - to store the values and then repopulate the controls.

    Although a store does not have to be a database, there is no way to do repopulate the controls and load the values to the properties of controls without having made certain store available. Keep in mind that WEB APPLICATION IS STATELESS.

    The ViewState is one of the stores available in the ASP.NET Web Forms by default. As a matter of fact you are now using it in your application. I guess you have observed that the ViewSate is working perfectly on the postback which is initiated by clicking the ImageButton or Remove button.

    > If I catch the click event inside Load and add a new item to the collection/repeater and rebinds it works as I want it to. ASP automatically repopulates the fields via ViewState. If I however do the same inside the Click-event/method I have to manually keep track of the values. I am wondering if there is another way. I would use the "catch click event inside Load" if it didnt have it's drawbacks and is kind of hacky.

    Do you realize that even when the Add button is clicked the postback occurs and the ViewSate works perfectly? ASP.NET repopulates the controls and loads the values to the properties of controls.

    After the controls are complete, however, the Unnamed_Click handler reloads the Stuff in which the values other than ID are empty and the TextBox.Text property is overwritten by empty.

    This is the reason why you see the empty text boxes when you click the Add button.

    You have to reload the Stuff which has the values for the text boxes. You can use a database instead of the Stuff. I recommend a database.

    You can use the Stuff if you have a reason not to use a database.

    As I mentioned above the ViewSate is working perfectly. Therefore, the controls have the values in their properties at the time the Unnamed_Click handler is initiated. You can fill the values of Text properties of the text boxes into the Stuff. Then bind it to the Repeater. You will see the result you want.

    Thursday, January 21, 2021 2:47 AM
  • User-1545767719 posted

    In my previous reply I mentioned:

    You can use the Stuff if you have a reason not to use a database.

    As I mentioned above the ViewSate is working perfectly. Therefore, the controls have the values in their properties at the time the Unnamed_Click handler is initiated. You can fill the values of Text properties of the text boxes into the Stuff. Then bind it to the Repeater. You will see the result you want.

    Shown below is a sample code:

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeBehind="WebForm16.aspx.cs" Inherits="WebApplication1.WebForm16" %>
    
    <!DOCTYPE html>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
            <div>
                <asp:UpdatePanel ID="UpdatePanel1" runat="server">
                    <ContentTemplate>
                        <asp:Panel ID="Panel1" runat="server">
                            <asp:Button runat="server" Text="Add" ID="btn1" OnClick="Unnamed_Click" />
                            <asp:ImageButton runat="server" ID="btn2" />
    
                            <asp:Repeater ID="rpr" runat="server">
                                <ItemTemplate>
                                    <br />
                                    <asp:TextBox ID="TextBox1" runat="server" Text='<%#Eval("Id") %>'></asp:TextBox>
                                    Name:
                                    <asp:TextBox ID="Name" runat="server" Text='<%#Eval("Name")%>'></asp:TextBox>
                                    PhoneNumber:
                                    <asp:TextBox ID="Phone" runat="server" Text='<%#Eval("PhoneNumber")%>'></asp:TextBox>
                                    <asp:Button runat="server" Text="Remove" ID="btn111" />
                                </ItemTemplate>
                            </asp:Repeater>
                        </asp:Panel>
                    </ContentTemplate>
                </asp:UpdatePanel>
            </div>
        </form>
    </body>
    </html>
    using System;
    using System.Collections.Generic;
    using System.Web.UI.WebControls;
    
    namespace WebApplication1
    {
        public partial class WebForm16 : System.Web.UI.Page
        {
            [Serializable]
            class Item
            {
                public string ID { get; set; } = Guid.NewGuid().ToString();
                public string Name { get; set; }
                public string PhoneNumber { get; set; }
            }
    
            private List<Item> Stuff
            {
                get
                {
                    if (ViewState["Items"] == null)
                    {
                        Stuff = new List<Item>();
                    }
                    return (List<Item>)ViewState["Items"];
                }
    
                set
                {
                    ViewState["Items"] = value;
                }
            }
    
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    rpr.DataSource = Stuff;
                    rpr.DataBind();
                }
            }
    
            protected void Unnamed_Click(object sender, EventArgs e)
            {
                int i = 0;
                RepeaterItemCollection items = rpr.Items;
                foreach (RepeaterItem item in items)
                {
                    TextBox name = item.FindControl("Name") as TextBox;
                    TextBox phone = item.FindControl("Phone") as TextBox;
                    if (name != null && phone != null)
                    {
                        Stuff[i].Name = name.Text;
                        Stuff[i].PhoneNumber = phone.Text;
                    }
                    i++;
                }
                
                Stuff.Add(new Item());
                rpr.DataSource = Stuff;
                rpr.DataBind();
            }
        }
    }

    @mgebhard gave you the other ideas which use a database and cache. Now it is your turn to consider the best solution for your own use.

    Thursday, January 21, 2021 3:01 AM