Along with (apparently) many .NET developers, I was having difficulty understanding why my ViewState wasn't being stored for my controls within a composite control I was building that had an internal Table.
For example, in the overridden CreateChildControls() method, I'd do something like this:
protected override CreateChildControls()
{
bool useDataSource = true;
if(ViewState["UseDataSource"]!=null)
{
useDataSource = (bool)ViewState["UseDataSource"];
}
Table table = new Table();
Controls.Add(table); //Add table to CompositeControls' ControlCollection
TableRow row = new TableRow();
table.Rows.Add(row);
for(int i = 0;i<4;i++)
{
TableCell cell = new TableCell();
if(useDataSource){ cell.Text = "Cell " + i.ToString(); }
row.Cells.Add(cell);
}
if(useDataSource) {ViewState["UseDataSource"] = false;}
}
Now, really I would abstract away the Table construction bits into a CreateControlHierarchy method (ala Kothari), but I ignored that here in this test. Now when I ran my control, ViewState wasn't storing the values
of my table cells (Cell 0,Cell 1, Cell 2, Cell 3) on the first go around (when the useDataSource variable was "true").
What gives? I added my table to the controls collection like I should and (I thought) followed the guidlines in the Kothari book (although here it doesn't look exactly the same).
What I SHOULD have done is this:
protected override CreateChildControls()
{
bool useDataSource = true;
if(ViewState["UseDataSource"]!=null)
{
useDataSource = (bool)ViewState["UseDataSource"];
}
Table table = new Table();
Controls.Add(table); //Add table to CompositeControls' ControlCollection
TableRow row = new TableRow();
table.Rows.Add(row);
for(int i = 0;i<4;i++)
{
TableCell cell = new TableCell();
row.Cells.Add(cell);
if(useDataSource){ cell.Text = "Cell " + i.ToString(); }
}
if(useDataSource) {ViewState["UseDataSource"] = false;}
}
See the difference? It is ONE slight difference that makes the difference between whether your Table stores its text values in view state or not...Look at the snippet where the iteration over the cells is being done:
for(int i = 0;i<4;i++)
{
TableCell cell = new TableCell();
row.Cells.Add(cell);
if(useDataSource){ cell.Text = "Cell " + i.ToString(); }
}
YOU MUST ADD THE CELL TO THE COLLECTION BEFORE ASSIGNING THE TEXT (OR ANY OTHER PROPERTY YOU WANT IN VIEW STATE) TO THE CELL!!! Subtle and I can't seem to find anyone screaming this loudly except for here: http://scottonwriting.net/sowblog/posts/2129.aspx
Scott has a lengthy post on all the other developers that ran into this "gotcha". I'm sure it is my impatience with lengthy technical articles that made me miss it in the books I own :)
So the rule here is, to not only add the Controls within a composite control to the main ControlCollection before assigning properties to that control, but the same rule applies for that Control's children (for example, a table with rows and cells).
Hope this helps someone else!