Control Life Cycle


When a browser makes requests to an ASP.NET page, communication takes place over the stateless HTTP protocol. However, the page framework creates an illusion of stateful execution that enables a page to provide a user experience similar to that of a continuously executing desktop process. To create the illusion of continuity, on each subsequent request after the initial request, the page effectively begins execution where it left off at the end of the previous request. The page saves its state at the end of processing a request and, upon postback, uses the saved state to restore its state before processing the new request. This process of saving and restoring state is the most important aspect of the life cycle of a page and its controls.

The page framework divides request processing into several distinct, logical phases so that it can re-create and save the page and its control tree in a predictable manner. Once the page framework restores the control tree, controls can execute and interact as though in a continuously executing process.

As a control developer, you must understand a control's life cycle so that you know which logic to implement in the various phases. However, if you are new to control development, you do not have to understand the full complexity of the control life cycle before you begin implementing useful controls. To get started, you merely need an overview of the various phases in a control's life cycle, as Figure 9-1 depicts.

Figure 9-1. Control life cycle

graphics/f09hn01.jpg

The methods that begin with On (such as OnInit ) are part of your control's event infrastructure and raise the corresponding event (such as Init ). Some of the phases are implemented as events so that a page developer can respond to them by attaching event handlers.

Here's an overview of what happens in each phase and what you need to implement in your control. If you are new to control authoring, the phases that you must understand to get started are Instantiate, Initialize, Load, PreRender, and Render. You can skim the descriptions of the other phases for now and return to them when you create more advanced controls.

  • Instantiate

    The control is instantiated by the page or by another control by invoking its constructor. The phases that are listed after this stage occur only if the control is added to the control tree, as you'll see in the LifeCycleDemoTest.aspx demonstration in Listing 9-2.

  • Initialize

    In this phase, the page and all the controls in its control tree invoke their OnInit method by default (which raises the Init event). Prior to executing its life cycle phases, the page builds its initial control tree based on the declarative syntax of the .aspx page. Consequently, control properties specified in declarative page syntax are assigned before the Initialize phase. A page developer can provide additional logic to initialize the page by implementing the Page_Init method, which the page framework wires up to the Init event of the page. You can provide initialization logic for your control by overriding your control's OnInit method. At this point in its life cycle, your control can safely access child controls that are present in its Controls collection, but it cannot access its parent or any other control (such as the page) higher in the control hierarchy.

  • Begin Tracking View State

    This phase occurs at the end of the Initialize phase. In this phase, the page automatically invokes the TrackViewState method of your control. The TrackViewState method ensures that, after this phase, changes made to properties that use the ViewState dictionary are persisted in your control's view state. We introduced the view state concept in Chapter 7, "Simple Properties and View State," and will examine it in more detail in Chapter 10, "Complex Properties and State Management." The page framework invokes TrackViewState after initialization for efficiency. Initial values are always reloaded by the page framework when it reconstructs the control tree on postback, and it is inefficient to save those values in your control's view state. For the most part, the implementation of TrackViewState provided by the base Control class is adequate. You have to override TrackViewState only if your control defines complex properties, as we'll describe in Chapter 10.

  • Load View State (postback only)

    This phase occurs on postback and not during the initial request. In this phase, your control must restore its state to where it was at the end of processing the previous request. The page framework automatically restores the ViewState dictionary in this phase. If your control does not maintain state or it uses the ViewState dictionary for storing all its state information (as we described in Chapter 7), you do not have to implement logic for this phase. However, if your control requires custom state management, you must override the LoadViewState method to implement custom state restoration, as we'll describe in Chapter 10.

  • Load Postback Data (postback only, optional)

    This phase occurs on postback only if your control participates in postback data processing by implementing the IPostBackDataHandler interface. An example is the TextBox control. In this stage, a control must update its state from posted form data by implementing the LoadPostData method of the IPostBackDataHandler interface. We'll look at two examples of postback data processing, SimpleTextBox and Login , later in this chapter.

  • Load

    By the beginning of this phase, all the controls in the control tree are initialized and restored to the state they had at the end of the previous cycle. In addition, postback controls have been populated with posted form data. At this point in the life cycle (but not earlier), your control can safely access other controls in the page. In this phase, you should implement logic that is common to each request by overriding the OnLoad method. You saw an example of overriding the OnLoad method in the PageTracker example in Chapter 7 and will see this method implemented in other examples in subsequent chapters. If you need to implement logic that is executed only during the initial request for the page, you should check the IsPostBack property of the page ( if (Page.IsPostBack == false) {...} ) when implementing that logic. The page and all the controls in its control tree raise their Load event during this phase by default.

  • Raise Changed Events (postback only, optional)

    This phase occurs on postback only if your control participates in postback data processing by implementing the IPostBackDataHandler interface. During this stage, a control raises events (such as the TextChanged event of the TextBox control) to signal that its state changed as a result of postback. To participate in this phase, your control must implement the RaisePostDataChangedEvent method of the IPostBackDataHandler interface. We'll look at two examples of raising changed events later in this chapter, when we examine the SimpleTextBox and Login controls.

  • Raise Postback Event (postback only, optional)

    This phase occurs on postback only if your control participates in postback event processing by implementing the IPostBackEventHandler interface. In this phase, you can implement logic to map a client event into a server-side event by implementing the RaisePostBackEvent method of the IPostBackEventHandler interface. An example is the Button control, which raises a Click event on the server to enable the page developer to handle the client-side postback event. Later in this chapter, we'll look at several controls that contain examples of postback events ( SimpleButton, PostbackButtons , and Login ) and show you how to raise events during this phase.

  • PreRender

    In this phase, you should implement any work that your control needs to do before it is rendered, by overriding the OnPreRender method. We'll see an example of overriding the OnPreRender method later in this chapter when we examine the Login control. The page and all the controls in its control tree raise their PreRender event during this phase.

  • Save View State

    If your control does not maintain state or it uses the ViewState dictionary for storing all its state information, you do not have to implement any additional logic during this phase. The page framework automatically saves the ViewState dictionary during this phase. If your control requires custom state management, you must override the SaveViewState method to implement custom state restoration, as you will see in Chapter 10. This method is called only for controls whose EnableViewState property (and recursively, that of its parent) is set to true . Any changes made to your control after this phase will not be persisted in your control's view state.

  • Render

    In this method, your control writes markup text to the output stream by overriding the Render method of Control or one of the rendering methods of the WebControl class. We described rendering in depth in Chapter 8, "Rendering."

  • Unload

    A page performs cleanup in this phase by implementing the Page_Unload method. As a control developer, you should instead override the Dispose method to perform cleanup. The page and all the controls in its control tree raise their Unload event during this phase by default.

  • Dispose

    In this phase, you should override the Dispose method to free any resources that your control holds.

