IntroductionIl
est souvent utile d'afficher des messages « veuillez patienter » ou des images gif animées pendant le processus de soumission de formulaire d'une application Web, en particulier lorsque le processus de soumission prend beaucoup de temps. J'ai récemment développé un programme de soumission d'enquêtes dans lequel les utilisateurs internes téléchargent des feuilles de calcul Excel via une page Web. Le programme insère les données de la feuille de calcul téléchargées dans la base de données. Ce processus ne prend que quelques secondes, mais même s'il dure quelques secondes, il s'agit d'un processus d'attente très évident du point de vue de la page Web. Lors des tests du programme, certains utilisateurs ont cliqué à plusieurs reprises sur le bouton de téléchargement. Il est donc utile de fournir un message visuel pour informer les gens que le téléchargement est en cours. Et masquez le bouton de téléchargement en même temps pour éviter plusieurs clics. Le contrôle présenté ici est une sous-classe du contrôle Button, qui montre comment encapsuler le code JavaScript côté client dans un contrôle serveur ASP.NET pour fournir des fonctions pratiques.
Bien qu'il existe de nombreux exemples javascript pour y parvenir, j'ai rencontré quelques problèmes lorsque j'ai essayé d'encapsuler ces fonctions dans des contrôles ASP.NET. J'ai d'abord essayé d'invalider le bouton via le gestionnaire javascript onclick et de le remplacer par un autre texte. Mais j'ai trouvé cela très délicat, car cela entraverait le fonctionnement de l'événement click du côté du serveur asp.net. Ce qui a finalement fonctionné et qui offrait un bon support pour différents navigateurs, c'était d'afficher le bouton dans une balise div. Le div peut être masqué et hors de portée de l'événement click d'asp.net.
Utilisation du contrôle
En tant que dérivé du contrôle bouton normal, les fonctions de PleaseWaitButton sont fondamentalement les mêmes. Il utilise trois propriétés supplémentaires pour gérer l'affichage des messages ou des images « veuillez patienter » lorsque le bouton est cliqué.
S'il vous plaîtAttendezTexte
Il s'agit du message texte côté client qui s'affiche et, s'il est présent, remplacera le bouton lorsque celui-ci est cliqué.
S'il vous plaîtAttendezImage
Il s'agit du fichier image (comme une image GIF animée) qui est affiché et, s'il est présent, remplacera le bouton lorsque vous cliquerez dessus. Cet attribut deviendra l'attribut src dans la balise <img>.
S'il vous plaîtWaitType
Une des valeurs d’énumération PleaseWaitTypeEnum : TextOnly, ImageOnly, TextThenImage ou ImageThenText. Il contrôle la disposition des messages et des images.
Vous trouverez ci-dessous un exemple de fichier .aspx qui illustre un PleastWaitButton avec l’ensemble PleaseWaitText et PleaseWaitImage.
<%@ Langage de la page="C#" %>
<%@ Register TagPrefix="cc1" Namespace="JavaScriptControls"
Assembly="VeuillezWaitButton" %>
<script runat="serveur">
vide privé PleaseWaitButton1_Click (expéditeur de l'objet, System.EventArgs e)
{
// Gestionnaire d'événements Click côté serveur ;
// simule quelque chose qui pourrait prendre beaucoup de temps,
// comme un téléchargement de fichier ou un traitement serveur fastidieux
DateTime dt = DateTime.Now.AddSeconds(5);
tandis que (DateTime.Now < dt)
{
// ne fait rien ; simule une pause de 5 secondes
}
// à la fin de la boucle affiche un message de réussite
// et masque le formulaire de soumission
panelSuccess.Visible = true;
PleaseWaitButton1.Visible = false ;
}
</script>
<html>
<tête>
<title>Test de PleaseWaitButton</title>
</tête>
<corps>
<form id="Form1" method="post" runat="server">
<P>Test du contrôle PleaseWaitButton.</p>
<cc1: PleaseWaitButton id = " PleaseWaitButton1 " runat = " serveur "
Text="Cliquez sur moi pour démarrer un processus fastidieux"
PleaseWaitText="Veuillez patienter "
PleaseWaitImage="pleaseWait.gif"
OnClick="VeuillezWaitButton1_Click" />
<asp:Panel id="panelSuccess" runat="server"
visible="faux">
Merci d'avoir soumis ce formulaire. Vous êtes vraiment.
l'utilisateur le plus cool que j'ai jamais eu le plaisir de servir.
Non, vraiment, je le pense, il y en a eu d'autres, bien sûr,
mais vous êtes vraiment dans une classe à part.
</asp:Panneau>
</form>
</corps>
</html>
Comment ça marche
Le contrôle PleaseWaitButton restitue un bouton ASP.NET standard à l'intérieur d'une balise <div>. Il affiche également une balise <div> vide pour les informations/images. Lorsque le bouton est cliqué, le masquage du bouton et l'affichage des informations sont contrôlés par la fonction Javascript (voir fonction client ci-dessous). Pour plus de commodité, l'implémentation de tout le code client javascript nécessaire est gérée par le contrôle serveur PleaseWaitButton.
Étant donné que PleaseWaitButton implémente son propre gestionnaire onclick javascript, nous devons prendre quelques mesures supplémentaires pour conserver le gestionnaire onclick d'origine et permettre au contrôle d'exécuter proprement du code de validation côté client. Afin d'atteindre cet objectif, nous restaurons d'abord la classe de base Button dans un tampon de chaîne, puis la gérons habilement pour inclure le code onclick que nous avons défini.
remplacement protégé void Render (sortie HtmlTextWriter)
{
// Sortie du code HTML du bouton (avec attributs)
// vers un HtmlTextWriter factice
StringWriter sw = new StringWriter();
HtmlTextWriter wr = new HtmlTextWriter(sw);
base.Render(wr);
string sButtonHtml = sw.ToString();
wr.Close();
sw.Close();
// modifie maintenant le code pour inclure un gestionnaire "onclick"
// avec notre fonction PleaseWait() appelée de manière appropriée
// après toute validation côté client.
sButtonHtml = ModifyJavaScriptOnClick(sButtonHtml);
// avant de rendre le bouton, affiche un <div> vide
// qui sera renseigné côté client via javascript
// avec un message "veuillez patienter""
sortie.Write(string.Format("<div id='pleaseWaitButtonDiv2_{0}'>",
this.ClientID));
output.Write("</div>");
// affiche le bouton dans sa propre balise <div> encapsulante
output.Write(string.Format("<div id='pleaseWaitButtonDiv_{0}'>",
this.ClientID));
sortie.Write(sButtonHtml);
sortie.Write("</div>");
}
Cette technique consistant à réduire le bouton à un tampon de chaîne puis à traiter son contenu onclick est certainement un hack. Mais elle nous permet d'implémenter un code de validation standard dans la classe du bouton parent, puis d'implémenter notre appel de fonction Javascript PleaseWait(). Sans cela, nous devrions implémenter notre appel de fonction PleaseWait() dans l'attribut onclick avant le code de validation, à moins que nous ne souhaitions remplacer complètement le rendu de l'attribut de la classe Button parent. De cette façon, même s'il y a des erreurs de saisie sur la page, cela aura pour effet de masquer le bouton et d'afficher le message « please wait » dont on ne veut pas. Par conséquent, nous devons forcer notre fonction client PleaseWait() dans le gestionnaire onclick à apparaître après validation de la page client.
La modification de l'attribut onclick s'effectue dans la fonction ModifyJavaScriptOnClick(). Cette fonction récupère la chaîne HTML rendue par le bouton et vérifie si l'attribut onclick est présent. Si tel est le cas, cette fonction vérifie si le code de validation côté client est utilisé. Si tel est le cas, la fonction PleaseWait() que nous avons définie sera ajoutée à la fin du code onclick existant, immédiatement après la vérification de la variable boolin Page_IsValid par le client. Cette variable indique si le contrôle de validation est utilisé. Si la valeur de Page_IsValid est fausse, le message « Veuillez patienter » ne s'affichera pas. Affiché si vrai.
chaîne privée ModifyJavaScriptOnClick (string sHtml)
{
// Merci au membre de CodeProject KJELLSJ (Kjell-Sverre Jerijaervi)
// pour des idées de code permettant au bouton de fonctionner avec
la chaîne de validation côté client sReturn = "";
string spleaseWaitCode = GeneratepleaseWaitJavascript();
// existe-t-il un attribut onclick existant ?
Regex rOnclick = new Regex("onclick="(?<onclick>[^"]*)");
Match mOnclick = rOnclick.Match(sHtml);
si (mOnclick.Succès)
{
// il existe un attribut onclick existant ;
// ajoute notre code à la fin si c'est côté client
// la validation a été rendue, assurez-vous
// on vérifie si la page est valide ;
chaîne sExisting = mOnclick.Groups["onclick"].Value ;
chaîne sRemplacer = sExistant
+ (sExisting.Trim().EndsWith(";") ? "" : "; ");
if (IsValidatorIncludeScript() && this.CausesValidation)
{
// inclut du code pour vérifier si la page est valide
chaîne sCode = "if (Page_IsValid) " + spleaseWaitCode
+ "retour Page_IsValid;";
// ajoute notre code à la fin du code onclick existant ;
sRemplacer = sRemplacer + sCode ;
}
autre
{
// ne vous inquiétez pas de la validité de la page ;
sRemplacer = sRemplacer + sVeuillezWaitCode ;
}
// remplacez maintenant notre code onclick
sRemplacer = "onclick="" + sRemplacer ;
sReturn = rOnclick.Replace(sHtml, sReplace);
}
autre
{
// il n'existe pas d'attribut onclick existant ;
// ajoute le nôtre
int i = sHtml.Trim().Length - 2;
string sInsert = " onclick="" + spleaseWaitCode + "" ";
sReturn = sHtml.Insert(i, sInsert);
}
return sReturn;
}
IsValidatorIncludeScript() utilise la vérification ci-dessus pour voir s'il existe un bloc de code Javascript standard pour le contrôle de validation asp.net enregistré avec la page. Ce qui suit utilise une méthode simple pour tester s'il existe un code de validation et des variables telles que Page_IsValid.
bool privé IsValidatorIncludeScript()
{
// renvoie TRUE si cette page a enregistré du javascript
// pour la validation côté client ; ce code ne peut pas être enregistré
// si ASP.NET détecte ce qu'il pense (correctement ou incorrectement)
// est un navigateur de bas niveau.
return this.Page.IsStartupScriptRegistered("ValidatorIncludeScript");
} Le GeneratepleaseWaitJavascript() suivant construit la fonction Javascript PleaseWait() contenue dans l'attribut onclick. Nous pouvons déterminer la disposition souhaitée en inspectant les propriétés du contrôle.
chaîne privée GeneratepleaseWaitJavascript()
{
// crée un appel de fonction JavaScript "pleaseWait()"
// convient pour une utilisation dans un gestionnaire d'événements onclick
string sMessage = "";
chaîne sText = _pleaseWaitText ;
string sImage = (_pleaseWaitImage != String.Empty
? chaîne.Format(
"<img src="{0}" align="absmiddle" alt="{1}"/>"
, _pleaseWaitImage, _pleaseWaitText )
: String.Empty);
// établit la mise en page basée sur PleaseWaitType
commutateur (_pleaseWaitType)
{
cas PleaseWaitTypeEnum.TextThenImage :
sMessage = sTexte + sImage ;
casser;
cas PleaseWaitTypeEnum.ImageThenText :
sMessage = sImage + sTexte ;
casser;
cas PleaseWaitTypeEnum.TextOnly :
sMessage = sTexte ;
casser;
cas PleaseWaitTypeEnum.ImageOnly :
sMessage = sImage;
casser;
}
// renvoie le morceau de code final
chaîne sCode = chaîne.Format(
"Veuillezattendre('pleaseWaitButtonDiv_{0}',
'pleaseWaitButtonDiv2_{1}', '{2}');"
, this.ClientID, this.ClientID, sMessage);
sCode = sCode.Replace(""", """);
return sCode;
}
Si vous spécifiez PleaseWaitImage, vous devez inclure un élément de code Javascript supplémentaire pour informer le client de précharger l'image. L'enregistrement de ce script doit apparaître dans la méthode OnPreRender remplacée. La clé enregistrée est le nom de l'image ; si plusieurs boutons utilisent la même image, le script de préchargement ne doit être implémenté qu'une seule fois. Une expression régulière est utilisée ici pour créer une variable d'image Javascript afin de garantir que les caractères spéciaux (tels que les barres obliques dans les chemins de fichiers) sont convertis en traits de soulignement.
remplacement protégé void OnPreRender (EventArgs e)
{
base.OnPreRender (e);
// Si nous utilisons une image, enregistrez du javascript
// pour le préchargement des images côté client
if (_pleaseWaitImage != String.Empty
&& _pleaseWaitType != PleaseWaitTypeEnum.TextOnly)
RegisterJavascriptPreloadImage(_pleaseWaitImage);
}
vide privé RegisterJavascriptPreloadImage (string sImage)
{
Regex rex = new Regex("[^a-zA-Z0-9]");
chaîne sImgName = "img_" + rex.Replace(sImage, "_")
;
sb.Append("<script langage='JavaScript'>");
sb.Append("if (document.images) { ");
sb.AppendFormat("{0} = new Image();", sImgName);
sb.AppendFormat("{0}.src = "{1}";", sImgName, sImage);
sb.Append(" } ");
sb.Append("</script>");
this.Page.RegisterClientScriptBlock(sImgName + "_PreloadScript",
sb.ToString());
}
Fonctions côté client
Le fichier texte intégré javascript.txt contient le <div> qui masque le bouton et le code côté client qui affiche le message ou l'image « veuillez patienter ». Ces codes sont chargés dans la méthode privée RegisterJavascriptFromResource() appelée dans la méthode OnInit() substituée. Cette méthode appelle la méthode générique GetEmbeddedTextFile(), qui charge le fichier en tant que source et renvoie le contenu sous forme de chaîne.
remplacement protégé void OnInit (EventArgs e)
{
base.OnInit(e);
// le code javascript côté client est conservé
// dans une ressource embarquée ; charge le script
// et enregistrez-le avec la page.
RegisterJavascriptFromResource();
}
privé vide RegisterJavascriptFromResource()
{
// charge le fichier texte intégré "javascript.txt"
// et enregistre son contenu en tant que script côté client
chaîne sScript = GetEmbeddedTextFile("javascript.txt");
this.Page.RegisterClientScriptBlock("pleaseWaitButtonScript", sScript);
}
chaîne privée GetEmbeddedTextFile (chaîne sTextFile)
{
// fonction générique pour récupérer le contenu
// d'une ressource de fichier texte incorporée sous forme de chaîne
// nous obtiendrons l'assembly en cours d'exécution et dériverons
// l'espace de noms utilisant le premier type dans l'assembly
Assemblage a = Assembly.GetExecutingAssembly();
String sNamespace = a.GetTypes()[0].Namespace;
// avec l'assembly et l'espace de noms, nous obtiendrons le
//ressource intégrée sous forme de flux
Flux s = a.GetManifestResourceStream(
string.Format("{0}.{1}", sNamespace, sTextFile)
);
// lit le contenu du flux dans une chaîne
StreamReader sr = nouveau(x) StreamReader(s) ;
String sContents = sr.ReadToEnd();
sr.Close();
s.Close();
renvoie sContents ;
}
La ressource intégrée javascript.txt contient la méthode côté client PleaseWait() qui est exécutée dans le gestionnaire Javascript onclick du bouton. Ce code appelle également une méthode côté client HideDiv() pour masquer le conteneur <div> du bouton, puis assemble les informations ou l'image dans la balise <div> précédemment vide en définissant l'attribut innerHTML. La fonction auxiliaire GetDiv() renvoie un objet <div> avec un identifiant en vérifiant document.getElementById, document.all et document.layers, garantissant ainsi la compatibilité avec les différents navigateurs. Vous trouverez ci-dessous le code complet de javascript.txt :
<langage de script="JavaScript">
fonction GetDiv(sDiv)
{
vardiv;
si (document.getElementById)
div = document.getElementById(sDiv);
sinon si (document.all)
div = eval("fenêtre." + sDiv);
sinon si (document.layers)
div = document.layers[sDiv];
autre
div = nul ;
renvoie div ;
}
fonction HideDiv(sDiv)
{
d = GetDiv(sDiv);
si(d)
{
if (document.layers) d.visibility = "masquer" ;
sinon d.style.visibility = "caché" ;
}
}
fonction PleaseWait(sDivButton, sDivMessage, sInnerHtml)
{
MasquerDiv(sDivButton);
var d = GetDiv(sDivMessage);
si (d) d.innerHTML = sInnerHtml ;
}
</script>
Lien original : http://www.codeproject.com/aspnet/pleaseWaitButton.asp
Télécharger le projet source - 7 Ko
Télécharger le projet de démonstration - 30 Ko
http://www.cnblogs.com/jeffamy/archive/2006/08/20/481952.html