FREE BOOK

Chapter 5: Event-Based Programming

Posted by Apress Free Book | ASP.NET January 02, 2009
In this chapter, we explore the intricacies of working with server control events.

Control Life Cycle

The examples so far have demonstrated the use of server-side events to coordinate the activities of an ASP.NET application as part of an .aspx page. Each HTTP request / response cycle that the page executes follows a well-defined process known as the control execution life cycle. The Page server control orchestrates these activities on behalf of all the server controls in the Page's control tree. Control developers need to understand the flow of execution to ensure that their custom controls perform as expected as part of an ASP.NET Web Form. Figure 5-21 provides a high-level view of the page life cycle process.



Figure 5-21. An overview of the page life cycle

After the initial page request as an HTTP GET, each subsequent HTTP POST page request/response cycle generally consists of the following steps:

  1. Instantiate the control tree, creating each server control object.
     
  2. Unpack ViewState for each server control object.
     
  3. Set the state from the previous server-side processing cycle for each object in
    the tree.
     
  4. Process postback data.
     
  5. Handle the Page_Load event.
     
  6. Let controls know that data changed through postback, updating control state
    as necessary.
     
  7. Execute server-side events based on data changes from postback.
     
  8. Persist state back to ViewState.
     
  9. Execute the render process for each server control.
     
  10. Unload the page and its control tree.

This process is what provides the illusion of a stateful application to the end user. During each request/response round-trip, state is unpacked, changes are processed, the UI is updated, and the page is sent back to the user's browser with its new state values embedded in a hidden form field as ViewState, ready for the next request/response cycle. We next examine what events are available to controls as the page life cycle executes on the server side.

Plugging Into the Life Cycle

Server controls have a well-defined behavior pattern that coincides with the overall page life cycle. The ASP.NET framework provides a series of events that server controls can override to customize behavior during each phase of the life cycle. Table 5-1 provides an overview of each of these events.

Table 5-1. Server Control Events Related to the Control Execution Life Cycle

SERVER CONTROL EVENT PAGE LIFE CYCLE PHASE DESCRIPTION
Init Initialization Initializes settings for the control.
LoadViewState Unpack ViewState Populates the state values of the
control from ViewState.
LoadPostData Handle form postback data Updates control's state values from posted data.
Load Page_Load event Executes code common to every
page request/response cycle.
RaisePostDataChangedEvent Initialization for server-side events Notifies control that newly posted data changed its state.
RaisePostBackEvent Execute server-side events Goes hand-in-hand with previous event. Server-side events fire as a result of changes found in posted data for a particular control.
PreRender Render process Allows each control a chance to update state values before rendering.
SaveViewState Save ViewState Persists a control's updated state through the ViewState mechanism.
Render Render process Generates HTML reflecting the control's state and settings.
Dispose Dispose of control tree Releases any resources held by the control before teardown.

As you can see in Table 5-1, ASP.NET provides each server control the capability to finely tune each phase in the life cycle. You can choose to accept default behavior, or you can customize a particular phase by overriding the appropriate event.

The Lifecycle Server Control

Now that we have covered the basics of the control execution life cycle, we are going to examine this process in more detail by overriding all available events in a server control named Lifecycle. The overridden methods fall into two camps: those that raise defined events exposed by a control and those that are not events but perform a necessary action for the control.

OnInit, OnLoad, OnPreRender, and OnUnload are events defined in System.Web.UI.Control that a control developer can override as required for a particular control. LoadViewState, LoadPostData, RaisePostDataChangedEvent, RaisePostBackEvent, TrackViewState, SaveViewState, and Render are all events that perform necessary actions for the control to maintain its state and event processing.

CAUTION As with most object-oriented class hierarchies, it is usually (though not always) necessary to call the base class's version of an overridden method in the descendent class to ensure consistent behavior. If the base method is not called in the descendent class, instances of that class will most likely fail to behave as expected-or worse, they could cause instability.

The implementation of Dispose deviates from the previous description for overridden methods. The Control class does expose a Dispose event, but it does not have an OnDispose method to raise it. Instead, providing a Dispose method follows the design pattern for objects that work with scarce resources, implementing the IDisposable interface.

Life Cycle and the HTTP Protocols GET and POST

The page life cycle differs based on whether the Web Form is requested for the first time via an HTTP GET or instead is initiated as part of a postback resulting from an HTTP POST generated by a control element on the page submitting the Web Form back to the server. The HTTP POST generally causes more life cycle activities because of the requirement to process data posted by the client back to the web server, raising events associated with state changes.

Figure 5-22 shows the two variants (initial GET versus POST) of the Web Form life cycle and the names of the phases we discuss in detail shortly.



Figure 5-22. The control life cycle

In order to discuss the control life cycle, we use a control that overrides the methods necessary to track the execution of each of the life cycle events as they occur. Listing 5-19 provides the class file for the Lifecycle control that handles this task. The implementation of each overridden method is quite simple, with a call to the trace function notifying us that the method is executing.

