The Issue
I need to maintain the state of a dynamically created table through a PostBack on an ASP page.
The Details
When a user accesses the page, a table of CheckBoxes is created based of information stored in a database. Basically, these CheckBoxes are laid out in a grid, checked/unchecked and enabled/disabled based off of information in the database. They’re also color-coded, but that’s not really relevant.
The dimensions of the grid, and the state of the checkboxes is determined at Page_Load. I have a class called DisplayWell which is just a TableCell which holds the CheckBox. There’s an empty Table on the page itself, and I loop through and add the DisplayWells. The user can then make edits to the state of the checkboxes, and a handful of TextFields, and click a button to save.
The problem, as I’m sure you know, is that fact that these dynamically created objects disappear after Page_Load: the server hands them off to the client and they’re destroyed. I need to be able to preserve the state of the table or the object array to be able to update the database.
Until now, I’ve used hidden fields to store information that I needed to persist across postbacks, but only for one or two variables, which really wouldn’t work in this case (typically we’re talking about 96 CheckBoxes, but it could be any number). I’ve read that you can store objects in the session variables, but will the state of the object register changes made on the client side? I’ve also heard that’s a bad idea.
Edit:
After testing it, changes are NOT registered – I got the same array back from the session variables.
FWIW, here’s Page_Load:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
if (Request.QueryString["Plate_INDEX"] != null &&
Request.QueryString["Block_INDEX"] != null)
{
String sPIndex = Request.QueryString["Plate_INDEX"].ToString();
String sBIndex = Request.QueryString["Block_INDEX"].ToString();
if(-1 != Block_INDEX)
{
lblExpPlate.Text = "Edit a Solution";
populateFields();
}
hfPlate_INDEX.Value = Plate_INDEX.ToString();
hfBlock_INDEX.Value = Block_INDEX.ToString();
createPlate();
addToTable();
} // end queryString != null
}
} // end Page_Load
private void createPlate()
{
MTT_Plate_IO mpio = new MTT_Plate_IO();
SqlDataReader plateReader = mpio.Get_Plate(Plate_INDEX);
if (plateReader.Read())
{
r = (int)plateReader["Plate_Rows"];
c = (int)plateReader["Plate_Columns"];
hfPlate_INDEX.Value = plateReader["Plate_INDEX"].ToString();
dwArr = new DisplayWell[r, c];
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
dwArr[i, j] = new DisplayWell();
dwArr[i, j].cb.Checked = false;
dwArr[i, j].cb.Enabled = true;
}
} // end creation of plate
} // end plateReader
} //end createPlate();
private void addToTable()
{
// create a header for the table
TableRow header = new TableRow();
TableHeaderCell blankCell = new TableHeaderCell();
header.Cells.Add(blankCell); //blank cell to align with data
// add numbers to top of plate
for (int i = 1; i <= c; i++)
{
TableHeaderCell thc = new TableHeaderCell();
thc.Text = i.ToString();
header.Cells.Add(thc);
}
tblPlate.Rows.Add(header);
//create the plate
for (int i = 0; i < r; i++)
{
TableRow tr = new TableRow();
TableCell rowHeader = new TableCell();
rowHeader.CssClass = "style5";
//add a letter to the beginning of the row
String rowHeaderText = ((char)(i + 65)).ToString();
rowHeader.Text = rowHeaderText;
tr.Cells.Add(rowHeader);
for (int j = 0; j < c; j++)
{
tr.Cells.Add(dwArr[i, j].tc);
}
tblPlate.Rows.Add(tr);
}
}
Thanks to the advise of Andrew-Barber, who I had hoped would show up and answer this question (you still can!), I figured out the solution:
Create the object in the
OnInitmethod and remove theif(!Page.IsPostBack)block, instead instantiating the object for every instance of the page. This happens earlier in the page’s life cycle, and persists the object in memory on server-side, allowing changes made client-side to be registered.