ptg 1694 CHAPTER 38 Using Server-Side ASP.NET AJAX Runat=”server” /> <asp:Button id=”btnSearch” Text=”Search” OnClick=”btnSearch_Click” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> <asp:UpdatePanel id=”upResults” UpdateMode=”Conditional” Runat=”server”> <ContentTemplate> Results Time: <%= DateTime.Now.ToString(“T”) %> <br /> <asp:GridView id=”grdResults” runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html> UpdatePanels and JavaScript You must take special care when using JavaScript with UpdatePanel controls. If you use the standard methods of the ClientScriptManager class for working with JavaScript, they will fail when called during an asynchronous request. For example, I often use the Page.ClientScript.RegisterStartupScript() method from my server-side code to inject a JavaScript script into a page dynamically. The page in Listing 38.8 contains a Delete All Files button. When you click the button, and the FileHelper.DeleteAll() method returns true, a JavaScript alert box displays the message All Files Deleted Successfully! (see Figure 38.7). From the Library of Wow! eBook ptg 1695 Using the UpdatePanel Control 38 LISTING 38.8 ShowAlert.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnDeleteAll_Click(object sender, EventArgs e) { if (FileHelper.DeleteAll() == true) { string script = @”alert(‘All Files Deleted Successfully!’);”; Page.ClientScript.RegisterStartupScript(this.GetType(), “filesDeleted”, ➥ script, true); } } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>Show Alert</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:Button id=”btnDeleteAll” Text=”Delete All Files” OnClick=”btnDeleteAll_Click” FIGURE 38.7 Displaying a JavaScript alert. From the Library of Wow! eBook ptg 1696 CHAPTER 38 Using Server-Side ASP.NET AJAX Runat=”server” /> </div> </form> </body> </html> Unfortunately, the page in Listing 38.8 does not work when the Button control is wrapped in an UpdatePanel. The JavaScript alert never appears after you click the button. The page fails silently. If you need to inject JavaScript into a page when performing an asynchronous postback, you need to take advantage of the methods exposed by the ScriptManager class. The ScriptManager class duplicates all the standard JavaScript methods of the ClientScriptManager class, including the following: . RegisterArrayDeclaration()—Enables you to add a JavaScript array to the page. . RegisterClientScriptBlock()—Enables you to add an inline JavaScript script right after the opening <form> tag. . RegisterClientScriptInclude()—Enables you to add a JavaScript <script src=””> tag to a page. . RegisterClientScriptResource()—Enables you to add a reference to a JavaScript file embedded in an assembly. . RegisterExpandoAttribute()—Enables you to register a tag expando. . RegisterOnSubmitStatement()—Enables you to register a JavaScript script that is executed when the form is submitted. . RegisterStartupScript()—Enables you to add an inline JavaScript script right before the closing <form> tag. The page in Listing 38.9 demonstrates how you can add JavaScript from the server to a page when performing an asynchronous postback. LISTING 38.9 ShowAlertUpdatePanel.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void btnDeleteAll_Click(object sender, EventArgs e) { if (FileHelper.DeleteAll() == true) { From the Library of Wow! eBook ptg 1697 Using the UpdatePanel Control 38 string script = @”alert(‘All Files Deleted Successfully!’);”; ScriptManager.RegisterStartupScript(this, this.GetType(), “filesDeleted”, ➥ script, true); } } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head id=”Head1” runat=”server”> <title>Show Alert UpdatePanel</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:ScriptManager id=”sm1” Runat=”server” /> <asp:UpdatePanel id=”up1” runat=”server”> <ContentTemplate> UpdatePanel Time: <%= DateTime.Now.ToString(“T”) %> <br /> <asp:Button id=”btnDeleteAll” Text=”Delete All Files” OnClick=”btnDeleteAll_Click” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html> In Listing 38.9, the Button control is wrapped in an UpdatePanel. When you click the button, the ScriptManager.RegisterStartupScript() method adds the JavaScript alert to the page dynamically. UpdatePanel Server-Side Page Execution Life Cycle You need to understand that a server-side page goes through its normal page execution life cycle when you perform an asynchronous postback. The Page PreInit, Init, Load, and PreRender events are raised for an asynchronous postback in just the same way as these events are raised for a normal postback. From the Library of Wow! eBook ptg 1698 CHAPTER 38 Using Server-Side ASP.NET AJAX The page in Listing 38.10 logs each server event and displays the log in a BulletedList control (see Figure 38.8). FIGURE 38.8 Viewing an asynchronous postback’s server lifecycle. LISTING 38.10 ServerLifecycle.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> public ArrayList _log = new ArrayList(); void Page_PreInit() { _log.Add(“PreInit “ + sm1.IsInAsyncPostBack); } void Page_Init() { _log.Add(“Init “ + sm1.IsInAsyncPostBack); } void Page_Load() { _log.Add(“Load “ + sm1.IsInAsyncPostBack); } void Page_PreRender() { _log.Add(“PreRender “ + sm1.IsInAsyncPostBack); // Show Lifecycle log bltLog.DataSource = _log; From the Library of Wow! eBook ptg 1699 Using the UpdatePanel Control 38 bltLog.DataBind(); } </script> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>Server Lifecycle</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:ScriptManager id=”sm1” runat=”server” /> <asp:UpdatePanel id=”up1” runat=”server”> <ContentTemplate> <asp:Button id=”btnLog” Text=”Show Server Page Lifecycle” Runat=”server” /> <asp:BulletedList id=”bltLog” Runat=”server” /> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html> When you first open the page in Listing 38.10, each page event is listed in the BulletedList control. Next to each event, you see the word False. The ScriptManager.IsInAsyncPostBack property displays whether the page is processed within a normal postback or an asynchronous postback. The page includes an UpdatePanel that contains a Button control. Clicking the button initiates an asynchronous postback. After you click the button, the exact same list of events appears in the BulletedList control. The exact same events are raised during an asynchronous postback as are raised during a normal postback. From the Library of Wow! eBook ptg 1700 CHAPTER 38 Using Server-Side ASP.NET AJAX NOTE ScriptManager.IsInAsyncPostBack has the value False when the PreInit event is raised during an asynchronous postback. This IsInAsyncPostBack property is updated after this event. (So it is just wrong.) UpdatePanel Client-Side Page Execution Life Cycle A page that contains a ScriptManager control not only has a server-side page execution life cycle, it also has a client-side page execution life cycle. The following series of events happen on the client-side: . Application.init—Raised when a page is first requested. This event is not raised during an asynchronous postback. . PageRequestManager.initializeRequest—Raised before an asynchronous request to the server starts. . PageRequestManager.beginRequest—Raised before an asynchronous request to the server starts. . PageRequestManager.pageLoading—Raised after an asynchronous response is received from the server but before UpdatePanel content is updated. . PageRequestManager.pageLoaded—Raised after an asynchronous response is received from the server and after UpdatePanel content is updated. Also raised during the initial page request. . Application.load—Raised during both normal and asynchronous postbacks. . PageRequestManager.endRequest—Raised after an asynchronous response both when there is and when there isn’t an error. . Application.unload—Raised before the user leaves or reloads the page. Two client-side objects raise client life-cycle events: Sys.Application object and Sys.WebForms.PageRequestManager. The Sys.Application events happen in a page regard- less of whether the page contains UpdatePanel controls. The Sys.WebForms.PageRequestManager events are tied to UpdatePanels. The page in Listing 38.11 illustrates when each of these client-side events occurs. The page takes advantage of ASP.NET AJAX’s client-side trace support. When each client event occurs, Sys.Debug.trace() is used to write a message to the Trace Console. Figure 38.9 shows the page after the Async Postback button is clicked. From the Library of Wow! eBook ptg 1701 Using the UpdatePanel Control 38 LISTING 38.11 ClientLifecycle.aspx <%@ Page Language=”C#” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <html xmlns=”http://www.w3.org/1999/xhtml”> <head runat=”server”> <title>Client Lifecycle</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:ScriptManager ID=”ScriptManager1” runat=”server” /> <asp:UpdatePanel ID=”up1” runat=”server”> <ContentTemplate> <asp:Button ID=”btnAsync” Text=”Async Postback” runat=”server” /> </ContentTemplate> </asp:UpdatePanel> <asp:Button ID=”Button1” Text=”Normal Postback” runat=”server” /> <br /><br /> <textarea id=”TraceConsole” cols=”60” rows=”10”></textarea> </div> </form> </body> <script type=”text/javascript”> Sys.Application.add_init(application_init); FIGURE 38.9 Viewing an asynchronous page’s client execution lifecycle. From the Library of Wow! eBook ptg 1702 CHAPTER 38 Using Server-Side ASP.NET AJAX function application_init() { Sys.Debug.trace(“Application.Init”); var prm = Sys.WebForms.PageRequestManager.getInstance(); prm.add_initializeRequest( prm_initializeRequest ); prm.add_beginRequest( prm_beginRequest ); prm.add_pageLoading( prm_pageLoading ); prm.add_pageLoaded( prm_pageLoaded ); prm.add_endRequest( prm_endRequest ); } function pageLoad() { Sys.Debug.trace(“Application.Load”); } function prm_initializeRequest() { Sys.Debug.trace(“PageRequestManager.initializeRequest”); } function prm_beginRequest() { Sys.Debug.trace(“PageRequestManager.beginRequest”); } function prm_pageLoading() { Sys.Debug.trace(“PageRequestManager.pageLoading”); } function prm_pageLoaded() { Sys.Debug.trace(“PageRequestManager.pageLoaded”); } function prm_endRequest() { Sys.Debug.trace(“PageRequestManager.endRequest”); } function pageUnload() { alert(“Application.Unload”); From the Library of Wow! eBook ptg 1703 Using the UpdatePanel Control 38 } </script> </html> Because we are discussing client-side events, we have moved over into the JavaScript world. The script in Listing 38.11 has to be written in JavaScript because it executes within the browser and not on the server. Different information is available during each client-side event. You can access the event information by reading the properties of the second parameter passed to the event handler. What follows is the event information passed to each event handler. InitializeRequestEventArgs Passed to the PageRequestManager.initializeRequest event handler. Supports the follow- ing properties: . cancel—Enables you to cancel the current asynchronous postback. . postBackElement—The element that caused the asynchronous postback. . request—The request object used to perform the asynchronous postback. BeginRequestEventArgs Passed to the PageRequestManager.beginRequest event handler. Supports the following properties: . postBackElement—The element that caused the asynchronous postback. . request—The request object used to perform the asynchronous postback. PageLoadingEventArgs Passed to the PageRequestManager.pageLoading event handler. Supports the following properties: . dataItems—The data items registered with the ScriptManager.RegisterDataItem() method. . panelsDeleting—The array of UpdatePanel elements being deleted. . panelsUpdating—The array of UpdatePanel elements being updated. PageLoadedEventArgs Passed to the PageRequestManager.pageLoaded event handler. Supports the following properties: . dataItems—The data items registered with the ScriptManager.RegisterDataItem() method. . panelsCreated—The array of UpdatePanel elements created. . panelsUpdated—The array of UpdatePanel elements updated. From the Library of Wow! eBook . The Sys.Application events happen in a page regard- less of whether the page contains UpdatePanel controls. The Sys.WebForms.PageRequestManager events are tied to UpdatePanels. The page in Listing. <div> < ;asp: ScriptManager ID=”ScriptManager1” runat=”server” /> < ;asp: UpdatePanel ID=”up1” runat=”server”> <ContentTemplate> < ;asp: Button ID=”btnAsync” Text=”Async Postback”. prm_initializeRequest ); prm.add_beginRequest( prm_beginRequest ); prm.add_pageLoading( prm_pageLoading ); prm.add_pageLoaded( prm_pageLoaded ); prm.add_endRequest( prm_endRequest ); } function pageLoad()