Cleaning up a legacy ASP.Net application to conform more to the usual ASP.Net paradigm, I came across page that instantiated user controls using LoadControl in Page_Init, and those controls again creating user controls using LoadControl.
“True” ASP.Net (as I am used to developing) would embed the controls in the markup, and have the framework instantiate the controls and initialize them in their Page_Init events, as I sketched in my post on the ASP.Net Life Cycle.
There is a difference in the sequence of events though, if you use LoadControl as opposed to embedding in markup:
Page.Page_PreInit MasterPage.constructor Page.Page_Init . LoadControl .. Control.Page_Init ... LoadControl .... ChildControl.Page_Init LoadViewstate Page.Page_Load
whereas when the controls are embedded in markup, the events are
Page.Page_PreInit MasterPage.constructor Control.Page_Init (bottom up) Page.Page_Init
So in order to keep the controls’ complicated Page_Init logic (referencing MasterPage properties), I needed a sort of Post_Init event (which is not defined in ASP.Net) that initialized the controls prior to retrieving their viewstates.
I ended up creating an IPostInit interface
public interface IPostInit { void Page_PostInit(); }
which is processed in the page’s OnInit() method like this:
protected override void OnInit(EventArgs e) { base.OnInit(e); OnPostInit(); }
The OnPostInit method simply iterates all controls top-down, and invokes the Page_PostInit method:
private void OnPostInit(Control c) { foreach (Control ctrl in c.Controls) { var pi = ctrl as IPostInit; if (pi != null) { pi.Page_PostInit(); } PostInitChildren(ctrl); } }
Using this additional interface and method, it’s easy to implement initialization in both the (built-in) bottom-up and the custom top-down directions.