We'll now examine the mechanics of the page execution cycle. As we described in Chapter 2, a page is an HTTP handler and is responsible for processing an HTTP request to an .aspx file. When it starts processing a request, the page creates its control tree. It then sequentially executes the phases shown in Figure 9-1 by recursively invoking the methods appropriate to each phase on the control tree. Note that a page is a control (derives from Control ) and, like any other control, inherits the methods and events shown in Figure 9-1. Because several of the methods listed in Figure 9-1 are protected, you might wonder how a page can invoke them on its child controls. This invocation is possible because every control inherits ”from the Control class ”some internal (assembly- ­accessible) framework methods that recursively invoke the protected methods.

Note

The execution sequence that we just described applies to controls that are created declaratively on the page. But what if a control is created in an event handler and dynamically added to the control tree? In that case, the control plays catch-up. As soon as it is added to the control tree, it starts to execute its phases until it reaches the current phase of the page. At that point, it follows along with the page.


To demonstrate the execution sequence, we'll create the simple LifeCycleDemo control shown in Listing 9-1. LifeCycleDemo uses the tracing feature of ASP.NET to write a simple message from each execution phase by overriding the relevant methods (such as OnInit and OnLoad ).

Listing 9-1 LifeCycleDemo.cs
 using System; using System.Web.UI; namespace MSPress.ServerControls {     public class LifeCycleDemo : Control {         public LifeCycleDemo() {         }         protected override void OnInit(EventArgs e) {             base.OnInit(e);             Page.Trace.Write(this.ID, "In Init...");          }         protected override void TrackViewState() {             base.TrackViewState();             Page.Trace.Write(this.ID, "In TrackViewState...");         }         protected override void LoadViewState(object savedstate) {             base.LoadViewState(savedstate);             Page.Trace.Write(this.ID, "In LoadViewState...");         }         protected override void OnLoad(EventArgs e) {             base.OnLoad(e);             Page.Trace.Write(this.ID, "In Load...");                  }         protected override object SaveViewState() {                      Page.Trace.Write(this.ID, "In SaveViewState...");             return base.SaveViewState();         }         protected override void OnPreRender(EventArgs e) {             base.OnPreRender(e);             Page.Trace.Write(this.ID, "In PreRender...");                    }         protected override void Render(HtmlTextWriter writer) {             Page.Trace.Write(this.ID, "In Render...");         } 
 public override void Dispose() {             base.Dispose();         }                            } } 

