Accord de priorité à une publication (postback) asynchrone spécifique
Mise à jour : novembre 2007
Par défaut, lorsqu'une page fait plusieurs publications (postback) asynchrones en même temps, la publication faite le plus récemment prend la priorité. Dans certains scénarios, vous pouvez souhaiter donner la priorité à une publication asynchrone spécifique et annuler les autres publications.
Dans ce didacticiel, vous contrôlerez quelle publication prend la priorité. Vous pouvez le faire en créant un gestionnaire d'événements pour l'événement initializeRequest de la classe PageRequestManager. Pour plus d'informations sur la séquence d'événements déclenchée dans la classe PageRequestManager, consultez Utilisation d'événements PageRequestManager.
Composants requis
Pour implémenter les procédures dans votre propre environnement de développement, vous avez besoin des éléments suivants :
Microsoft Visual Studio 2005 ou Microsoft Visual Web Developer Express.
Un site Web ASP.NET AJAX.
Création d'un script donnant la priorité à un élément de publication spécifique
Vous commencerez par créer le code ECMAScript (JavaScript) qui gère la publication asynchrone dans le navigateur.
Pour créer un script donnant la priorité à un élément de publication spécifique
Dans le site Web ASP.NET, ajoutez un fichier JScript et nommez-le PostbackPrecedence.js.
Ajoutez le script suivant au fichier :
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();
Le script effectue les tâches suivantes :
Définit un gestionnaire pour l'événement load de la classe Sys.Application. Le gestionnaire enregistre ensuite un gestionnaire nommé InitializeRequest pour l'événement initializeRequest de la classe PageRequestManager.
Définit le gestionnaire InitializeRequest pour vérifier si une publication asynchrone est en cours d'exécution, et pour déterminer le nom de l'élément qui a provoqué la publication. Si l'élément qui a provoqué la publication est un élément que vous avez spécifié comme élément de publication exclusif (qui doit prendre la priorité), la nouvelle publication est annulée en définissant la propriété d'annulation de la classe InitializeRequestEventArgs.
Définit une fonction ActivateAlertDiv qui bascule la visibilité d'un élément <div> dans la page pour afficher des messages.
Utilisation du script avec un contrôle UpdatePanel
Dans cette procédure, vous utiliserez le script que vous avez créé dans une page. La page contient un bouton dont la publication prend la priorité sur la publication d'un autre bouton dans la page.
Pour créer une page afin de s'assurer que la publication d'une publication prend la priorité
Créez une page Web ASP.NET à fichier unique et basculez en mode Design.
Sous l'onglet Extensions AJAX de la boîte à outils, double-cliquez sur le contrôle ScriptManager pour l'ajouter à la page.
Double-cliquez deux fois sur le contrôle UpdatePanel pour ajouter deux instances du contrôle dans la page.
Dans chaque contrôle UpdatePanel, sous l'onglet Standard de la boîte à outils, ajoutez un contrôle Label et un contrôle Button.
Définissez la valeur Text du contrôle Label dans les deux panneaux sur Panneau initialement rendu.
Double-cliquez sur chaque contrôle Button pour ajouter un gestionnaire pour l'événement Click de chaque bouton.
Ajoutez le code suivant pour les gestionnaires Click afin de créer un délai artificiel et d'afficher l'heure actuelle dans le panneau d'où provient la publication :
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(); }
Remarque : Les gestionnaires de l'événement Click introduisent volontairement un délai pour ce didacticiel. Dans la pratique, vous n'introduiriez pas de délai. Au lieu de cela, le délai aurait pour cause le trafic sur le serveur ou le temps de traitement d'un code serveur plus long que d'habitude, pour une requête de base de données par exemple.
Basculez en mode Source et ajoutez le bloc suivant <style> dans l'élément <head> de la 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>
Les règles de style définissent la taille de l'élément <div> restitué par le contrôle UpdatePanel et de l'élément <div> qui alerte l'utilisateur lorsqu'une publication est annulée.
Ajoutez dans la page la balise suivante à l'intérieur de l'élément <form> :
<div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div>
<div id="AlertDiv" class="MessageStyle"> <span id="AlertMessage"></span> </div>
La balise définit un élément <div> qui affichera un message lorsqu'une publication asynchrone est annulée parce qu'une autre est déjà en cours.
Basculez en mode Design.
Cliquez à l'intérieur du premier contrôle UpdatePanel puis, sous l'onglet Extensions AJAX de la boîte à outils, ajoutez un contrôle UpdateProgress.
Cliquez à l'intérieur du contrôle UpdateProgress et tapez Mise à jour Panel1...
La propriété ProgressTemplate est également définie.
Sélectionnez le contrôle UpdateProgress et, dans la fenêtre Propriétés, affectez UpdatePanel1 à la propriété AssociatedUpdatePanelID.
La page dans le concepteur ressemblera à l'illustration suivante :
Cliquez à l'intérieur du deuxième contrôle UpdatePanel et ajoutez un deuxième contrôle UpdateProgress.
Cliquez à l'intérieur du contrôle UpdateProgress et tapez Mise à jour Panel2...
La propriété ProgressTemplate est également définie.
Sélectionnez le contrôle UpdateProgress et, dans la fenêtre Propriétés, affectez UpdatePanel2 à la propriété AssociatedUpdatePanelID.
La page dans le concepteur ressemblera à l'illustration suivante :
Sélectionnez le contrôle ScriptManager.
Dans la fenêtre Propriétés, sélectionnez la propriété Scripts et cliquez sur le bouton de sélection (…) pour afficher la boîte de dialogue Éditeur de collections ScriptReference.
Cliquez sur Ajouter pour ajouter une référence de script.
Affectez la valeur PostbackPrecedence.js.js à la propriété Path de la référence de script, c'est-à-dire le fichier JavaScript que vous avez créé précédemment.
L'ajout d'une référence de script à l'aide de la collection Scripts du ScriptManager assure le chargement du script après que le chargement de Microsoft AJAX Library.
Cliquez sur OK pour fermer la boîte de dialogue Éditeur de collections ScriptReference.
Enregistrez vos modifications et appuyez sur CTRL+F5 pour afficher la page dans un navigateur.
Cliquez sur le bouton dans le premier panneau puis cliquez sur le bouton dans le deuxième panneau.
Un message s'affiche pour indiquer que la nouvelle publication a été annulée. Le bouton dans le premier panneau doit finir avant qu'une nouvelle publication soit initialisée. Le fichier de script fournit la logique pour mettre en vigueur ce comportement.
Cliquez sur le bouton dans le second panneau puis cliquez sur le bouton dans le premier panneau.
Le bouton dans le deuxième panneau n'a pas la priorité parce qu'il n'a pas été codé pour le faire dans le fichier de script. Par conséquent, aucun message d'avertissement n'est affiché et une nouvelle publication est initialisée par le bouton dans le premier panneau. Il s'agit du comportement par défaut des publications asynchrones : la dernière publication a priorité.
<%@ 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" /> <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" /> <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>
Récapitulatif
Ce didacticiel indique comment permettre à une publication asynchrone spécifique de prendre la priorité (autrement dit, finir le traitement) avant le démarrage d'une autre publication asynchrone. La logique pour mettre en vigueur ce comportement est dans un fichier JavaScript inclus en tant que référence de script pour la page. Le script peut être personnalisé afin que toutes les publications asynchrones actuelles se terminent avant de permettre le démarrage d'une nouvelle publication. Toutefois, vous devez considérer attentivement votre design lorsque vous spécifiez les publications qui ont la priorité.
Voir aussi
Concepts
Utilisation d'événements PageRequestManager