Guillermo G. Blog

Software Architect
ASP.NET MCP
"The best way to predict the future is to invent it"

December 2007 - Posts

AJAX: Como crear una ventana modal "Procesando..." utilizando los controles UpdateProgress y ModalPopup

ajax

Hace algunos días me vi en la necesidad de implementar en una aplicación Web que estaba desarrollando, funcionalidad basada en la tecnología AJAX. Cuando se hace una petición al servidor haciendo clic sobre un control de la página, al estar trabajando con AJAX la sensación de PostBack de la pagina desaparece y algunas veces es imperceptible detectar que la página se encuentra procesando el requerimiento con base en el evento generado.

Existe un control de ASP.net AJAX que nos permite presentarle al usuario un indicador de progreso de la petición denominado UpdateProgress, a pesar de ser muy útil para "controlar" la paciencia de los usuarios, se puede continuar interactuado con los demás controles de la aplicación lo que puede ocasionar comportamientos extraños en la aplicación. 

// Ejemplo de implementación de un UpdateProgress 
<asp:UpdateProgress ID="UpdateProg1" DisplayAfter="0" runat="server"> 
  <ProgressTemplate> 
    <div style="position: relative; top: 30%; text-align: center;">  
     <img src="loading.gif" style="vertical-align:middle" alt="Procesando"/> 
      Procesando ... 
    </div> 
  </ProgressTemplate> 
</asp:UpdateProgress> 

Desafortunadamente no existe un control de ASP.net AJAX que "bloquee" el contexto gráfico de la aplicación mientras se hace una petición de PostBack, pero afortunadamente se puede hacer una combinación exitosa utilizando otro control del AJAX Control Toolkit llamado ModalPopup Extender, el cual permite presentar un contenido con apariencia modal evitando que el usuario pueda interactuar con el contenido de la pagina desde la cual fue llamado.

//Ejemplo de implementación de un Modal Popup Extender 
<ajaxToolkit:ModalPopupExtender ID="ModalProgress" 
runat="server" TargetControlID="panelUpdateProgress"  
BackgroundCssClass="modalBackground" PopupControlID="panelUpdateProgress" /> 

Ahora viene la parte que interesante, tomar la ventaja de cada uno de los controles para crear una funcionalidad que presente un indicador de progreso al cliente pero que al mismo tiempo que la presenta de manera modal, con el fin de evitar que el usuario pueda interactuar con la pagina que originó el evento AJAX. El siguiente ejemplo de código presenta como realizar esta implementación:

// Como estamos utilizando ASP.net AJAX debemos se deben incluir las 
// siguientes directivas de registro en la pagina
<%@ Register Assembly="System.Web.Extensions, Version=1.0.61025.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI"
TagPrefix="asp" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit"
TagPrefix="ajaxToolkit" %>
// Incluir la etiqueta ScriptManager encargada de brindarle los scripts y 
// librerías necesarias para el funcionamiento de AJAX 
<asp:ScriptManager ID="ScriptManager1" runat="server" /> 
 
// Incorporamos el UpdateProgress dentro de un control Panel 
// y luego el ModalPopupExtender 
<asp:Panel ID="panelUpdateProgress" runat="server" 
CssClass="updateProgress"> 
    <asp:UpdateProgress ID="UpdateProg1" DisplayAfter="0" runat="server"> 
      <ProgressTemplate> 
        <div style="position: relative; top: 30%; text-align: center;"> 
          <img src="loading.gif" style="vertical-align: middle" 
          alt="Procesando" /> 
          Procesando ... 
        </div> 
      </ProgressTemplate> 
    </asp:UpdateProgress> 
  </asp:Panel> 
<ajaxToolkit:ModalPopupExtender ID="ModalProgress" runat="server" 
TargetControlID="panelUpdateProgress" BackgroundCssClass="modalBackground" 
PopupControlID="panelUpdateProgress" />

Se hace necesario adicionar utilizando lenguaje JavaScript dos funciones, que se deben ejecutar en las peticiones inicial y final de AJAX

//Código JavaScript incluido en un archivo denominado jsUpdateProgress.js 
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(beginReq); 
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endReq);    
function beginReq(sender, args){ 
    // muestra el popup 
    $find(ModalProgress).show();        
} 
 
function endReq(sender, args) { 
    //  esconde el popup 
    $find(ModalProgress).hide(); 
} 

Si se observa en las funciones de JavaScript se hace Referencia a la variable ModalProgress la cual debe ser creada desde el code-behind para que luego pueda ser utilizada por javascript, en el siguiente trozo de código se muestra como se crea la variable javascript desde el code-behind y se hace la referencia al archivo javascript con las funciones.

<script type="text/javascript" language="javascript"> 
      var ModalProgress ='<%= ModalProgress.ClientID %>';         
</script> 
 
<script type="text/javascript" src="jsUpdateProgress.js"></script>

Por ultimo le agregamos un poco de CSS con el fin de tener la ventana modal con un contorno gris y formato general para la imagen, y el texto contenido

.modalBackground 
{ 
    background-color: Gray; 
    filter: alpha(opacity=50); 
    opacity: 0.50; 
} 
 
.updateProgress 
{ 
    border-width: 1px; 
    border-style: solid; 
    background-color: #FFFFFF; 
    position: absolute; 
    width: 180px; 
    height: 65px; 
} 
 

Aquí terminamos con la elaboración de una ventana modal que muestra el mensaje de "Procesando..." mientras se hace una petición utilizando ASP.net AJAX.

El codigo fuente del ejemplo para que lo descargues y puedas ponerlo en práctica en tus aplicaciones.

Actualizado (Septiembre 02 de 2009): Ya hay una versión para Visual Basic incluida en el código de ejemplo.

Tip: Cast using the as Statement and Convert class vs Normal Casting

blackboard

Convert data from a DataType to another is a daily task of a developer; the applications require show formatted data (i.e Dates, currency, etc.) or make operations with this data. Here I'll show you an easy tip to avoid (or minimize) the use of try ... catch sentences when you need to do a casting or data conversion.

Normally to convert a numerical DataType to a string DataType (for example), we use the ToString() native method of the object. It's so easy and is the "natural" way to do it, but, what happens if the ToString() method can't do the conversion? It throws an Exception !!!

string
mySessionValue = Session["myKey"].ToString();
// if Session["myKey"] doesn't exists it throws an exception trying to convert null
// to string DataType.

Ok, a simple solution is to do the conversion using the as statement, this way it avoids to throw an exception if an error occurred when it's trying to do the conversion and a null value is assigned to mySessionValue variable.

string mySessionValue = Session["myKey"] as string;
// if Session["myKey"] doesn't exists it don't throw an exception trying to convert
//
null to string DataType.

Another valid solution using the ToString() method of the Convert class ...

string mySessionValue = Convert.ToString(Session["myKey"]);
// if Session["myKey"] doesn't exists it don't throw an exception trying to convert
//
null to string DataType.

And ... It's better to ask for a null value ...

if (string.IsNullOrEmpty(mySessionValue))
{
   // some code ...
}

Than to wrap the code with a try catch sentence.

try
{
   
string mySessionValue = Session["myKey"].ToString();
}
catch (InvalidCastException ex)
{
   
// Do something
}

I hope that this little and easy tip helps you to write better code.

Posted: Dec 05 2007, 11:46 AM by gugonzar | with 2 comment(s)
Filed under: , , ,
More Posts