Listing 5-19. The Lifecycle Control Class File

using System;
using System.Web.UI;
using System.Collections.Specialized;
using System.Diagnostics;
namespace ControlsBookLib.Ch05
{
    [ToolboxData("<{0}:Lifecycle runat=server></{0}:Lifecycle>")]
    public class Lifecycle : Control, IPostBackEventHandler, IPostBackDataHandler
    {
        // Init Event
        override protected void OnInit(System.EventArgs e)
        {
            Trace("Lifecycle: Init Event.");
            base.OnInit(e);
        }
        override protected void TrackViewState()
        {
            Trace("Lifecycle: Track ViewState.");
            base.TrackViewState();
 
        }
        // Load ViewState Event
        override protected void LoadViewState(object savedState)
        {
            Trace("Lifecycle: Load ViewState Event.");
            base.LoadViewState(savedState);
        }
        // Load Postback Data Event
        public bool LoadPostData(string postDataKey,
        NameValueCollection postCollection)
        {
            Trace("Lifecycle: Load PostBack Data Event.");
            Page.RegisterRequiresRaiseEvent(this);
            return true;
        }
        // Load Event
        override protected void OnLoad(System.EventArgs e)
        {
            Trace("Lifecycle: Load Event.");
            base.OnLoad(e);
        }
        // Post Data Changed Event
        public void RaisePostDataChangedEvent()
        {
            Trace("Lifecycle: Post Data Changed Event.");
        }
        // Postback Event
        public void RaisePostBackEvent(string argument)
        {
            Trace("Lifecycle: PostBack Event.");
        }
        // PreRender Event
        override protected void OnPreRender(System.EventArgs e)
        {
            Trace("Lifecycle: PreRender Event.");
            Page.RegisterRequiresPostBack(this);
            base.OnPreRender(e);
        }
        // Save ViewState
        override protected object SaveViewState()
        {
            Trace("Lifecycle: Save ViewState.");
            return base.SaveViewState();
        }
        // Render Event
        override protected void Render(HtmlTextWriter writer)
        {
            base.Render(writer);
            Trace("Lifecycle: Render Event.");
            writer.Write("<h3>LifeCycle Control</h3>");
        }
        // Unload Event
        override protected void OnUnload(System.EventArgs e)
        {
            Trace("Lifecycle: Unload Event.");
            base.OnUnload(e);
        }
        // Dispose Event
        public override void Dispose()
        {
            Trace("Lifecycle: Dispose Event.");
            base.Dispose();
        }
        private void Trace(string info)
        {
            Context.Trace.Warn(info);
            Debug.WriteLine(info);
        }
    }
}


Listings 5-20 and 5-21 outline the Web Form that hosts the control, with the ASP.NET tracing mechanism turned on. The UI appearance is a single button on the Web Form with trace output turned on.

Listing 5-20. The Life Cycle Web Form .aspx Page File

<%@ Register TagPrefix="apressUC" TagName="ControlsBookFooter"
Src="..\ControlsBookFooter.ascx" %>
<%@ Register TagPrefix="apressUC" TagName="ControlsBookHeader"
Src="..\ControlsBookHeader.ascx" %>
<%@ Register TagPrefix="apress" Namespace="ControlsBookLib.Ch05"
Assembly="ControlsBookLib" %>
<%@ Page Trace="true" language="c#" Codebehind="LifeCycle.aspx.cs"
AutoEventWireup="false" Inherits="ControlsBookWeb.Ch05.LifeCycle" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<
HEAD>
<
title>Ch05 Lifecycle</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</
HEAD>
<
body MS_POSITIONING="FlowLayout">
<form id="LifeCycle" method="post" runat="server">
<apressUC:ControlsBookHeader id="Header" runat="server" ChapterNumber="5"
ChapterTitle="Event-based Programming" />
<h3>Ch05 Lifecycle</h3>
<apress:Lifecycle id="life1" runat="server" />
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
<apressUC:ControlsBookFooter id="Footer" runat="server" />
</form>
</
body>
</
HTML>

Listing 5-21. The Life Cycle Web Form Code-Behind Class File

using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace ControlsBookWeb.Ch05
{
    public class LifeCycle : System.Web.UI.Page
    {
        protected System.Web.UI.WebControls.Button Button1;
        protected ControlsBookLib.Ch05.Lifecycle life1;
        private void Page_Load(object sender, System.EventArgs e)
        {
        }
        #region Web Form Designer generated code
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
        }
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.Load += new System.EventHandler(this.Page_Load);
        }
        #endregion
    }
}


The first execution of the Life Cycle Web Form results in an HTTP GET protocol request and generates the life cycle events shown in the ASP.NET Trace output of Figure 5-23.



Figure 5-23. The Lifecycle.aspx trace output from an HTTP GET request

We next cover the life cycle events that occur when an HTTP GET request occurs, starting with the Init event.
 

Total Pages : 12 89101112
Image Loading...