Thursday, March 8, 2012

3 Different Ways to Display Progress in an ASP.NET AJAX Application

In this article, we will study three different techniques that allow you to visually display progress to users while performing partial-page updates using the UpdatePanel. For all the three approaches, I have used a .gif image to show a spinning gear kind of a progress bar while the UpdatePanel is performing some action. The image can be found with the source code for this article over here.
Method 1: Using PageRequestManager to display progress in an ASP.NET AJAX application
The PageRequestManager class handles the partial-page updates of the UpdatePanel. This class defines client events that you can use during an asynchronous request cycle. Let us see how to use some events of this class to display progress to the user while the UpdatePanel updates its contents.
Drag and drop a Button(btnInvoke) and Label(lblText) control inside the UpdatePanel. Also add a <div id="divImage" inside the UpdatePanel. This div will contain a .gif image that depicts progress and is initially set to invisible style="display:none". On the button click, perform a time consuming task. In our case, we have set a delay of 3 seconds by using Thread.Sleep(3000).  
C#
    protected void btnInvoke_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(3000);
        lblText.Text = "Processing completed";
    }
VB.NET
      Protected Sub btnInvoke_Click(ByVal sender As ObjectByVal e As EventArgs)
            System.Threading.Thread.Sleep(3000)
            lblText.Text = "Processing completed"
      End Sub
The markup and code for this sample is as shown below:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UsingPageRequestManager.aspx.cs" Inherits="UsingCSS" %>
 
<!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>Display Progress Using PageRequestManager</title>  
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
         <script type="text/javascript">
             // Get the instance of PageRequestManager.
             var prm = Sys.WebForms.PageRequestManager.getInstance();
             // Add initializeRequest and endRequest
             prm.add_initializeRequest(prm_InitializeRequest);
             prm.add_endRequest(prm_EndRequest);
            
             // Called when async postback begins
             function prm_InitializeRequest(sender, args) {
                 // get the divImage and set it to visible
                 var panelProg = $get('divImage');                
                 panelProg.style.display = '';
                 // reset label text
                 var lbl = $get('<%= this.lblText.ClientID %>');
                 lbl.innerHTML = '';
 
                 // Disable button that caused a postback
                 $get(args._postBackElement.id).disabled = true;
             }
 
             // Called when async postback ends
             function prm_EndRequest(sender, args) {
                 // get the divImage and hide it again
                 var panelProg = $get('divImage');                
                 panelProg.style.display = 'none';
 
                 // Enable button that caused a postback
                 $get(sender._postBackSettings.sourceElement.id).disabled = false;
             }
         </script>
 
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="lblText" runat="server" Text=""></asp:Label>
                <div id="divImage" style="display:none">
                     <asp:Image ID="img1" runat="server" ImageUrl="~/images/progress.gif" />
                     Processing...
                </div>                
                <br />
                <asp:Button ID="btnInvoke" runat="server" Text="Click"
                    onclick="btnInvoke_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>
    </form>
</body>
</html>
 
As shown in the code above, we first get a reference to the PageRequestManager and then wire up the initializeRequest and endRequest events to execute, when an async postback begins and ends respectively.
When the user initiates a postback by clicking on the button kept inside the UpdatePanel, we set a delay of 3 seconds. To display progress to the user, we handle the InitializeRequest at the client side and set the divImage to visible. This shows up the .gif image with the progress as shown below. The button that caused the postback is disabled during this event, so in order to prevent users from hitting the button again.
Progress Bar
Note: Remember that you cannot have simultaneous async postbacks using ASP.NET AJAX.
When the async postback completes (in our case when 3 seconds are over), the endRequest event gets fired. The divImage is set to invisible, there by hiding the gif image and the button is enabled again.
Method 2: Using the UpdateProgress control to display progress in an ASP.NET AJAX application
Another very simple option to display progress during an async postback is to use the UpdateProgress control. You can use this control to display status information to the user, while the UpdatePanel updates its content. In the example below, we use the same .gif to display progress while the UpdatePanel is updating its content. For understanding purposes, we have emulated a time consuming operation by setting a delay of 3 seconds by using Thread.Sleep(3000) on the button click.
 C#
    protected void btnInvoke_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(3000);
        lblText.Text = "Processing completed";
    }
VB.NET
      Protected Sub btnInvoke_Click(ByVal sender As ObjectByVal e As EventArgs)
            System.Threading.Thread.Sleep(3000)
            lblText.Text = "Processing completed"
      End Sub
 
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UsingUpdateProgress.aspx.cs" Inherits="_Default" %>
 
