Compartir a través de


Dar prioridad a una devolución de datos asincrónica específica

Actualización: noviembre 2007

De forma predeterminada, cuando una página realiza al mismo tiempo varias devoluciones de datos asincrónicas, tiene prioridad la última devolución de datos realizada. En algunos casos, podría desear dar la prioridad a una devolución de datos asincrónica concreta y cancelar las otras devoluciones de datos.

En este tutorial, controlará qué devolución de datos tiene prioridad. Para ello, crea un controlador de eventos para el evento initializeRequest de la clase PageRequestManager. Para obtener información sobre la secuencia de eventos que se provocan en la clase PageRequestManager, vea Trabajar con eventos de PageRequestManager.

Requisitos previos

Para implementar los procedimientos en su propio entorno de desarrollo, necesitará:

  • Microsoft Visual Studio 2005 o Microsoft Visual Web Developer Express.

  • Un sitio web ASP.NET habilitado para AJAX.

Crear script que da prioridad a un elemento de devolución de datos concreto

Para empezar, creará código ECMAScript (JavaScript) que administra la devolución de datos asincrónica en el explorador.

Para script que da prioridad a un elemento de devolución de datos concreto

  1. En el sitio web de ASP.NET, agregue un archivo JScript y denomínelo PostbackPrecedence.js.

  2. Agregue el siguiente script al archivo:

    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();
    

    El script realiza las siguientes tareas:

    • Define un controlador para el evento load de la clase Sys.Application. El controlador se registra a su vez un controlador denominado InitializeRequest para el evento initializeRequest de la clase PageRequestManager.

    • Define el controlador InitializeRequest para comprobar si se está ejecutando una devolución de datos asincrónica actualmente, y para determinar el nombre del elemento que produjo la devolución de datos. Si el elemento que produjo la devolución de datos es uno de los que ha especificado como elemento de devolución de datos exclusivo (uno que debería tener prioridad), la nueva devolución de datos se cancela mediante el establecimiento de la propiedad cancel de la clase InitializeRequestEventArgs.

    • Define una función ActivateAlertDiv que alterna la visibilidad de un elemento <div> en la página para mostrar mensajes.

Usar el script con un control UpdatePanel

En este procedimiento usará el script que creó en una página. La página contiene un botón cuya devolución de datos tiene prioridad sobre la devolución de datos de otro botón de la página.

