Giving Precedence to a Specific Asynchronous Postback

By default, when a page makes multiple asynchronous postbacks at the same time, the postback made most recently takes precedence. In some scenarios, you might want to give precedence to a specific asynchronous postback and cancel the other postbacks.

In this tutorial, you will control which postback takes precedence. You can do this by creating an event handler for the initializeRequest event of the PageRequestManager class. 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 Gives Precedence to a Specific Postback Element

You will start by creating ECMAScript (JavaScript) code that manages the asynchronous postback in the browser.

To create a script that gives precedence to a specific postback element

  1. In the ASP.NET Web site, add a JScript file and name it PostbackPrecedence.js.

  2. Add the following script to the file:

    Sys.Application.add_load(ApplicationLoadHandler)
    function ApplicationLoadHandler(sender, args)
    {
        if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack())
        {
          Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequest);
        }
    }
    
    var divElem = 'AlertDiv';
    var messageElem = 'AlertMessage';
    var exclusivePostBackElement = 'Button1';
    var lastPostBackElement;
    function InitializeRequest(sender, args)
    { 
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        if (prm.get_isInAsyncPostBack() && 
            args.get_postBackElement().id === exclusivePostBackElement) 
        {
            if (lastPostBackElement === exclusivePostBackElement)
            {
              args.set_cancel(true);
              ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.');
              setTimeout("ActivateAlertDiv('hidden','')", 1500);
            }
            else if (lastPostBackElement !== exclusivePostBackElement)
            {
              prm.abortPostBack();
            }
        }
        else if (prm.get_isInAsyncPostBack() && 
                 args.get_postBackElement().id !== exclusivePostBackElement)
        {
            if (lastPostBackElement === exclusivePostBackElement)
            {
                args.set_cancel(true);
                ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.');
                setTimeout("ActivateAlertDiv('hidden','')", 1500);
            }       
        }
        lastPostBackElement = args.get_postBackElement().id;      
    }
    
    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();
    
    Sys.Application.add_load(ApplicationLoadHandler)
    function ApplicationLoadHandler(sender, args)
    {
        if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack())
        {
          Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequest);
        }
    }
    
    var divElem = 'AlertDiv';
    var messageElem = 'AlertMessage';
    var exclusivePostBackElement = 'Button1';
    var lastPostBackElement;
    function InitializeRequest(sender, args)
    { 
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        if (prm.get_isInAsyncPostBack() && 
            args.get_postBackElement().id === exclusivePostBackElement) 
        {
            if (lastPostBackElement === exclusivePostBackElement)
            {
              args.set_cancel(true);
              ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.');
              setTimeout("ActivateAlertDiv('hidden','')", 1500);
            }
            else if (lastPostBackElement !== exclusivePostBackElement)
            {
              prm.abortPostBack();
            }
        }
        else if (prm.get_isInAsyncPostBack() && 
                 args.get_postBackElement().id !== exclusivePostBackElement)
        {
            if (lastPostBackElement === exclusivePostBackElement)
            {
                args.set_cancel(true);
                ActivateAlertDiv('visible', 'A previous postback is still executing. The new postback has been canceled.');
                setTimeout("ActivateAlertDiv('hidden','')", 1500);
            }       
        }
        lastPostBackElement = args.get_postBackElement().id;      
    }
    
    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. The handler in turn registers a handler named InitializeRequest for the initializeRequest event of the PageRequestManager class.

    • Defines the InitializeRequest handler to check whether an asynchronous postback is currently executing, and to determine the name of the element that caused the postback. If the element that caused the postback is one that you have specified as an exclusive postback element (one that should take precedence), the new postback is canceled by setting the cancel property of the InitializeRequestEventArgs class.

    • Defines an ActivateAlertDiv function that toggles the visibility of a <div> element on the page in order to display messages.

Using the Script with an UpdatePanel Control

In this procedure you will use the script that you created in a page. The page contains one button whose postback takes precedence over the postback of another button on the page.

