Page and control events occur in a certain order, which is called the page lifecycle. The precise order and number of events in this lifecycle are shown below. Do note, however, that this lifecycle diagram was created for ASP.NET 2.0; some addition events or steps may have been introduced or changed.
If you want to examine the setup of this pipeline yourself, you can do so by examining the private ProcessRequestMain method of Page. One way to do so is to use a tool such as the .NET Reflector (available from redgate) to examine the code in the System.Web.UI assembly.
The following table describes the lifecycle in all of its exhausting order.
| Event | Description |
| Determine postback mode |
The IsPostBack property is set based on the presence of the view state in the page request. Can be handled by overriding the DeterminePostBackMode method. |
| PreInit |
Occurs at the beginning of page initialization. You can use this event to set the master page or theme dynamically. |
| Initialize themes |
The page theme is set and initialized. The private method InitializeThemes method of the Page class is called. |
| Apply master page |
The page’s master page is applied. The private method ApplyMasterPage method of the Page class is called. |
| Get control adapter (controls, then page) |
Control adapters allow a developer to change the markup produced by server controls. This step gets any control adapter defined in the App_Browsers folder for the control. |
| Apply skin (controls, then page) |
Applies any skin defined for the control. |
| Init (controls, then page) |
You cannot access other server controls yet as there is no guarantee that it has been initialized yet. View state information cannot be used yet. |
| InitComplete |
Raised after page initialization is complete. All declared controls on the page are initialized; they do not, however, contain data entered by the user. View state information can still not be used yet. |
| Page state is loaded from persistence medium |
If this is a postback request, load any saved view state information from hidden <input> element. You can implement your own custom state mechanism by overriding the LoadPageStateFromPersistenceMedium method of the Page class. |
| Control state loaded (controls) |
If this is a postback request, load any control state information. Control state exists in a postback request even if view state has been disabled. |
| View state loaded (page, then controls) |
If this is a postback request, load any relevant view state information for this page or control. |
| Process post data |
Loads post data back into any controls. Implemented by the private ProcessPostData method of the Page class. |
| PreLoad |
Occurs after any view state is restored but before the Load event. |
| Load (page, then controls) |
Used to perform most of the processing steps for the page and controls that are to occur for each page request. |
| Process post data |
Loads post data back into any controls. This is attempted again in order to populate any dynamic controls added in any Load handlers. |
| Control Change Events |
All control change events (such as TextChanged for a TextBox) are triggered. |
| Control Postback Events |
All control postback events (such as Click for a Button) are triggered |
| LoadComplete |
Occurs after all Load events. You can use this event for any task that requires all controls to be loaded. |
| Prepare callback |
If an asynchronous call back is defined, it is raised. |
| Create child controls (page, then controls) |
If the control contains any child controls, they are created. |
| Data binding |
Data binding (and its events) occurs for any controls that have a DataSourceID property set. |
| PreRender (page, then controls) |
This event is the last chance to affect the page or controls before they are rendered. |
| Execute any asynchronous tasks |
Starts the execution of any asynchronous tasks that have been defined for the page using the PageAsyncTask class and registered using the RegisterAsyncTask method. |
| Render callback |
Renders any client-script callback. |
| PreRenderComplete |
Indicates that all content for the page has been pre-rendered. |
| Page state is saved to persistence medium |
Saves the page view state and control state to persistence medium. You can implement your own custom state mechanism by overriding the SavePageStateFromPersistenceMedium method of the Page class. |
| SaveStateComplete |
Occurs after the page state has been saved. |
| Render (for page, then controls) |
The page’s Render method is called and then the Render method for each control and its children is called. Rendering finally outputs the HTML and other text to be sent to the client. |
| Unload (for controls, then page) |
First each control and then the page triggers this event just before calling the Dispose method for the control or page. Can be used to perform any final cleanup of resources used by the controls or pages. |
This is no doubt a very imposing list of steps. Fortunately, for most development tasks you can remain blithely ignorant of most of these steps. We can get by initially instead simply by understanding the five general stages in the page life cycle:
- Page initialization
During this stage, the page and its controls are initialized. The page determines if it is a new request or a postback request. The page event handlers Page_PreInit and Page_Init are called. As well the PreInit and Init methods of any server controls are called. Any themes are then applied.
- Loading
If the request is a postback, control properties are loaded with information recovered from special page state containers called the view state and the control state. The Page_Load method of the page as well as the Page_Load method of its server controls, are called.
- Postback event handling
- Page initialization
If the request is a postback, then any control postback event handlers are called.
- Rendering
During page rendering, the view state is saved to the page, and then each control along with the page renders themselves to the output response stream. The PreRender then the Render method of the page and the controls is called. Finally the result from the rendering is sent back to the client via the HTTP response.
- Unloading
Final cleanup and disposal of resources used by the page occurs. The Unload methods of the controls and the page are called.
Within each of these stages, the ASP.NET page raises events that you can handle in your code. For the vast majority of situations, you only need worry about one page event, (Page_Load), and certain unique control events. Since page events always happen, you only need write the page event handler in your code using the appropriate naming convention (if AutoEventWireup is enabled). The naming convention is Page_XXXX where XXXX is the event name.
Control events, on the other hand, need to be explicitly wired – that is, you must explicitly bind the handler method to the event. This can be done declaratively in the control definition in the markup, or programmatically in the code-behind. Prior to Visual Studio 2005, the Designer in Visual Studio always used the programmatic approach. The current version of Visual Studio now uses the declarative approach.
To declaratively bind a handler to a control event, you use the appropriate OnXXXX attribute of the control, where XXXX is the event name. For instance, to bind the event handler method btnSubmit_Click to the Click event of a Button web server control, you would use:
<asp:Button id="btnSubmit" runat="server" OnClick="btnSubmit_Click" />
There now must be an event handler named btnSubmit_Click defined in the code for this page. As mentioned earlier, all event handlers in the .NET Framework have a common method signature. The appropriate event handler would thus look like the following:
protected void btnSubmit_Click(object sender, EventArgs e){
// do something
}
You can also do the equivalent event binding using programming. Conceptually this approach is quite a bit more complicated. It requires that you hook up a delegate to the appropriate event of the control. A delegate is an object that encapsulates a method (similar to a function pointer in C and C++) in a type-safe manner. The analogous code for programmatically wiring the button’s Click event using a delegate would be:
btnSubmit.Click += new EventHandler( this.btnSubmit_Click );
Since an event can be handled by multiple event handlers, the above code had to add the delegate to its list of delegates for that event (using the += operator).