Listing 9-2 shows a page that uses the LifeCycleDemo control. The page has three instances of the LifeCycleDemo control ”one created declaratively and two created dynamically in its button1_Click event handler. The page adds one of the dynamically created instances of LifeCycleDemo to its control tree, but not the other. You'll see that the execution phases occur only in the instance that is added to the control tree. Tracing is enabled on the page by setting trace="true" in the Page directive. Figures 9-2 and 9-3 show the trace log for the page on initial request and after postback.

Listing 9-2 LifeCycleDemoTest.aspx
 <%@ Page Language="C#" Trace="true"%> <%@ Register TagPrefix="msp" Namespace="MSPress.ServerControls"   Assembly="MSPress.ServerControls" %> <html>   <head>     <script runat="server" >       void button1_Click(object sender, EventArgs e) {           LifeCycleDemo dynamic1 = new LifeCycleDemo();           dynamic1.ID = "dynamic1";           this.Controls.Add(dynamic1);                      // The next instance of LifeCycleDemo is not added to the           // control tree of the page.           LifeCycleDemo dynamic2 = new LifeCycleDemo();           dynamic2.ID = "dynamic2";         }              </script>   </head>   <body>     <form runat="server">       <asp:Button id="button1" OnClick="button1_Click" Text="Submit"         runat="server" />       <br       <msp:LifeCycleDemo runat="server" id="declarative1" />     </form>   </body> </html> 
Figure 9-2. A section of the trace log from LifeCycleDemoTest.aspx on first request. The messages corresponding to aspx.page in the Category column are written by the page. The other messages are written by the declarative instance of LifeCycleDemo .

graphics/f09hn02.jpg

On first request, you can see the execution sequence of the declarative instance of LifeCycleDemo with ID="declarative1" in the trace log. On postback, another instance of LifeCycleDemo with ID="dynamic1" is created in the Raise Postback Event phase, as shown in Figure 9-3. This instance plays catch-up, and three of its execution phases occur in succession after it is created and added to the control tree. Note that the instance of LifeCycleDemo with ID="dynamic2" that is created in the button1_Click event handler (shown in Listing 9-2) does not execute its phases after instantiation because the page did not add the control to the control tree. A control cannot participate in request processing unless it is added to the control tree. When a control is created declaratively on a page, the page parser adds it to the control tree. If you create a control dynamically, you are responsible for adding it to the control tree yourself.

Figure 9-2 contains two calls to the SaveViewState method of the declarative1 control instance. The first call is an artifact of tracing and does not occur in normal execution. When tracing is enabled, the page makes the additional call to estimate the size of the view state.

Although tracing helps you to understand processing of the page and its controls, you should not include trace statements in production-quality code. Trace output is not rendered when tracing is disabled on the page; nonetheless, the trace statements execute and add an unnecessary overhead.

Figure 9-3. A section of the trace log from LifeCycleDemoTest.aspx on postback. This log shows the additional phases that occur in a postback scenario. It also contains messages from a second (dynamically added) instance of LifeCycleDemo .

graphics/f09hn03.jpg



Developing Microsoft ASP. NET Server Controls and Components
Developing Microsoft ASP.NET Server Controls and Components (Pro-Developer)
ISBN: 0735615829
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net