Loading a custom control at runtime

You can load a server control to your page using the constructor of the control. For example a Literal control can be loaded as follows:

plhContainer.Controls.Add(
new Literal
{
Text = string.Format("{0}.{1}",
method.ReflectedType.FullName, method.Name)
});

When it comes to a custom control you also want the markup code of you custom control to be loaded too. So you need to tell the Page o load it for you:


var nameBox = (NameBox) Page.LoadControl("NameBox.ascx");

Basically, you could do this at any time, but it is recommanded to do this at Page_Load the reason is that this is the best place for the control to restore its state and receive postback events. Also the binding will take place after this method. Look at my previous post for the sequence of the events and method calls when page gets loaded.
It is also recomannded to set a unique ID to that control if you need to find that later using FindControl, or some one else want to find where you have put it 🙂

So, my load method will look like this:


private void LoadMyControls()
{
var nameBox = (NameBox) Page.LoadControl("NameBox.ascx");
// Give the user control a unique name by setting its ID property.
// You can use this information to retrieve a reference to the control
// when you need it with the Page.FindControl() method.
nameBox.ID = "nameBox";
nameBox.FirstName = "Asghar";
nameBox.LastName = "Panahy";
nameBox.ChangeRequest += ChangeName;
plhContainer.Controls.Add(nameBox);
}

When I call LoadMyControls() in Page_Load method, I see the following sequence in my output:


STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources._Default.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

Notice that the custom control gets its data binded just after the page has passed Loading which is a good thing.

ASP Page en Control Lifecycle

When I put a logging in a couple of override methods of a NameBox control and load the page containing the custom control I see the following:

STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload

It is important to note that Page_Load is long before OnLoad method, similar to Page_Init versus OnInit.

Next I click on the change button to post back to handle the event and I see the following:

STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.ChangeRequestClicked
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload

Next, I add some similar loggging to the page that contains the control and see what happens when I load the page:


STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources._Default.OnLoad

STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources._Default.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

So, The OnLoad method gets called after binding whereas the Page_Load is about before the binding. Obviously, if you need to initialize your data, you better put your code in OnInit rather that OnLoad or Page_Load.
Another important thig here is the PreRender methods. These methods get called after load has been completed and the data is assumed to be in place.

Now let’s see what happens when I click a button on the control which causes a postback:


STARTING: MCTS._70_515.Resources.NameBox.Page_Init
STARTING: MCTS._70_515.Resources.NameBox.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Init
STARTING: MCTS._70_515.Resources._Default.OnInit
STARTING: MCTS._70_515.Resources._Default.Page_Load
STARTING: MCTS._70_515.Resources._Default.OnLoad

STARTING: MCTS._70_515.Resources.NameBox.Page_Load
STARTING: MCTS._70_515.Resources.NameBox.OnDataBinding
STARTING: MCTS._70_515.Resources.NameBox.get_LastName
STARTING: MCTS._70_515.Resources.NameBox.OnLoad
STARTING: MCTS._70_515.Resources.NameBox.ChangeRequestClicked
STARTING: MCTS._70_515.Resources._Default.ChangeName
STARTING: MCTS._70_515.Resources._Default.OnPreRender

STARTING: MCTS._70_515.Resources.NameBox.OnPreRender
STARTING: MCTS._70_515.Resources.NameBox.OnUnload
STARTING: MCTS._70_515.Resources._Default.OnUnload

Both event handlers in the control and in the page are called after all controls and the page has been loaded and the data is binded too, just before the rendering take place.