Friday, March 23, 2012

UpdatePanel Progress Emulation or How to show "Progress" information when we need to generate full postback (by PostBackTrigger) in the UpdatePanel

Initial data
We have an UpdatePanel. In this UpdatePanel we have two buttons. By clicking each button application does something. Also we have an UpdateProgress for the UpdatePanel. BUT one button generate full PostBack.
<%@ Page Title="Home Page" Language="vb" MasterPageFile="~/Site.Master" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="UpdatePanelProgressEmulation._Default" %>
<%-- It is registration for a web user control that include presentation layout of our progress information. --%>
<%@ Register src="Preloader.ascx"  tagname="Preloader" tagprefix="uc1" %>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <asp:ScriptManager ID="ScriptManagerMain" unat="server"></asp:ScriptManager>

<asp:UpdatePanel ID="UpdatePanelMain" runat="server">
            <%--Register our full postback action for button--%>
            <asp:PostBackTrigger ControlID="btnWithPostBackTrigger" />

            <%--UpdateProgress - uses ucPreloader. As in the above code.--%>
            <asp:UpdateProgress ID="UpdateProgressMain" EnableViewState="false"    AssociatedUpdatePanelID="UpdatePanelMain" runat="server">
                    <uc1:Preloader    ID="ucPreloader" ClientIDMode="Static"   runat="server" />
            <asp:Button runat="server" ID="btnWithoutPostBackTrigger" Text="Button without PostBackTrigger " BackColor="#006600" BorderStyle="Solid" BorderColor="#003300" ForeColor="White"/>
            <asp:Button runat="server" ID="btnWithPostBackTrigger" Text="Button with PostBackTrigger" BackColor="#CC0000" BorderStyle="Solid"  BorderColor="Maroon" ForeColor="White" />

The code of the Preloader.ascx used to show progress info:
<%--A simple Div that shows us "Loading" message.--%>
<div style="top:150px; width:100%; left:0px; display:block;position:fixed; z-index:2000;" align="center" >
    <table style=" width:600px; height:200px; z-index:2002; background-color:#f9f9f9; border-style:solid; border-color:Grey; ">
            <td valign="middle" align="center">
                <h1 style=" color:Navy">Loading: 5000 milliseconds...</h1>

So, if we click this button with a full PostBack action - we don't see any Progress. If we click the button without the full PostBack action - we see this progress information. But it is not friendly for user, because in one time he sees progress info, in another time he doesn't see it. It would be much better if user has ability to see progress information for each situation.

There are many ways to solve this situation. But I select simplest way, as for me. And it is emulation of the showing of the progress info for Update Panel.

The idea – to run JavaScript code by clicking our FullPostBack button. In any cases this code will be runned and will be executed before a moment when request of our page will be send to server and will be back.  We click button – and by JavaScript shows ProgressInfo. And until  request don’t return from the server – we see our ProgressInfo. Also we don’t need to think how to hide our ProgressInfo, because when our request returns from server – we will have reRander of our page and it will hide our ProgressInfo automatically.

Code in aspx file…
<div id="divPreloader" style="visibility:hidden;">
      <uc1:Preloader    ID="ucPre"  runat="server" />

Add this code above somewhere outside of the UpdatePanel.  The purpose of this code – to show  our progressinfo for our  FullPostBack. I placed it  above UpdatePanel. We will find this div by JavaScript and will show it. Yes, if you want you can find Preloader that is used by UpdatePanel inside. But I  prefer to have separate div for this.

And add OnClientClick="ShowProgress('divPreloader')" to our btnWithPostBackTrigger. ShowProgress – it is our JavaScript function that will show what we need.

Code in .vb file
Private Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Dim PageLoadedHandlerScript As String = " function getObject (sId) { if(!sId) return null; else if (document.all && document.all[sId])  return document.all[sId];  else if (document.getElementById)  return document.getElementById(sId); else return null;}" _
         & " function ShowProgress(sId) { var dP = getObject(sId); if (dP != null) { = 'visible'; } }"
        Page.ClientScript.RegisterClientScriptBlock(Me.GetType, "getObjectScript", PageLoadedHandlerScript, True)
        btnWithPostBackTrigger.OnClientClick = "ShowProgress('divPreloader')"
End Sub

In this code we register our JavaScript on the page. There are two functions – the first function finds DOM element by id or name. The second function is our ShowProgress function that is used by btnWithPostBackTrigger. You can use your own JavaScript and jQuery if you need. 

That’s all. Hope it will help you.
to sources >>