Tutoriel : Créer un overlayer d'attente lors d'un Postback pour ASP.NET/AJAX en C#

Nico-pyright(c)

Cet article présente comment créer un contrôle qui affiche un overlayer d'attente pendant un postback partiel AJAX pour ASP.NET en C#. Vous y verrez comment encapsuler le contrôle UpdateProgress et vous aurez un aperçu du cycle de vie client d'un postback AJAX.

N'hésitez pas à commenter cet article ! Commentez ♪

- Titre : Tutoriel : Créer un overlayer d'attente lors d'un Postback pour ASP.NET/AJAX en C#

- Auteur : Nico-pyright(c)

- Parution : 24 juillet 2008

- Mise à jour : 24 juillet 2008

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2007 Nico-pyright(c). Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.

Sommaire

- 1.Introduction

- 2.Présentation du contrôle

- 3.Le contrôle WaitPostback

- 3.1.Les propriétés

- 3.2.Ajouter les ressources à l'assembly

- 3.3.Encapsuler l'update progress

- 4.Utiliser le contrôle

- 4.1.Référencer le projet et référencer le contrôle

- 4.2.Exemple

- 5.Restreindre l'overlayer à l'UpdatePanel

- 5.1.Ajout d'une propriété AssociatedDivID

- 5.2.Utiliser les événements client AJAX

- 5.2.1.Rappel sur le cycle de vie des événements client AJAX

- 5.2.2.L'implémentation

- 5.3.Exemple

- 6.Exemple de deux contrôles en même temps

- 6.1.Exemple

- 6.2.Téléchargement

- 7.Conclusion

- Remerciements

- Contact

1.Introduction

Vous êtes un développeur ASP.NET utilisant le C# et les extensions AJAX (notamment l'UpdatePanel) et vous souhaitez apprendre à créer un contrôle qui permette d'indiquer de patienter pendant un postback tout en désactivant la page ?
Alors ce tutoriel est pour vous.

À travers cet article, nous allons créer un contrôle qui encapsule le contrôle UpdateProgress pour permettre à l'utilisateur de patienter pendant un postback partiel. Nous verrons également comment utiliser les événements client du cycle de vie d'un postback pour piloter des éléments HTML.
Tout au long de ce cours, je vais utiliser Visual C# 2008.

2.Présentation du contrôle

