ViewState and PostBacks

The web is stateless, but ASP.NET likes to pretend it isn't. When a user submits a web form, ASP.NET rebuilds the form on the server and uses the posted data to dispatch events to the controls on the page. This is postback processing. For statically specified controls (part of an ASPX page), the page can be re-built trivially -- when ASP.NET first encounters an ASPX page it compiles it into a class which has a method whose job is to do just that. If all the controls on a page are entirely static, then the page that is re-built for the postback will be an exact copy of the one originally rendered to the browser. To the programmer, it will seem as though it is the same page.

However, if some of the controls are generated dynamically (e.g. allocated and placed on the page in the code-behind file) or generate content based on data provided to them (e.g. the ASP.NET DataGrid), then the page resulting from re-building the static control structure is incomplete. And in order for postback processing to work correctly, the page structure has to match exactly.

The first consequence of this is that if you dynamically put controls on the page, then you have to make sure to do so during the postback. And those controls need to be identical to the page sent to the browser originally. For example, in one of my early ASP.NET pages I was generating control ID's dynamically and accidentally got myself into the situation where the ID's generated on postback were different than on the original page. This resulted in events not being dispatched to those controls (I discovered that a good way to look into problems like this is to override the FindControl() method on the page/control and just have it call the base method -- but then you can breakpoint on that and have a look at what controls the ASP.NET framework is trying to locate on your page and whether it was successful or not).

Things get more complicated if you are writing something like the ASP.NET DataGrid control. The DataGrid is designed to dynamically render content based on tabular data that you provide it. Generally this data is going to come from a DB. Now you can make a DataGrid work correctly on postback by simply re-querying the DB, and letting the DataGrid re-render itself. If you make the same query (and the contents of the DB haven't changed) then the page built during the postback will be identical to the original, and all will be happiness and light. In fact, I've seen a bunch of postings on the net where people actually build projects like this.

But if its expensive to query the DB or your query results may be different by the time the postback happens, then this is not a good solution. Fortunately the DataGrid was written to deal with this situation. When it renders itself for the original page, the DataGrid also sets up some ViewState so that on postback it can re-build itself without needing to get the tabular data fed into it again. I haven't looked in detail at what the DataGrid puts in the ViewState, but conceptually it seems to "remember" the raw data that you fed it originally. This ViewState gets stored on the page as a hidden field -- which means that when the page is submitted back to the server, the ASP.NET infrastructure can grab it from the posted data and restore the ViewState for each control on the page.

So, on postback, if you don't do a DataBind() call on it, the DataGrid will happily re-render itself with the information from its ViewState. Thus, the page will be structurally identical to the original page, and ASP.NET can correctly apply posted values to controls and dispatch events. However, there are numerous ways in which this simple model can go awry.