title: deleting dynamically created table rows in asp code behind
body: <p>Hi I've been working on this problem for weeks now and in the process have researched the ASP page life cycle, view state and other topics, along with numerous related postings, to try and come up with a solution. I've made a lot of progress, but have reached an impasse.</p>
  
  <p>I've made this ASP application as simple as possible in order to demonstrate (to myself) how to dynamically add and delete rows of data in a table. On the initial visit to the page, the user is presented with a text box and and "Add" button. Each time the user enters data in the tb and clicks "Add", an ASP table is inserted (at the placeholder "Placeholder1"). The table contains whatever was previously entered along with a new row containing the data that was just entered in the text box (the tb is then cleared). Each row of the table has its own "Delete" button which, when clicked, deletes the row.</p>
  
  <p>Behind the scenes, on each "add", the data entered by the user is being saved to a data table which is being saved to the view state. On each "delete", the row is deleted from the data table which is again saved to the view state. </p>
  
  <p>I've almost got it working, but if I delete a row and then subsequently attempt to add a row, the added row does not appear. I stepped through the code for this use case and the ASP table appears to be generated correctly - the added row is just not being displayed. Something about the "delete" operation is messing things up.</p>
  
  <p>I've read that dynamic tables should be rebuilt on each postback in the Page_Init step, but view state is not available in this step, and I need to retrieve the data table in order to know how many rows to create, so I'm rebuilding it in the Page_Load step.</p>
  
  <p>Anyone's help would be greatly appreciated!</p>
  
  <p>Here's the .aspx:</p>
  
  <pre><code>&lt;%@ Page Title="Home Page" Language="C#" AutoEventWireup="true"
  CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %&gt;
  
  &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
  
  &lt;head id="Head1" runat="server"&gt;
      &lt;title&gt;Dynamic Adding and Deleting of Rows in ASP Table Demo&lt;/title&gt;
  &lt;/head&gt;
      &lt;body&gt;
          &lt;form runat="server"&gt;
              Please enter some text:&lt;br /&gt;&lt;br /&gt;
              &lt;asp:TextBox ID="TextBox1" runat="server"&gt;&lt;/asp:TextBox&gt;
              &lt;asp:Button ID="Button1" runat="server" Text="Add" onclick="btnAdd_Click" /&gt;&lt;br /&gt;&lt;br /&gt;
              &lt;asp:PlaceHolder ID="PlaceHolder1" runat="server"&gt;&lt;/asp:PlaceHolder&gt;
          &lt;/form&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>and here's the code-behind:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using System.Web.UI.HtmlControls;
  using System.Data;
  
  namespace WebApplication1
  {
      public partial class _Default : System.Web.UI.Page
      {
          int noOfRows = 0;
  
          protected void Page_Init(object sender, EventArgs e)
          {
  
          }
  
          protected void Page_Load(object sender, EventArgs e)
          {
              MakeTable();
          }
  
          /// &lt;summary&gt;
          /// On first visit to page, create a data table (zero rows) in which to store user-entered data
          /// If postback, create a new ASP table called "tblMyTable" of n rows where n = saved viewstate "NoOfRows" 
          /// and insert it into form at Placeholder1; each row of the ASP table contains a label (text to be added later) 
          /// and a "Delete" button
          /// &lt;/summary&gt;
          private void MakeTable()
          {
              //On first visit to page...
              if (!Page.IsPostBack)
              {
                  DataTable myDataTable = new DataTable();
                  DataColumn myCol = myDataTable.Columns.Add();
                  myCol.DataType = System.Type.GetType("System.String");
                  ViewState["MyDataTable"] = myDataTable;
                  ViewState["NoOfRows"] = 0;
              }
              //On postback...
              else
              {
                  //Fetch number of rows from view state
                  noOfRows = (int)ViewState["NoOfRows"];
  
                  Table myTable = new Table();
                  myTable.ID = "tblMyTable";
                  TableRow myRow = null;
                  TableCell myCell = null;
                  Label myLabel = null;
                  Button myButton = null;
                  for (int i = 0; i &lt; noOfRows + 1; i++)
                  {
                      myRow = new TableRow();
                      myCell = new TableCell();
                      myLabel = new Label();
                      myLabel.ID = "lblLabel" + i.ToString();
                      myCell.Controls.Add(myLabel);
                      myRow.Cells.Add(myCell);
                      myCell = new TableCell();
                      myButton = new Button();
                      myButton.ID = "btnDelete" + i.ToString();
                      myButton.Text = "Delete";
                      myButton.CommandName = "Delete";
                      //CommandArgument identifies the row number
                      myButton.CommandArgument = i.ToString();
                      myButton.Click += new EventHandler(btnDelete_Click);
                      myCell.Controls.Add(myButton);
                      myRow.Cells.Add(myCell);
                      myTable.Rows.Add(myRow);
                  }
                  PlaceHolder1.Controls.Add(myTable);
              }
          }
  
          /// &lt;summary&gt;
          /// Clicking on the form's Add button causes a new row to be added to data table, and the contents of the
          /// text box are copied to this new row. The MyDataTable view state is saved, and the NoOfRows view state is 
          /// incremented by 1
          /// &lt;/summary&gt;
          /// &lt;param name="sender"&gt;&lt;/param&gt;
          /// &lt;param name="e"&gt;&lt;/param&gt;
          protected void btnAdd_Click(object sender, EventArgs e)
          {
              DataTable myDataTable = (DataTable)ViewState["MyDataTable"]; 
              if (TextBox1.Text != "")
              {
                  DataRow myDataRow = myDataTable.NewRow();
                  myDataRow[0] = TextBox1.Text;
                  myDataTable.Rows.Add(myDataRow);
                  TextBox1.Text = "";
                  ViewState["MyDataTable"] = myDataTable;
                  noOfRows++;
                  ViewState["NoOfRows"] = noOfRows;
              }
              //Copy values from data table to labels in ASP table
              FillTable(myDataTable);
          }      
  
          /// &lt;summary&gt;
          /// Each row in tblMyTable has a "Delete" button. When the Delete button is clicked, the corresponding row 
          /// in the data table is deleted, then the values in the data table are copied to the corresponding labels in 
          /// the ASP table, and then the last two rows of the ASP table are hidden
          /// &lt;/summary&gt;
          /// &lt;param name="sender"&gt;&lt;/param&gt;
          /// &lt;param name="e"&gt;&lt;/param&gt;
          void btnDelete_Click(object sender, EventArgs e)
          {
              Button myButton = (Button)sender;
              //The row number is stored in each Delete button's CommandArgument
              int thisRow = Convert.ToInt32(myButton.CommandArgument);
              //Retrieve data table from view state, delete row, then save data table back to view state
              DataTable myDataTable = (DataTable)ViewState["MyDataTable"];
              myDataTable.Rows[thisRow].Delete();
              ViewState["MyDataTable"] = myDataTable;
              //Save NoOfRows view state, which is now 1 less than before Delete button was clicked
              noOfRows = myDataTable.Rows.Count;
              ViewState["NoOfRows"] = noOfRows;
              //Copy data from data table to labels in ASP table
              FillTable(myDataTable);
              //Hide last two rows of ASP table
              Table myTable = (Table)Page.Form.FindControl("tblMyTable");
              myTable.Rows[myTable.Rows.Count - 1].Visible = false;
              myTable.Rows[myTable.Rows.Count - 2].Visible = false;
          }
  
          /// &lt;summary&gt;
          /// Fill the ASP table "tblMyTable" by setting each rows label equal to the corresponding value
          /// in the data table "myDataTable"
          /// &lt;/summary&gt;
          /// &lt;param name="myDataTable"&gt;&lt;/param&gt;
          private void FillTable(DataTable myDataTable)
          {
              Table myTable = (Table)Page.Form.FindControl("tblMyTable");
              Label myLabel = null;
              for (int i = 0; i &lt; noOfRows; i++)
              {
                  myLabel = (Label)myTable.Rows[i].FindControl("lblLabel" + i.ToString());
                  myLabel.Text = myDataTable.Rows[i][0].ToString();
              }
          }
      }
  }    
  </code></pre>