I was trying to create and page with Asp.NET 2.0 and Ajax 1.0.
I was using a placeholder control to dynamically load a user control based on the user selection.
The first error I encountered is :
{"Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree
that was used to save viewstate during the previous request. For example, when adding controls dynamically, the
controls added during a post-back must match the type and position of the controls added during the initial
request."}
This is because I'm suppose to load the same user control on every page request, not only in (!IsPostBack) block. I solved that by moving the loading code to Page's OnInit event handler. According to MSDN article, http://msdn2.microsoft.com/en-us/library/ms972976.aspx#viewstate_topic4, here is the time when the page can load all of it's child controls before restore their viewstates.
After that, everything looks fine except that I can't get the value I entered into the dynamically loaded user control when post back! To make it more interesting, when keep the same user control loaded (don't load other user controls), I enter the value again, and click submit again, boom! You got it.
What could be wrong? After a day of scratching head and debugging, I notice that every time I load a different control, the loaded user control's ID is randomly assigned such as 'ctl26'. So I explicitly specify the ID before load it:
Control ctl = LoadControl(ControlPath);
ctl.ID = "UcSecuritySubTypeDetails";
placeHolderSecuritySubTypeDetails.Controls.Add(ctl);
Now everything works together. So the keys of using dynamically loaded control is:
1. Load it every time.
2. Give it an explicit ID
One thing I need to clarify is that initially I was loading the dynamic control in Page_PreInit event handler as suggested by the MSDN article: http://msdn2.microsoft.com/en-us/library/ms178472(VS.80).aspx. It says PreInit event is typically used for "Create or re-create dynamic controls". But if do as such, I will get an error complaining that the object of my placeholder control is not yet instantiated. That is because although Page is derived from Control class, but at Page_PreInit stage of the Asp.NET life cycle, only Page object is created, all sub-controls include the placeholder are initiated after Page_PreInit and before Page_Init. Check Alex Arkhipov's nice post here for details of Asp.NET 2.0 Page life cycle:
http://blogs.vertigosoftware.com/alexark/archive/2005/05/06/898.aspx
Page_Init is the best place you can load the dynamic controls into a parent control other than the Page.