Para crear una página y garantizar que tiene prioridad la devolución de datos de un botón determinado

  1. Cree una nueva página web ASP.NET de un solo archivo y cambie a la vista Diseño.

  2. En la ficha Extensiones AJAX del cuadro de herramientas, haga doble clic en el control ScriptManager para agregarlo a la página.

  3. Haga doble clic en el control UpdatePanel dos veces para agregar dos instancias del control a la página.

  4. En cada control UpdatePanel, en la ficha Estándar del cuadro de herramientas, agregue un control Label y un control Button.

  5. Establezca el valor Text del control Label de ambos paneles en Panel representado inicialmente.

  6. Haga doble clic en cada control Button para agregar un controlador para el evento Click de cada botón.

  7. Agregue el código siguiente en los controladores Click, que crea artificialmente un retraso y, a continuación, muestra la hora actual en el panel donde se origina la devolución de datos:

    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();        
    }
    
    Nota:

    Los controladores del evento Click aplican de forma intencionada un retraso en este tutorial. En la práctica, no debería incluir un retraso. Si se produce un retraso en este caso, será como resultado del tráfico del servidor o debido a que el código de servidor tarda mucho en tiempo en procesarse, como ocurre con las consultas de base de datos de ejecución prolongada.

  8. Cambie a la vista Código fuente y agregue el siguiente bloque <style> en el elemento <head> de la página.

        <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>
    

    Las reglas de estilo definen el tamaño del elemento <div> que se representa mediante el control UpdatePanel y del elemento <div> que avisa al usuario cuando se cancela una devolución de datos.

  9. Agregue el marcado siguiente dentro del elemento <form> de la página:

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

    El marcado define un elemento <div> que mostrará un mensaje cuando se cancele una devolución de datos asincrónica debido a que otra ya está en curso.

  10. Cambie a la vista Diseño.

  11. Haga clic dentro del primer control UpdatePanel y, a continuación, en la ficha Extensiones AJAX del cuadro de herramientas, agregue un control UpdateProgress.

  12. Haga clic dentro del control UpdateProgress y escriba Panel1 actualizándose ….

    De esta forma establece la propiedad ProgressTemplate.

  13. Seleccione el control UpdateProgress y, en la ventana Propiedades, establezca la propiedad AssociatedUpdatePanelID en UpdatePanel1.

    La página del diseñador se parecerá a la figura siguiente:

  14. Haga clic dentro del segundo control UpdatePanel y agregue un segundo control UpdateProgress.

  15. Haga clic dentro del control UpdateProgress y escriba Panel2 actualizándose ….

    De esta forma establece la propiedad ProgressTemplate.

  16. Seleccione el control UpdateProgress y, en la ventana Propiedades, establezca la propiedad AssociatedUpdatePanelID en UpdatePanel2.

    La página del diseñador se parecerá a la figura siguiente:

  17. Seleccione el control ScriptManager.

  18. En la ventana Propiedades, seleccione la propiedad Scripts y haga clic en el botón de puntos suspensivos (…) para mostrar el cuadro de diálogo Editor de la colección ScriptReference.

  19. Haga clic en Agregar para agregar una referencia de script.

  20. Establezca la propiedad Path de la referencia de script en PostbackPrecedence.js, el archivo JavaScript que creó previamente.

    Al agregar una referencia de script con la colección Scripts de ScriptManager se asegura de que se carga el script después de que se cargue Microsoft AJAX Library.

  21. Haga clic en Aceptar para cerrar el cuadro de diálogo Editor de la colección ScriptReference.

  22. Guarde los cambios y presione CTRL+F5 para ver la página en un explorador.

  23. Haga clic en el botón del primer panel y, a continuación, haga clic en el botón del segundo panel.

    Se muestra un mensaje que indica que la nueva devolución de datos se ha cancelado. El botón del primer panel debe finalizar antes de que se inicie una nueva devolución de datos. El archivo de script proporciona la lógica para exigir este comportamiento.

  24. Haga clic en el botón del segundo panel y, a continuación, haga clic en el botón del primer panel.

    El botón del segundo panel no tiene prioridad porque no se ha codificado de esta forma en el archivo de script. Por tanto, no se muestra ningún mensaje de advertencia y el botón del primer panel inicia una nueva devolución de datos. Éste es el comportamiento predeterminado de las devoluciones de datos asincrónicas; la devolución de datos más reciente tiene prioridad.

    <%@ Page Language="VB" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script >
        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" >
        <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" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                <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" >Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button1"  Text="Button" OnClick="Button1_Click" />&nbsp;
                    <asp:UpdateProgress ID="UpdateProgress1"  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" >Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button2"  Text="Button" OnClick="Button2_Click" />
                    <asp:UpdateProgress ID="UpdateProgress2"  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 >
        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" >
        <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" >
            <div>
                <asp:ScriptManager ID="ScriptManager1" >
                <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" >Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button1"  Text="Button" OnClick="Button1_Click" />&nbsp;
                    <asp:UpdateProgress ID="UpdateProgress1"  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" >Panel initially rendered.</asp:Label><br />
                    <asp:Button ID="Button2"  Text="Button" OnClick="Button2_Click" />
                    <asp:UpdateProgress ID="UpdateProgress2"  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>
    

Revisión

Este tutorial muestra cómo se consigue que una devolución de datos asincrónica concreta tenga prioridad (es decir, finalice el procesamiento) antes de que se inicie otra devolución de datos asincrónica. La lógica para exigir este comportamiento se encuentra en un archivo JavaScript incluido como una referencia de script en la página. El script se puede personalizar de forma que deban finalizar todas las devoluciones de datos asincrónicas actuales antes de que se inicie una nueva. Sin embargo, debería considerar el diseño con detenimiento a la hora de especificar qué devoluciones de datos tienen prioridad.

Vea también

Conceptos

Trabajar con eventos de PageRequestManager

Referencia

Sys.WebForms.PageRequestManager (Clase)

initializeRequest