ASP.NET control event order/lifecycle
March 24, 2010
This is a very concise reference for the order which events are fired when you subclass a control. The longer more detailed MSDN page on the lifecycle can be found here. The particular control this came from was a subclassed CompositeControl, but this could be any control, or a page.
OnInit: 1
LoadViewState: 2
CreateChildControls: 3
OnLoad: 4
ShowButton: 5
OnPreRender: 6
Render: 7
OnUnload: 8
The code that produced this is below. The list above was produced after a button press on the form. This button pressed called the ShowButton() method below.
int count = 1; | |
protected override void RecreateChildControls() | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("RecreateChildControls: {0}", count++)); | |
base.RecreateChildControls(); | |
} | |
protected override void OnInit(EventArgs e) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("OnInit: {0}", count++)); | |
base.OnInit(e); | |
} | |
protected override void OnLoad(EventArgs e) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("OnLoad: {0}", count++)); | |
base.OnLoad(e); | |
} | |
protected override void OnPreRender(EventArgs e) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("OnPreRender: {0}", count++)); | |
base.OnPreRender(e); | |
} | |
public void ShowButton() | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("ShowButton: {0}", count++)); | |
} | |
protected override void OnUnload(EventArgs e) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("OnUnload: {0}", count++)); | |
base.OnUnload(e); | |
} | |
protected override void Render(HtmlTextWriter writer) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("Render: {0}", count++)); | |
base.Render(writer); | |
} | |
protected override object SaveControlState() | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("SaveControlState: {0}", count++)); | |
return base.SaveControlState(); | |
} | |
protected override void LoadViewState(object savedState) | |
{ | |
System.Diagnostics.Debug.WriteLine(string.Format("LoadViewState: {0}", count++)); | |
base.LoadViewState(savedState); | |
} |
There is also an equivalent lifecycle chart for AJAX.
Here’s a few gotchas that have gotcha’d me:
- OnInit() is called before the ViewState is loaded, so if you need the values of the controls after postback, this isn’t the event.
- OnLoad() is called before your control events on the page are fired. So if you have a button with an event handler and that changes your control, any OnLoad logic for properties of the control will be overwritten.
- CreateChildControls() is not guaranteed to be 3rd as show above. It may be called at any stage as the MSDN docs state.
- If you put rendering code in PreRender() and a method in your control that is called by a button event (or any event) relies on a control created in PreRender(), you’ll get an exception. The control won’t have been created until after that event has fired.
- Put the properties of the control that need persitance inside the ViewState, not just a backing field (example below). It might seem an obvious point but can cause headaches.
public int CurrentPage | |
{ | |
get | |
{ | |
int val; | |
int.TryParse(ViewState["CurrentPage"].ToString(), out val); | |
return val; | |
} | |
set | |
{ | |
if (value < 0) | |
value = 0; | |
else if (value <= SomeObject.Pages.Count) | |
value = MandarinForm.Pages.Count - 1; | |
ViewState["CurrentPage"] = value; | |
} | |
} |
I'm Chris Small, a software engineer working in London. This is my tech blog. Find out more about me via Github, Stackoverflow, Resume