Geeks With Blogs
Mike Nichols - SonOfNun Technology If I were the captain on a big steamboat...
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! Posted on Monday, May 22, 2006 3:41 PM ASP.NET | Back to top


Comments on this post: Composite Controls and the Missing View State

# re: Composite Controls and the Missing View State
Requesting Gravatar...
I'm exploring how the viewstate works in a composite control so thank you for helping me in advance!
Left by lisa on Feb 28, 2007 4:36 PM

# re: Composite Controls and the Missing View State
Requesting Gravatar...
I just want to clarify this to everyone since i've also wasted hours on this particular problem. It is not only the cell that must be added to the collection before it's propertyies are set, it is also the table itself. If your add the table to the conrols collection after adding the cell to the table, the TrackViewState method will NOT be called and your viewstate won't work. I find it's best to add controls tho their parent collections as soon as I initialise them (Which is done in the code sample above).
Left by Chris Moseley on May 08, 2007 2:45 PM

# re: Composite Controls and the Missing View State
Requesting Gravatar...
I think it's important to point out that this is the *opposite* of what you want to do if you want to minimize the bandwidth you're sending out over the internet: you store a lot of information in viewstate that could likely be easily retrieved from your database at postback.

The trick to making it work and keeping your viewstate small is to always populate the table with data on every postback, whether or not it's the first time that the control is being created.

You don't have to worry about overwriting saved changes, either...if you add the control after you've given it its data, then it will load its viewstate (and any changes the user made to the data in the table that haven't been saved to the database) after you add it to the control collection, so the changes made by the user will be preserved.

If the query to get the data is very expensive, then going about it the way you are is the right thing, and if you're not concerned about the amount of internet bandwidth you use it doesn't matter that much which way you do it, but if the data is cheap, and bandwidth matters, just always grab the data fresh every postback.

Google "truly understanding viewstate" for a good article on the details.
Left by Theodore on Apr 27, 2009 10:56 AM

# re: Composite Controls and the Missing View State
Requesting Gravatar...
As with the child controls, you must also make sure that the composite control is added to the page BEFORE setting any properties of the control, so that viewstate is properly tracked.
Left by Mark Weaver on Aug 07, 2009 5:27 PM

Your comment:
 (will show your gravatar)


Copyright © Mike Nichols | Powered by: GeeksWithBlogs.net