To create a page to make sure postback from one postback takes precedence

  1. Create a new single-file ASP.NET Web page and switch to Design view.

  2. In the AJAX Extensions tab of the toolbox, double-click the ScriptManager control to add it to the page.

    UpdatePanel Tutorial

  3. Double-click the UpdatePanel control two times to add two instances of the control to the page.

    UpdateProgress Tutorial

  4. In each UpdatePanel control, from the Standard tab of the toolbox. add a Label control and a Button control.

  5. Set the Text value of the Label control in both panels to Panel Initially Rendered.

    UpdateProgress Tutorial

  6. Double-click each Button control to add a handler for each button's Click event.

  7. Add the following code for the Click handlers, which artificially creates a delay and then displays the current time in the panel where the postback originated:

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
        System.Threading.Thread.Sleep(4000)
        Label1.Text = "Last update from server " & DateTime.Now.ToString()
    End Sub
    
    Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs)
        System.Threading.Thread.Sleep(1000)
        Label2.Text = "Last update from server " & DateTime.Now.ToString()
    End Sub
    
    protected void Button1_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(4000);
        Label1.Text = "Last update from server " + DateTime.Now.ToString();        
    }
    
    protected void Button2_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(1000);
        Label2.Text = "Last update from server " + DateTime.Now.ToString();        
    }
    

    Note

    The handlers for the Click event intentionally introduce 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.

  8. Switch to Source view, and then add the following <style> block in the <head> element of the page:

        <style type="text/css">
        body {
            font-family: Tahoma;
        }
        #UpdatePanel1, #UpdatePanel2 {
          width: 400px;
          height: 100px;
          border: solid 1px gray;
        }
        div.MessageStyle {
          background-color: #FFC080;
          top: 95%;
          left: 1%;
          height: 20px;
          width: 600px;
          position: absolute;
          visibility: hidden;
        }
        </style>
    
        <style type="text/css">
        body {
            font-family: Tahoma;
        }
        #UpdatePanel1, #UpdatePanel2 {
          width: 400px;
          height: 100px;
          border: solid 1px gray;
        }
        div.MessageStyle {
          background-color: #FFC080;
          top: 95%;
          left: 1%;
          height: 20px;
          width: 600px;
          position: absolute;
          visibility: hidden;
        }
        </style>
    

    The style rules define the size of the <div> element that is rendered by the UpdatePanel control and of the <div> element that alerts the user when a postback is canceled.

  9. Add the following markup inside the <form> element on the page:

    <div id="AlertDiv" class="MessageStyle">
    <span id="AlertMessage"></span>
    </div>
    
    <div id="AlertDiv" class="MessageStyle">
    <span id="AlertMessage"></span>
    </div>
    

    The markup defines a <div> element that will display a message when an asynchronous postback is canceled because one is already in progress.

  10. Switch to Design view.

  11. Click inside the first UpdatePanel control, and then from the AJAX Extensions tab in the toolbox, add an UpdateProgress control.

  12. Click inside the UpdateProgress control and type Panel1 updating ….

    This sets the ProgressTemplate property.

  13. Select the UpdateProgress control, and then in the Properties window, set the AssociatedUpdatePanelID property to UpdatePanel1.

    The page in the designer will resemble the following figure:

    UpdateProgress Tutorial

  14. Click inside the second UpdatePanel control and add a second UpdateProgress control.

  15. Click inside the UpdateProgress control and type Panel2 updating ….

    This sets the ProgressTemplate property.

  16. Select the UpdateProgress control, and then in the Properties window, set the AssociatedUpdatePanelID property to UpdatePanel2.

    The page in the designer will resemble the following figure:

    UpdateProgress Tutorial

  17. Select the ScriptManager control.

  18. In the Properties window, select the Scripts property and click the ellipsis (…) button to display the ScriptReference Collection Editor dialog box.

  19. Click Add to add a script reference.

  20. Set the Path property of the script reference to PostbackPrecedence.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.

    UpdatePanel Tutorial

  21. Click OK to close the ScriptReference Collection Editor dialog box.

  22. Save your changes and then press CTRL+F5 to view the page in a browser.

  23. Click the button in the first panel and then click the button in the second panel.

    A message is displayed that indicates that the new postback was canceled. The button in the first panel must finish before a new postback is initiated. The script file provides the logic to enforce this behavior.

  24. Click the button in the second panel and then click the button in the first panel.

    The button in the second panel does not take precedence because it was not coded to do this in the script file. Therefore, no warning message is displayed and a new postback is initiated by the button in the first panel. This is the default behavior of asynchronous postbacks—the most recent postback takes precedence.

    <%@ Page Language="VB" %>
    <!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 Button1_Click(ByVal sender As Object, ByVal e As EventArgs)
            System.Threading.Thread.Sleep(4000)
            Label1.Text = "Last update from server " & DateTime.Now.ToString()
        End Sub
    
        Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs)
            System.Threading.Thread.Sleep(1000)
            Label2.Text = "Last update from server " & DateTime.Now.ToString()
        End Sub
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Postback Precedence Example</title>
        <style type="text/css">
        body {
            font-family: Tahoma;
        }
        #UpdatePanel1, #UpdatePanel2 {
          width: 400px;
          height: 100px;
          border: solid 1px gray;
        }
        div.MessageStyle {
          background-color: #FFC080;
          top: 95%;
          left: 1%;
          height: 20px;
          width: 600px;
          position: absolute;
          visibility: hidden;
        }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Scripts>
                <asp:ScriptReference Path="PostBackPrecedence.js" />
                </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel  ID="UpdatePanel1" UpdateMode="Conditional" runat="Server" >
                    <ContentTemplate>
                    <strong>UpdatePanel 1</strong><br />
    
                    This postback takes precedence.<br />
                    <asp:Label ID="Label1" runat="server">Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />&nbsp;
                    <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
                    <ProgressTemplate>
                    Panel1 updating...
                    </ProgressTemplate>
                    </asp:UpdateProgress>
                    </ContentTemplate>
                </asp:UpdatePanel>
                <asp:UpdatePanel  ID="UpdatePanel2" UpdateMode="Conditional" runat="Server" >
                    <ContentTemplate>
                    <strong>UpdatePanel 2</strong><br />
                    <asp:Label ID="Label2" runat="server">Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" />
                    <asp:UpdateProgress ID="UpdateProgress2" runat="server" AssociatedUpdatePanelID="UpdatePanel2">
                    <ProgressTemplate>
                    Panel2 updating...
                    </ProgressTemplate>
                    </asp:UpdateProgress>
                    </ContentTemplate>
                </asp:UpdatePanel>
               <div id="AlertDiv" class="MessageStyle">
               <span id="AlertMessage"></span>
               </div>
            </div>
        </form>
    </body>
    </html>
    
    <%@ 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 Button1_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(4000);
            Label1.Text = "Last update from server " + DateTime.Now.ToString();        
        }
    
        protected void Button2_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(1000);
            Label2.Text = "Last update from server " + DateTime.Now.ToString();        
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Postback Precedence Example</title>
        <style type="text/css">
        body {
            font-family: Tahoma;
        }
        #UpdatePanel1, #UpdatePanel2 {
          width: 400px;
          height: 100px;
          border: solid 1px gray;
        }
        div.MessageStyle {
          background-color: #FFC080;
          top: 95%;
          left: 1%;
          height: 20px;
          width: 600px;
          position: absolute;
          visibility: hidden;
        }
        </style>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:ScriptManager ID="ScriptManager1" runat="server">
                <Scripts>
                <asp:ScriptReference Path="PostBackPrecedence.js" />
                </Scripts>
                </asp:ScriptManager>
                <asp:UpdatePanel  ID="UpdatePanel1" UpdateMode="Conditional" runat="Server" >
                    <ContentTemplate>
                    <strong>UpdatePanel 1</strong><br />
    
                    This postback takes precedence.<br />
                    <asp:Label ID="Label1" runat="server">Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />&nbsp;
                    <asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="UpdatePanel1">
                    <ProgressTemplate>
                    Panel1 updating...
                    </ProgressTemplate>
                    </asp:UpdateProgress>
                    </ContentTemplate>
                </asp:UpdatePanel>
                <asp:UpdatePanel  ID="UpdatePanel2" UpdateMode="Conditional" runat="Server" >
                    <ContentTemplate>
                    <strong>UpdatePanel 2</strong><br />
                    <asp:Label ID="Label2" runat="server">Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button2" runat="server" Text="Button" OnClick="Button2_Click" />
                    <asp:UpdateProgress ID="UpdateProgress2" runat="server" AssociatedUpdatePanelID="UpdatePanel2">
                    <ProgressTemplate>
                    Panel2 updating...
                    </ProgressTemplate>
                    </asp:UpdateProgress>
                    </ContentTemplate>
                </asp:UpdatePanel>
               <div id="AlertDiv" class="MessageStyle">
               <span id="AlertMessage"></span>
               </div>
            </div>
        </form>
    </body>
    </html>
    

Review

This tutorial shows how to enable a specific asynchronous postback to take precedence (that is, to finish processing) before another asynchronous postback starts. The logic for enforcing this behavior is in a JavaScript file that is included as a script reference for the page. The script can be customized so that all current asynchronous postbacks must finish before any new one is started. However, you should carefully consider your design when you specify which postbacks take precedence.

See Also

Concepts

Working with PageRequestManager Events

Reference

Sys.WebForms.PageRequestManager Class

initializeRequest