Canceling an Asynchronous Postback
Asynchronous postbacks are implemented in ASP.NET by using NET UpdatePanel Web server controls on the page. The UpdatePanel control removes the requirement to refresh the whole page with each postback, which improves the user experience. In the browser, the Sys.WebForms.PageRequestManager class in the Microsoft AJAX Library manages events in the client page life cycle for asynchronous postbacks. You can customize how asynchronous postbacks occur by handling events exposed by the PageRequestManager class.
In this tutorial you will use the initializeRequest event of the PageRequestManager class to cancel the currently executing asynchronous postback.
For information about the sequence of events raised in the PageRequestManager class, see Working with PageRequestManager Events.
Prerequisites
To implement the procedures in your own development environment you need:
Microsoft Visual Studio 2005 or Microsoft Visual Web Developer Express.
An AJAX-enabled ASP.NET Web site.
Creating Script That Cancels Postbacks
You will start by creating ECMAScript (JavaScript) code that manages the asynchronous postback in the browser.
To create JavaScript code to cancel a postback
In the ASP.NET Web site, add a new JScript file and name it CancelPostback.js.
Add the following script to the file:
var divElem = 'AlertDiv'; var messageElem = 'AlertMessage'; Sys.Application.add_load(ApplicationLoadHandler) function ApplicationLoadHandler(sender, args) { Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(CheckStatus); } function CheckStatus(sender, args) { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'CancelRefresh') { prm.abortPostBack(); } else if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') { args.set_cancel(true); ActivateAlertDiv('visible', 'Still working on previous request.'); } else if (!prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') { ActivateAlertDiv('visible', 'Retrieving headlines.'); } } function ActivateAlertDiv(visString, msg) { var adiv = $get(divElem); var aspan = $get(messageElem); adiv.style.visibility = visString; aspan.innerHTML = msg; } if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
var divElem = 'AlertDiv'; var messageElem = 'AlertMessage'; Sys.Application.add_load(ApplicationLoadHandler) function ApplicationLoadHandler(sender, args) { Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(CheckStatus); } function CheckStatus(sender, args) { var prm = Sys.WebForms.PageRequestManager.getInstance(); if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'CancelRefresh') { prm.abortPostBack(); } else if (prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') { args.set_cancel(true); ActivateAlertDiv('visible', 'Still working on previous request.'); } else if (!prm.get_isInAsyncPostBack() & args.get_postBackElement().id == 'RefreshButton') { ActivateAlertDiv('visible', 'Retrieving headlines.'); } } function ActivateAlertDiv(visString, msg) { var adiv = $get(divElem); var aspan = $get(messageElem); adiv.style.visibility = visString; aspan.innerHTML = msg; } if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
The script performs the following tasks:
Defines a handler for the load event of the Sys.Application class. This handler in turn registers a handler named CheckStatus for the initializeRequest event of the PageRequestManager class.
Defines the CheckStatus handler to check whether an asynchronous postback is currently executing, and to determine the name of the element that caused the postback.
Defines an ActivateAlertDiv function that toggles the visibility of a <div> element that is used to display messages.
Using the Script with an UpdatePanel Control
In this procedure you will use the script you created in a page that contains an UpdatePanel control. The script cancels the postback if the user clicks a link while the asynchronous postback is underway.
To create a page where users can cancel a postback
Create a new single-file ASP.NET Web page named Default.aspx and switch to Design view.
In the AJAX Extensions tab of the toolbox, double-click the ScriptManager control to add it to the page.
In the toolbox, double-click the UpdatePanel control to add it to the page.
Switch to Source view and add the following style rules to a <style> block in the <head> element of the page:
<style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1{ width: 400px; height: 200px; border: solid 1px gray; } div.AlertStyle { font-size: smaller; background-color: #FFC080; width: 400px; height: 20px; visibility: hidden; } </style>
<style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1{ width: 400px; height: 200px; border: solid 1px gray; } div.AlertStyle { font-size: smaller; background-color: #FFC080; width: 400px; height: 20px; visibility: hidden; } </style>
The style rules define the height and width of the <div> element that is rendered by the UpdatePanel control. The rules also define the appearance of the nested <div> element that displays a progress message.
Add the following markup inside the <ContentTemplate> element of the <asp:UpdatePanel> element:
<asp:DataList ID="HeadlineList" runat="server"> <HeaderTemplate> <strong>Headlines</strong> </HeaderTemplate> <ItemTemplate> <%# Eval("Value") %> </ItemTemplate> <FooterTemplate> </FooterTemplate> <FooterStyle HorizontalAlign="right" /> </asp:DataList> <p style="text-align:right"> <asp:Button ID="RefreshButton" Text="Refresh" runat="server" OnClick="NewsClick_Handler" /> </p> <div id="AlertDiv" class="AlertStyle"> <span id="AlertMessage"></span> <asp:LinkButton ID="CancelRefresh" runat="server"> Cancel</asp:LinkButton>
<asp:DataList ID="HeadlineList" runat="server"> <HeaderTemplate> <strong>Headlines</strong> </HeaderTemplate> <ItemTemplate> <%# Eval("Value") %> </ItemTemplate> <FooterTemplate> </FooterTemplate> <FooterStyle HorizontalAlign="right" /> </asp:DataList> <p style="text-align:right"> <asp:Button ID="RefreshButton" Text="Refresh" runat="server" OnClick="NewsClick_Handler" /> </p> <div id="AlertDiv" class="AlertStyle"> <span id="AlertMessage"></span> <asp:LinkButton ID="CancelRefresh" runat="server"> Cancel</asp:LinkButton>
The markup performs the following tasks:
Defines a DataList control whose items are bound to a Value field, which will be defined later in this procedure as a SortedList object.
Defines a Button control that causes an asynchronous postback.
Defines a <div> element that will be used to display a message during an asynchronous postback. The <div> element also contains a LinkButton control that enables the postback to be canceled.
In the <script runat="server"> element, add the following server code as the Click event handler, which is for the Refresh button in the UpdatePanel control.
Protected Sub NewsClick_Handler(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(2000) HeadlineList.DataSource = GetHeadlines() HeadlineList.DataBind() End Sub
protected void NewsClick_Handler(object sender, EventArgs e) { System.Threading.Thread.Sleep(2000); HeadlineList.DataSource = GetHeadlines(); HeadlineList.DataBind(); }
The code uses data binding to read and display a list of headlines in the DataList control.
Note
The handler for the Click event intentionally introduces a delay for this tutorial. In practice, you would not introduce a delay. Instead, the delay would be the result of server traffic or of server code that takes a long time to process, such as a long-running database query.
Inside the <script> element, add the following code for the page's Load event:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not (IsPostBack) Then HeadlineList.DataSource = GetHeadlines() HeadlineList.DataBind() End If End Sub
protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { HeadlineList.DataSource = GetHeadlines(); HeadlineList.DataBind(); } }
The code checks whether the current request is a postback. If the request is not a postback, the DataList control is bound to a list of headlines. (During asynchronous postbacks, data binding occurs in the NewClick_Handler method that you created in the previous step.)
Inside the <script> element, add the following code to generate headlines:
' Helper method to simulate news headline fetch. Private Function GetHeadlines() As SortedList Dim headlines As New SortedList() headlines.Add(1, "This is headline 1.") headlines.Add(2, "This is headline 2.") headlines.Add(3, "This is headline 3.") headlines.Add(4, "This is headline 4.") headlines.Add(5, "This is headline 5.") headlines.Add(6, "(Last updated on " & DateTime.Now.ToString() & ")") Return headlines End Function
// Helper method to simulate news headline fetch. private SortedList GetHeadlines() { SortedList headlines = new SortedList(); headlines.Add(1, "This is headline 1."); headlines.Add(2, "This is headline 2."); headlines.Add(3, "This is headline 3."); headlines.Add(4, "This is headline 4."); headlines.Add(5, "This is headline 5."); headlines.Add(6, "(Last updated on " + DateTime.Now.ToString() + ")"); return headlines; }
The headlines in this tutorial are created as a static list. In a real application they would be generated dynamically.
Switch to Design view and make sure that the page resembles the following figure.
Select the ScriptManager control.
In the Properties window, select the Scripts property and click the ellipsis (…) button to display the ScriptReference Collection Editor dialog box.
Click Add to add a script reference.
Set the Path property of the script reference to CancelPostback.js, which is the JavaScript file that you created previously.
Adding a script reference by using the Scripts collection of the ScriptManager makes sure that the script is loaded after the Microsoft AJAX Library has loaded.
Click OK to close the ScriptReference Collection Editor dialog box.
Save your changes and press CTRL+F5 to view the page in a browser.
Click the Refresh button and wait for the panel to refresh.
A message is displayed with an option to cancel the postback.
Click the Refresh button again and after the message appears, click the Refresh button again and wait for the panel to refresh.
The text of the message changes to indicate that the previous refresh is still in progress. The second refresh is ignored.
Click the Refresh button again, and when the message appears, click the Cancel link to cancel the postback.
This time, the time displayed in the UpdatePanel control does not change, because the asynchronous postback was canceled.
<%@ Page Language="VB" %> <%@ Import Namespace="System.Collections.Generic" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server"> Protected Sub NewsClick_Handler(ByVal sender As Object, ByVal e As EventArgs) System.Threading.Thread.Sleep(2000) HeadlineList.DataSource = GetHeadlines() HeadlineList.DataBind() End Sub Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) If Not (IsPostBack) Then HeadlineList.DataSource = GetHeadlines() HeadlineList.DataBind() End If End Sub ' Helper method to simulate news headline fetch. Private Function GetHeadlines() As SortedList Dim headlines As New SortedList() headlines.Add(1, "This is headline 1.") headlines.Add(2, "This is headline 2.") headlines.Add(3, "This is headline 3.") headlines.Add(4, "This is headline 4.") headlines.Add(5, "This is headline 5.") headlines.Add(6, "(Last updated on " & DateTime.Now.ToString() & ")") Return headlines End Function </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Canceling Postback Example</title> <style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1{ width: 400px; height: 200px; border: solid 1px gray; } div.AlertStyle { font-size: smaller; background-color: #FFC080; width: 400px; height: 20px; visibility: hidden; } </style> </head> <body> <form id="form1" runat="server"> <div > <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="CancelPostback.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="Server" > <ContentTemplate> <asp:DataList ID="HeadlineList" runat="server"> <HeaderTemplate> <strong>Headlines</strong> </HeaderTemplate> <ItemTemplate> <%# Eval("Value") %> </ItemTemplate> <FooterTemplate> </FooterTemplate> <FooterStyle HorizontalAlign="right" /> </asp:DataList> <p style="text-align:right"> <asp:Button ID="RefreshButton" Text="Refresh" runat="server" OnClick="NewsClick_Handler" /> </p> <div id="AlertDiv" class="AlertStyle"> <span id="AlertMessage"></span> <asp:LinkButton ID="CancelRefresh" runat="server"> Cancel</asp:LinkButton> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html>
<%@ Page Language="C#" %> <%@ Import Namespace="System.Collections.Generic" %> <!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 NewsClick_Handler(object sender, EventArgs e) { System.Threading.Thread.Sleep(2000); HeadlineList.DataSource = GetHeadlines(); HeadlineList.DataBind(); } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { HeadlineList.DataSource = GetHeadlines(); HeadlineList.DataBind(); } } // Helper method to simulate news headline fetch. private SortedList GetHeadlines() { SortedList headlines = new SortedList(); headlines.Add(1, "This is headline 1."); headlines.Add(2, "This is headline 2."); headlines.Add(3, "This is headline 3."); headlines.Add(4, "This is headline 4."); headlines.Add(5, "This is headline 5."); headlines.Add(6, "(Last updated on " + DateTime.Now.ToString() + ")"); return headlines; } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Canceling Postback Example</title> <style type="text/css"> body { font-family: Tahoma; } #UpdatePanel1{ width: 400px; height: 200px; border: solid 1px gray; } div.AlertStyle { font-size: smaller; background-color: #FFC080; width: 400px; height: 20px; visibility: hidden; } </style> </head> <body> <form id="form1" runat="server"> <div > <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="CancelPostback.js" /> </Scripts> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="Server" > <ContentTemplate> <asp:DataList ID="HeadlineList" runat="server"> <HeaderTemplate> <strong>Headlines</strong> </HeaderTemplate> <ItemTemplate> <%# Eval("Value") %> </ItemTemplate> <FooterTemplate> </FooterTemplate> <FooterStyle HorizontalAlign="right" /> </asp:DataList> <p style="text-align:right"> <asp:Button ID="RefreshButton" Text="Refresh" runat="server" OnClick="NewsClick_Handler" /> </p> <div id="AlertDiv" class="AlertStyle"> <span id="AlertMessage"></span> <asp:LinkButton ID="CancelRefresh" runat="server"> Cancel</asp:LinkButton> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html>
Review
This tutorial shows how to write JavaScript code that cancels an asynchronous postback. The script provides a handler for the initializeRequest event of the PageRequestManager class. In the initializeRequest event, you can determine which element caused the postback and whether a postback is already underway. You can then take appropriate action. In the tutorial, the code displays a <div> element that contains a cancel button.
To display UpdatePanel control status automatically, you can use the UpdateProgress control. For more information, see Introduction to the UpdateProgress Control.
See Also
Tasks
Programming UpdateProgress Controls in Client Script
Concepts
Working with PageRequestManager Events