Grâce aux extensions web d'ASP.NET et notamment grâce à l'UpdatePanel, il devient très facile de faire des rafraichissements de page partiels (ce qu'on appelle couramment un postback partiel).
En général, on veut pouvoir informer l'utilisateur qu'il se passe quelque chose, surtout si le traitement est long. Assez fréquemment, il faut également empêcher l'utilisateur de faire autre chose pendant ce postback qui risque de perturber le fonctionnement de l'application, comme arrêter le postback ou en effectuer un deuxième, etc.

Les extensions web d'ASP.NET disposent d'un contrôle très pratique qui permet d'informer l'utilisateur pendant un postback : le contrôle UpdateProgress.

Ce tutoriel va consister en la création d'un contrôle serveur qui va encapsuler ce contrôle UpdateProgress et créer un overlayer qui permettra d'afficher un message d'attente et empêchera l'utilisateur de faire d'autres actions pendant un postback.
Nous verrons également comment intégrer des ressources dans notre contrôle serveur.

Ce contrôle fonctionnera ainsi.
Par exemple lors du postback que va provoquer ce bouton :

On affichera un message personnalisé par-dessus un overlayer qui couvrira toute la page.

3.Le contrôle WaitPostback

Pour créer ce contrôle, nous allons utiliser un projet de type WEB/ASP.NET Server Control. Ce contrôle hérite bien évidemment de WebControl :

public class WaitPostback : WebControl
{
...
}

3.1.Les propriétés

Le contrôle UpdateProgress dispose d'une propriété qui permet de l'associer à un UpdatePanel. Il s'agit de la propriété AssociatedUpdatePanelID.
Nous allons donc exposer également cette propriété afin de pouvoir raccrocher notre UpdateProgress encapsulé à un UpdatePanel.
Nous voulons également permettre à l'utilisateur de personnaliser le message d'attente, ainsi nous allons exposer une propriété Text. Celle-ci aura également une valeur par défaut.

[DefaultValue("")]
public string AssociatedUpdatePanelID
{
get { return (string)ViewState["AssociatedUpdatePanelID"] ?? string.Empty; }
set { ViewState["AssociatedUpdatePanelID"] = value; }
}
[DefaultValue("Veuillez patienter ..."), Bindable(true)]
public string Text
{
get { return (string)ViewState["Text"] ?? "Veuillez patienter ..."; }
set { ViewState["Text"] = value; }
}

On utilise le ViewState pour stocker ces deux valeurs.

3.2.Ajouter les ressources à l'assembly

Nous allons appliquer à notre rendu html de l'OverLayer des propriétés CSS. Ces propriétés CSS seront disponibles dans un fichier .CSS.
De même, nous allons également utiliser une image d'attente de chargement que nous allons récupérer sur le site http://www.ajaxload.info/.
Le fichier CSS sera le suivant :

.WaitProgressOverLayerClass
{
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
background-color: gray;
filter: alpha(opacity=70);
opacity: 0.7;
-moz-opacity: 0.7;
z-index: 10;
padding-top: 25%;
padding-left: 30%;
}
.WaitProgressMessageClass
{
background-color: #eee;
padding: 10px;
border: 1px solid black;
z-index: 9;
filter: alpha(opacity=100);
-moz-opacity: 1.00;
text-align: center;
width: 500px;
}

L'image d'attente est la suivante, il s'agit d'un gif animé :

Pour que ces deux ressources soient directement incorporées dans l'assembly de notre contrôle, il faut respecter les étapes suivantes :

Tout d'abord, ajouter les fichiers à notre solution. Faire un clic droit sur chacun de ces fichiers, afficher la fenêtre des propriétés et changer l'action de génération à ressource incorporée (en anglais : Build Action => « Embedded Resource »).
Maintenant, à la compilation, les fichiers seront incorporés à l'assembly.

Pour accéder désormais à notre ressource, on utilisera le HTTP Handler « WebResource.axd ».

La première chose à faire est de signaler à l'assembly ces ressources afin qu'on ait le droit d'y accéder. Pour ce faire, on va modifier le fichier AssemblyInfo.cs et rajouter les lignes suivantes :

[assembly: WebResource("WaitPostback.WaitPostBack.css", "text/css")]
[assembly: WebResource("WaitPostback.wait.gif", "img/gif")]

La chaine à passer est de type Namespace.NomFichier.Extension.
Attention : bien vérifier que le namespace utilisé correspond à celui qu'il y a dans les propriétés du projet, onglet Application, Default namespace.
On lui indiquera également les types MIME des fichiers.

Ainsi, il sera possible d'obtenir l'url d'un fichier en utilisant la méthode GetWebResourceUrl de l'objet Page.ClientScript.

Voici comment l'utiliser pour inclure le fichier CSS.

protected override void OnPreRender(EventArgs e)
{
string csslink = string.Format("<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />",
Page.ClientScript.GetWebResourceUrl(GetType(), "WaitPostback.WaitPostBack.css"));
LiteralControl include = new LiteralControl(csslink);
Page.Header.Controls.Add(include);
base.OnPreRender(e);
}

3.3.Encapsuler l'update progress

Pour encapsuler l'UpdateProgress, nous allons simplement le rajouter à l'arbre des contrôles de notre contrôle personnalisé. Pour ce faire, le OnInit est l'endroit idéal.
Notez qu'on instancie et qu'on affecte un template de notre cru à la propriété ProgressTemplate de l'UpdateProgress. Nous allons voir cette classe RenderTemplate un peu plus loin. Notez simplement qu'on lui passe en paramètre le texte personnalisé à utiliser pour le message d'attente, ainsi que l'url de l'image (récupérée grâce à GetWebResourceUrl).

protected override void OnInit(EventArgs e)
{
UpdateProgress progress = new UpdateProgress();
progress.ProgressTemplate = new RenderTemplate(Text,  Page.ClientScript.GetWebResourceUrl(GetType(), "WaitPostback.wait.gif"));
progress.AssociatedUpdatePanelID = AssociatedUpdatePanelID;
Controls.Add(progress);
base.OnInit(e);
}

Dans la mesure où on utilise l'UpdateProgress, il faudra bien sûr ajouter la référence à System.Web.Extensions dans notre projet.

La classe RenderTemplate implémente l'interface ITemplate. C'est dans la méthode InstantiateIn que nous allons créer le rendu de notre template. (plus d'infos sur les contrôles templates dans cette Introduction aux contrôles templates pour Asp.Net 2.0 en C#).

Ici, nous créons un premier Panel qui sera le div de base où s'affichera l'overlayer et qui empêchera l'utilisateur d'accéder à sa page. Nous lui affectons la classe CSS WaitProgressOverLayerClass.
Il contiendra un autre Panel qui affichera la boite de dialogue contenant notre texte personnalisé. On lui affecte la classe CSS WaitProgressMessageClass.
Il contiendra également l'image d'attente à afficher.

private sealed class RenderTemplate : ITemplate
{
private string _text;
private string _url;
public RenderTemplate(string text, string url)
{
_text = text;
_url = url;
}

void ITemplate.InstantiateIn(Control container)
{
Panel outerDiv = new Panel();
outerDiv.ID = "WaitProgressOverLayer";
outerDiv.CssClass = "WaitProgressOverLayerClass";
Panel innerDiv = new Panel();
innerDiv.ID = "WaitProgressMessage";
innerDiv.CssClass = "WaitProgressMessageClass";
Label text = new Label();
text.Text = _text;
Image img = new Image();
img.ImageUrl = _url;
innerDiv.Controls.Add(text);
innerDiv.Controls.Add(img);
outerDiv.Controls.Add(innerDiv);
container.Controls.Add(outerDiv);
}
}

4.Utiliser le contrôle

Nous allons désormais utiliser ce contrôle. Pour cela, nous allons créer un projet web de test (projet ASP.NET Web Application).

4.1.Référencer le projet et référencer le contrôle

Tout d'abord, nous allons rajouter une référence à notre contrôle. Si comme moi vous avez ajouté le projet à la même solution, une référence projet suffit. Sinon, il faudra référencer l'assembly du contrôle.
Pour utiliser notre contrôle, il faudra le déclarer en haut de notre page ASPX, comme indiqué dans la FAQ ASP.NET.

<%@ Register TagPrefix="Exemple" Namespace="WaitPostback" Assembly="WaitPostback" %>

4.2.Exemple

Créons maintenant une page qui va utiliser notre contrôle. Elle devra contenir bien sur un contrôle serveur ScriptManager et devra apparaitre en toute logique avant l'UpdatePanel et avant notre contrôle. Nous mettons également un UpdatePanel qui va contenir un bouton. Ce bouton postera la page et simulera un traitement long en faisant une pause de 5 secondes.
Nous avons également mis deux Label qui contiendront l'heure à laquelle ils ont été rafraichis. Un sera disposé dans l'UpdatePanel et l'autre en dehors pour bien voir l'effet du postback partiel.
Enfin, nous rajoutons notre contrôle WaitPostback. Notez que sa propriété AssociatedUpdatePanelID correspond à l'ID de l'UpdatePanel.

<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:Label runat="server" ID="LabelRefer" />
<asp:UpdatePanel runat="server" ID="TotalUpdatePanel">
<ContentTemplate>
<asp:Button runat="server" Text="Recharger en grisant toute la page" OnClick="DoPostBack" />
<asp:Label runat="server" ID="Label1" />
</ContentTemplate>
</asp:UpdatePanel>
<Exemple:WaitPostback ID="WaitPostbackAll" runat="server" AssociatedUpdatePanelID="TotalUpdatePanel"
Text="Veuillez patienter pendant que je mets à jour les informations ..." />

private void MajLabel()
{
Label1.Text = DateTime.Now.ToLongTimeString();
LabelRefer.Text = DateTime.Now.ToLongTimeString();
}

protected override void OnLoad(EventArgs e)
{
MajLabel();
base.OnLoad(e);
}

protected void DoPostBack(object sender, EventArgs e)
{
Thread.Sleep(5000);
MajLabel();
}

5.Restreindre l'overlayer à l'UpdatePanel

Le paragraphe précédent nous a montré comment créer un overlayer qui couvre toute la page. Mais il peut arriver qu'on veuille simplement masquer la zone qui est rafraichie, c'est-à-dire la zone de l'UpdatePanel.
Cela pourrait donner ça :

Pour accomplir ceci, nous n'allons cette fois-ci ne plus nous servir de l'UpdateProgress, mais nous allons tout faire à la main, en nous servant des événements clients AJAX.

5.1.Ajout d'une propriété AssociatedDivID

Nous avons donc besoin d'une propriété pour dire sur quel div devra s'appliquer l'OverLayer. À cet effet, rajoutons la propriété AssociatedDivID.
Nous pourrons y affecter l'ID de l'UpdatePanel.
Vous me direz : dans ce cas, pourquoi ne pas utiliser la propriété AssociatedUpdatePanelID que nous avons déjà créée ?
Je vous répondrai : pourquoi pas, mais imaginons que nous voulions appliquer l'OverLayer ailleurs que sur l'UpdatePanel … C'est pour cela que nous allons rajouter cette propriété.

[DefaultValue("")]
public string AssociatedDivID
{
get { return (string)ViewState["AssociatedDivID"] ?? string.Empty; }
set { ViewState["AssociatedDivID"] = value; }
}

Comme vous pouvez le voir, le code n'a rien d'extraordinaire.
Nous n'avons plus besoin d'UpdateProgress, donc, dans le OnInit, on n'ajoute l'UpdateProgress que si la propriété AssociatedDivID est vide :

protected override void OnInit(EventArgs e)
{
if (string.IsNullOrEmpty(AssociatedDivID))
{
UpdateProgress progress = new UpdateProgress();
progress.ProgressTemplate = new RenderTemplate(Text,
Page.ClientScript.GetWebResourceUrl(GetType(), "WaitPostback.wait.gif"));
progress.AssociatedUpdatePanelID = AssociatedUpdatePanelID;
Controls.Add(progress);
}
base.OnInit(e);
}

5.2.Utiliser les événements client AJAX

5.2.1.Rappel sur le cycle de vie des événements client AJAX

Lorsque l'on fait un postback partiel en utilisant l'UpdatePanel, la page rentre dans un cycle de vie côté client. On peut s'abonner à un certain nombre d'événements en javascript grâce à l'objet PageRequestManager.
À savoir (dans l'ordre de leur apparition) :

Événement

Description

initializeRequest

Déclenché durant l'initialisation de la publication (postback) asynchrone. Cet événement permet de savoir quel est l'élément HTML qui a déclenché le postback et permet d'annuler le postback éventuellement.

beginRequest

Déclenché avant le début du traitement d'une publication (postback) asynchrone et l'envoi de la requête de publication au serveur.

pageLoading

Déclenché après la réception d'une réponse du serveur à une publication (postback) asynchrone, mais avant la mise à jour du contenu sur la page.

pageLoaded

Déclenché après l'actualisation de tout le contenu de la page suite à une publication (postback) synchrone ou asynchrone.

endRequest

Déclenché après qu'une publication (postback) asynchrone est terminée et que le contrôle a été retourné au navigateur.

5.2.2.L'implémentation

Pour accéder à l'objet PageRequestManager et s'abonner à ses événements, on devra utiliser le code javascript suivant :

var prm = Sys.WebForms.PageRequestManager.getInstance();

prm.add_initializeRequest(PageRequestManager_initializeRequest);
prm.add_endRequest(PageRequestManager_endRequest);

function PageRequestManager_initializeRequest(sender, args)
{
}
function PageRequestManager_endRequest(sender, args)
{
}

Dans notre cas, nous avons besoin de nous abonner uniquement aux événements initializeRequest et endRequest. Notez que ce code-ci doit obligatoirement se trouver après le contrôle serveur ScriptManager. En effet, c'est le contrôle server ScriptManager qui génère le javascript qui instancie les objets nécessaires à l'initialisation du cycle de vie du postback AJAX. Tout code javascript utilisant ces objets doit être exécuté après, sans quoi, on se retrouvera avec des objets undefined.
Nous allons donc gérer dans ces méthodes le javascript qui va nous permettre de créer un div et d'appliquer le style voulu. Le code javascript ressemblera à celui ci-dessous :

<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
var panel;

prm.add_initializeRequest(PageRequestManager_initializeRequest);
prm.add_endRequest(PageRequestManager_endRequest);

function PageRequestManager_initializeRequest(sender, args)
{
panel = null;
if (sender._postBackSettings.panelID == null ||
sender._postBackSettings.panelID.indexOf('ID_CLIENT_DE_L_UPDATEPANEL') != 0)
return;
panel = sender._postBackSettings.panelID;

var div = $get('ID_CLIENT_DU_DIV');
var nouveauDiv = document.createElement("div");
nouveauDiv.className = 'WaitProgressOverLayerClass2';
var nouveauDiv2 = document.createElement("div");
nouveauDiv2.innerHTML = 'TEXTE_A_AFFICHER';
nouveauDiv2.className = 'WaitProgressMessageClass2';
var img = document.createElement("img");
img.src = 'URL_DE_L_IMAGE';
nouveauDiv2.appendChild(img);
nouveauDiv.appendChild(nouveauDiv2);
div.appendChild(nouveauDiv);
}
function PageRequestManager_endRequest(sender, args)
{
var ctrl = sender._postBackSettings.panelID == null ? panel : sender._postBackSettings.panelID;
if (ctrl == null || ctrl.indexOf('ID_CLIENT_DE_L_UPDATEPANEL') != 0)
return;
var div = $get('ID_CLIENT_DU_DIV');
div.removeChild(div.lastChild);
}
</script>

Première chose à remarquer, dans la fonction PageRequestManager_initializeRequest, on commence par tester si le postback qui a été initié nous intéresse vraiment. En effet, ces événements sont levés pour tout postback, nous devons donc filtrer pour n'afficher l'overlayer que si c'est l'UpdatePanel correspondant qui est concerné par la mise à jour.
Pour ce faire, on va tester si l'objet sender._postBackSettings.panelID commence par l'ID de notre UpdatePanel.

On constate également qu'il y a des valeurs à remplacer, notamment ID_CLIENT_DE_L_UPDATEPANEL, ID_CLIENT_DU_DIV, TEXTE_A_AFFICHER et URL_DE_L_IMAGE.
Vous avez sans doute remarqué l'utilisation de la fonction $get qui est un raccourci défini par les extensions web pour utiliser document.getElementById.

Dans la méthode PageRequestManager_endRequest, on fait le même test pour vérifier que c'est le bon UpdatePanel.
NB : l'utilisation de la variable panel sert à éviter un bug qui peut arriver dans certains cas où, dans le PageRequestManager_endRequest, il n'est pas capable de récupérer la valeur de sender._postBackSettings.panelID.

Ce qui fait que notre OnPreRender ressemblera finalement à :

protected override void OnPreRender(EventArgs e)
{
string csslink = string.Format("<link href=\"{0}\" rel=\"stylesheet\" type=\"text/css\" />",
Page.ClientScript.GetWebResourceUrl(GetType(), "WaitPostback.WaitPostBack.css"));
LiteralControl include = new LiteralControl(csslink);
Page.Header.Controls.Add(include);
if (!string.IsNullOrEmpty(AssociatedDivID))
{
Control control = RecursiveFindControl(Page, AssociatedDivID);
UpdatePanel panel = (UpdatePanel)RecursiveFindControl(Page, AssociatedUpdatePanelID);
StringBuilder sb = new StringBuilder();
sb.Append("<script type=\"text/javascript\">\n");
sb.Append("var prm = Sys.WebForms.PageRequestManager.getInstance();\n");
sb.Append("var panel;\n");
sb.Append("prm.add_initializeRequest(PageRequestManager_initializeRequest);\n");
sb.Append("prm.add_endRequest(PageRequestManager_endRequest);\n");
sb.Append("function PageRequestManager_initializeRequest(sender, args) {\n");
sb.Append("panel = null;\n");
sb.Append("if (sender._postBackSettings.panelID == null ||
sender._postBackSettings.panelID.indexOf('" + panel.UniqueID + "') != 0)\n");
sb.Append("return;\n");
sb.Append("panel = sender._postBackSettings.panelID;\n");
sb.Append("var div = $get('" + control.ClientID + "');\n");
sb.Append("var nouveauDiv = document.createElement(\"div\");\n");
sb.Append("nouveauDiv.className = 'WaitProgressOverLayerClass2';\n");
sb.Append("var nouveauDiv2 = document.createElement(\"div\");\n");
sb.Append("nouveauDiv2.innerHTML = '" + Text + "';\n");
sb.Append("nouveauDiv2.className = 'WaitProgressMessageClass2';\n");
sb.Append("var img = document.createElement(\"img\");\n");
sb.Append("img.src = '" + Page.ClientScript.GetWebResourceUrl(GetType(), "WaitPostback.wait.gif") + "';\n");
sb.Append("nouveauDiv2.appendChild(img);\n");
sb.Append("nouveauDiv.appendChild(nouveauDiv2);\n");
sb.Append("div.appendChild(nouveauDiv);\n");
sb.Append("}\n");
sb.Append("function PageRequestManager_endRequest(sender, args) {\n");
sb.Append("var ctrl = sender._postBackSettings.panelID == null ? panel : sender._postBackSettings.panelID;\n");
sb.Append("if (ctrl == null || ctrl.indexOf('" + panel.UniqueID + "') != 0)\n");
sb.Append("return;\n");
sb.Append("var div = $get('" + control.ClientID + "');\n");
sb.Append("div.removeChild(div.lastChild);\n");
sb.Append("}\n");
sb.Append("</script>\n");
LiteralControl script = new LiteralControl(sb.ToString());
Controls.Add(script);
string cssadd = string.Format("<style type=\"text/css\">#{0}{{position:relative;}}</style>", control.ClientID);
LiteralControl add = new LiteralControl(cssadd);
Page.Header.Controls.Add(add);
}
base.OnPreRender(e);
}

On commence par rechercher les contrôles identifiés par AssociatedDivID et AssociatedUpdatePanelID grâce à la méthode RecursiveFindControl que l'on trouve dans la FAQ ASP.NET, afin de récupérer leurs UniqueID et ClientID.
Notez que j'utilise un LiteralControl pour insérer le contenu du javascript.
Notez également que pour trouver l'UpdatePanel concerné par le postback, on a besoin d'utiliser l'ID unique (UniqueID).
Je n'ai pas utilisé de fichier JS pour mettre ce javascript car n'oubliez pas que l'on doit absolument positionner ce javascript après la balise ScriptManager. Cela sera également plus simple pour gérer les différents paramètres, comme le texte à afficher, l'url de l'image ou l'id du div.

Les observateurs auront pu noter que j'ai défini d'autres classes CSS, en effet, j'avais besoin d'un effet légèrement différent. Les deux classes sont :

.WaitProgressOverLayerClass2
{
position: absolute;
left: 0px;
top: 0px;
background-color: gray;
filter: alpha(opacity=70);
opacity: 0.7;
-moz-opacity: 0.7;
z-index: 10;
width:100%;
}
.WaitProgressMessageClass2
{
background-color: #eee;
padding: 10px;
border: 1px solid black;
z-index: 9;
filter: alpha(opacity=100);
-moz-opacity: 1.00;
text-align: center;
}

J'ai principalement enlevé les notions de taille et certaines de positionnement.

Les observateurs encore plus méticuleux auront remarqué ce bout de code à la fin :

string cssadd = string.Format("<style type=\"text/css\">#{0}{{position:relative;}}</style>", control.ClientID);
LiteralControl add = new LiteralControl(cssadd);
Page.Header.Controls.Add(add);

Cela permet de rajouter un style au conteneur afin d'indiquer que c'est une position relative. J'utilise pour cela l'identifiant du contrôle.
Sans cette position relative, on ne serait pas capable de positionner correctement l'overlayer, dont la position absolue est basée sur l'origine du conteneur.
Un inconvénient de ce positionnement est qu'il impose au conteneur d'être en position relative, mais c'est bien souvent le cas dans un site web.

5.3.Exemple

La copie d'écran que l'on voit au paragraphe 5 correspond au code suivant. J'ai volontairement encadré l'UpdatePanel d'un div pour fixer sa taille en largeur afin que l'on se rende bien compte de l'overlayer partiel.

<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div style="width:300px;">
<asp:UpdatePanel ID="PartialUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button ID="Button1" runat="server" OnClick="DoPostBack" Text="Recharger" />
<asp:Label runat="server" ID="Label2" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<Exemple:WaitPostback ID="WaitPostbackPartial" runat="server" AssociatedDivID="PartialUpdatePanel"
Text="Veuillez patienter..." AssociatedUpdatePanelID="PartialUpdatePanel" />
<asp:TextBox ID="TextBox1" runat="server" />

On observe bien la valeur de la propriété AssociatedDivID qui correspond à l'ID de l'UpdatePanel.

Remarque : Dans cet exemple, je fais confiance à l'utilisateur en présupposant qu'il ne va pas mettre n'importe quoi dans la propriété AssociatedDivID. J'aurai tout intérêt à définir des attributs sur la propriété, comme IDReferenceProperty et TypeConverter, afin de n'autoriser que des champs attendus.
Ceci ne faisant pas partie de la portée de cet article, ceux qui voudront des précisions sur ces propriétés pourront se référer à mon article sur les validateurs, chapitre 7.

6.Exemple de deux contrôles en même temps

6.1.Exemple

Grâce aux conditions de filtre que l'on établit dans le contrôle, il est possible de mixer à la fois un contrôle avec overlayer total ainsi qu'un contrôle avec overlayer partiel.
Voici un exemple qui illustre ce point :

<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:Label runat="server" ID="LabelRefer" />
<br />
<br />
<br />
<p>Ce bouton rafraichit l'heure et bloque toute la page</p>
<asp:UpdatePanel runat="server" ID="TotalUpdatePanel" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button runat="server" Text="Recharger" OnClick="DoPostBack" />
<asp:Label runat="server" ID="Label1" />
</ContentTemplate>
</asp:UpdatePanel>
<Exemple:WaitPostback ID="WaitPostbackAll" runat="server" AssociatedUpdatePanelID="TotalUpdatePanel"
Text="Veuillez patienter pendant que je mets à jour les informations ..." />
<br />
<br />
<br />
<br />
<p>Celui-ci rafraichit l'heure et bloque uniquement la zone rafraichie</p>
<div style="width: 300px;">
<asp:UpdatePanel ID="PartialUpdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Button runat="server" OnClick="DoPostBack" Text="Recharger" />
<asp:Label runat="server" ID="Label2" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<Exemple:WaitPostback ID="WaitPostbackPartial" runat="server" AssociatedDivID="PartialUpdatePanel"
Text="Veuillez patienter..." AssociatedUpdatePanelID="PartialUpdatePanel" />
<br />
<br />
<p>TextBox témoin pour montrer qu'on peut saisir une valeur pendant le postback du deuxième bouton</p>
<asp:TextBox runat="server" />

private void MajLabel()
{
Label1.Text = DateTime.Now.ToLongTimeString();
Label2.Text = DateTime.Now.ToLongTimeString();
LabelRefer.Text = DateTime.Now.ToLongTimeString();
}

protected override void OnLoad(EventArgs e)
{
MajLabel();
base.OnLoad(e);
}

protected void DoPostBack(object sender, EventArgs e)
{
Thread.Sleep(5000);
MajLabel();
}

Ce qui nous donnera :

Remarque : Dans l'exemple, je positionne l'UpdateMode de l'UpdatePanel à Conditional pour que ne soit rafraichi que l'UpdatePanel concerné.

6.2.Téléchargement

Vous pouvez télécharger les sources des deux projets - version rar (77 Ko) - version zip (84 Ko).

7.Conclusion

Grâce à ce tutoriel, nous avons vu comment encapsuler le contrôle UpdateProgress pour permettre d'informer un utilisateur qu'il doit attendre la fin d'un postback partiel.
Nous avons vu également comment on pouvait empêcher l'utilisateur de faire autre chose pendant cette attente en affichant un overlayer sur toute la page.
Cet article a également décrit comment incorporer des ressources (image ou CSS) dans notre contrôle serveur.
Enfin, vous aurez vu un aperçu du cycle de vie d'un postback AJAX ainsi que la façon dont agir sur les éléments HTML lors de ces événements clients.

J'espère que vous avez trouvé cet article intéressant et que ce contrôle pourra vous être utile.

Remerciements

Je remercie particulièrement Gwen pour ses explications sur le positionnement des div ainsi que l'équipe Dotnet pour leurs relectures attentives du document.

Contact

Si vous constatez une erreur dans le tutoriel, dans le source, dans la programmation ou pour toutes informations, n'hésitez pas à me contacter par mail, ou par le forum.