<!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></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdateProgress ID="updProgress"
        AssociatedUpdatePanelID="UpdatePanel1"
        runat="server">
            <ProgressTemplate>           
            <img alt="progress" src="images/progress.gif"/>
               Processing...           
            </ProgressTemplate>
        </asp:UpdateProgress>
       
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="lblText" runat="server" Text=""></asp:Label>
                <br />
                <asp:Button ID="btnInvoke" runat="server" Text="Click"
                    onclick="btnInvoke_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>        
    </div>
    </form>
</body>
</html>
 
In the code shown above, we use the AssociatedUpdatePanelID property of the UpdateProgress control to associate it with an UpdatePanel control. The ProgressTemplate property that can contain HTML, is used to specify the message displayed by an UpdateProgress control. In our case, we are displaying a .gif image progress as shown below
Progress
Method 3: Using UpdatePanelAnimationExtender to display progress in an ASP.NET AJAX application
The UpdatePanelAnimation control can also be used to visually display progress to the users while the UpdatePanel is performing some operation. As defined in the ASP.NET AJAX documentation “The UpdatePanelAnimationExtender is a simple extender that allows you to utilize the powerful animation framework with existing pages in an easy, declarative fashion. It is used to play animations both while an UpdatePanel is updating and after it has finished updating”. You can read more about the UpdatePanelAnimationExtender overhere. For this sample to work, drag and drop a UpdatePanelAnimationExtender from the AJAX Toolkit on to your page.
<Animations> are declared in the UpdatePanelAnimationExtender to create animation effect. Within the <Animations>, you can define the sequence of effects for the UpdatePanelAnimation. You can even use <ScriptAction> definitions to fine-tune and customize the animation.
In this example, we will show how to display an image progress bar using the <ScriptAction> definition of the UpdatePanelAnimationExtender. In the example given below, we have defined two <ScriptAction>; one for while the UpdatePanel is updating(<OnUpdating>) and one for after the UpdatePanel has finished updating(<OnUpdated>).
The two <ScriptAction> definition tags call two JavaScript methods respectively that are responsible for displaying and hiding the image progress bar while the UpdatePanel performs an update on the control. As shown in the previous methods, we have emulated a time consuming operation by setting a delay of 3 seconds by using Thread.Sleep(3000) on the button click. You can replace this code with any time consuming operation, like fetching records from a remote database or performing any similar resource intensive operation. The technique of hiding and showing the image also remains the same as we had discussed in Method 1. The entire source code and mark up is as shown below:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UsingUpdatePanelAnimation.aspx.cs" Inherits="UpdPnlAnimation" %>
 
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
 
<!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></title>
    <script type="text/javascript">
 
        function onUpdating()
        {
            // get the divImage
            var panelProg = $get('divImage');
            // set it to visible
            panelProg.style.display = '';
 
            // hide label if visible     
            var lbl = $get('<%= this.lblText.ClientID %>');
            lbl.innerHTML = '';
        }
 
        function onUpdated()
        {
            // get the divImage
            var panelProg = $get('divImage');
            // set it to invisible
            panelProg.style.display = 'none';
        }
 
 
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <asp:Label ID="lblText" runat="server" Text=""></asp:Label>
                <div id="divImage" style="display:none">
                     <asp:Image ID="img1" runat="server" ImageUrl="~/images/progress.gif" />
                     Processing...
                </div>               
                <br />
                <asp:Button ID="btnInvoke" runat="server" Text="Click"
                    onclick="btnInvoke_Click" />
            </ContentTemplate>
        </asp:UpdatePanel>
        <cc1:UpdatePanelAnimationExtender ID="UpdatePanelAnimationExtender1"
        TargetControlID="UpdatePanel1" runat="server">
        <Animations>
            <OnUpdating>
               <Parallel duration="0">
                    <ScriptAction Script="onUpdating();" />
                    <EnableAction AnimationTarget="btnInvoke" Enabled="false" />                   
                </Parallel>
            </OnUpdating>
            <OnUpdated>
                <Parallel duration="0">
                    <ScriptAction Script="onUpdated();" />
                    <EnableAction AnimationTarget="btnInvoke" Enabled="true" />
                </Parallel>
            </OnUpdated>
        </Animations>
        </cc1:UpdatePanelAnimationExtender>       
    </div>
    </form>
</body>
</html>
 
C#
    protected void btnInvoke_Click(object sender, EventArgs e)
    {
        System.Threading.Thread.Sleep(3000);
        lblText.Text = "Processing completed";
    }
VB.NET
      Protected Sub btnInvoke_Click(ByVal sender As ObjectByVal e As EventArgs)
            System.Threading.Thread.Sleep(3000)
            lblText.Text = "Processing completed"
      End Sub
 
The progress will look similar to the ones shown in the other methods
progress
Well those were the three different methods of displaying progress to the user while the UpdatePanel updates its contents. The entire source code of this article can be downloaded from here. I hope this article was useful and I thank you for viewing it. 

No comments:

Post a Comment