Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>To ensure that the values of input fields persist across postbacks and that server events are raised:</p> <ul> <li>Use view state to keep track of dynamically created controls.</li> <li>Re-create the controls with the same IDs in <code>LoadViewState</code> (<em>not</em> <code>Load</code> or <code>PreRender</code>, because then the values of input fields will be lost).</li> </ul> <p>The rest of this answer details how I modified your code to get it to work.</p> <h2>RMAPart.ascx</h2> <p>Just for convenience, you can declare the header row in the .ascx:</p> <pre><code>&lt;asp:Table ID="Table_Parts" runat="server" CssClass="hor-zebra"&gt; &lt;asp:TableRow&gt; &lt;asp:TableHeaderCell Text="Part" /&gt; &lt;asp:TableHeaderCell Text="Quantity" /&gt; &lt;asp:TableHeaderCell /&gt; &lt;/asp:TableRow&gt; &lt;/asp:Table&gt; </code></pre> <h2>RMAPart.ascx.cs</h2> <p>To keep track of dynamically created rows, maintain a list of row IDs in view state:</p> <pre><code>public partial class RMAPart : System.Web.UI.UserControl { private List&lt;string&gt; RowIDs { get { return (List&lt;string&gt;)ViewState["m_RowIDs"]; } set { ViewState["m_RowIDs"] = value; } } </code></pre> <p>In the <code>btn_AddPart_Click</code> handler, generate a new row ID and create the controls for the new row:</p> <pre><code> protected void btn_AddPart_Click(object sender, EventArgs e) { string id = GenerateRowID(); RowIDs.Add(id); CreatePartRow(id); } private string GenerateRowID() { int id = (int)ViewState["m_NextRowID"]; ViewState["m_NextRowID"] = id + 1; return id.ToString(); } private void CreatePartRow(string id) { TableRow tr = new TableRow(); tr.ID = id; TableCell tc1 = new TableCell(); TextBox tb_Part = new TextBox(); tb_Part.ID = "tb_Part_" + id; tb_Part.CssClass = "textbox1"; tc1.Controls.Add(tb_Part); tr.Cells.Add(tc1); TableCell tc2 = new TableCell(); TextBox tb_Quantity = new TextBox(); tb_Quantity.ID = "tb_Quantity_" + id; tb_Quantity.CssClass = "textbox1"; tc2.Controls.Add(tb_Quantity); tr.Cells.Add(tc2); TableCell tc3 = new TableCell(); Button btn_Delete = new Button(); btn_Delete.ID = "btn_Delete_" + id; btn_Delete.CommandArgument = id; btn_Delete.Click += btn_DeleteTableRow_Click; btn_Delete.Text = "Remove"; tc3.Controls.Add(btn_Delete); tr.Cells.Add(tc3); Table_Parts.Rows.Add(tr); } </code></pre> <p>In the <code>btn_DeleteTableRow_Click</code> handler, delete the clicked row and update view state:</p> <pre><code> protected void btn_DeleteTableRow_Click(object sender, EventArgs e) { Button btn = (Button)sender; TableRow tr = (TableRow)Table_Parts.FindControl(btn.CommandArgument); Table_Parts.Rows.Remove(tr); RowIDs.Remove(btn.CommandArgument); } </code></pre> <p>Hook <code>Page_Load</code> and start things off by creating the first row:</p> <pre><code> protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Reset(); } } public void Reset() { while (Table_Parts.Rows.Count &gt; 1) Table_Parts.Rows.RemoveAt(Table_Parts.Rows.Count - 1); ViewState["m_NextRowID"] = 0; string id = GenerateRowID(); RowIDs = new List&lt;string&gt; { id }; CreatePartRow(id); } </code></pre> <p>Override <code>LoadViewState</code> and re-create the rows using the IDs stored in view state:</p> <pre><code> protected override void LoadViewState(object savedState) { base.LoadViewState(savedState); foreach (string id in RowIDs) { CreatePartRow(id); } } } </code></pre> <h2>Dealing with Parts</h2> <p>The code above doesn't use your <code>Part</code> structure at all. To actually move data between your business objects and the user control, you can add a public method that takes a <code>Part</code> collection and uses it to create rows and populate text boxes, and then add another public method that reads out the values of the text boxes into a <code>Part</code> collection.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload