Cours développement WEB avec ASP.NET, tutoriel & guide de travaux pratiques les fonctions accesseur en pdf.
Gérer l’événement Click d’un objet Button
Rappelons le fonctionnement d’une page .aspx. Celle-ci est un objet dérivé de la classe [Page]. Appelons la classe dérivée [unePage]. Lorsque le serveur reçoit une requête pour une telle page, un objet de type [unePage] est instancié par une opération [new unePage(…)]. Puis ensuite, le serveur génère deux événements appelés [Init] et [Load] dans cet ordre. L’objet [unePage] peut les gérer en fournissant les gestionnaires d’événements [Page_Init] et [Page_Load]. Ensuite d’autres événements seront générés. Nous aurons l’occasion d’y revenir. Si la requête du client est un POST, le serveur générera l’événement [Click] du bouton qui a provoqué ce POST. Si la classe [unePage] a prévu un gestionnaire pour cet événement, celui-ci sera appelé. Voyons ce mécanisme avec WebMatrix. Dans l’onglet [Design] de [form3.aspx], double-cliquons sur le bouton [Bouton1]. Nous sommes alors amenés automatiquement dans l’onglet [Code], dans le corps d’une procédure appelée [Button1_Click]. Pour mieux comprendre, allons dans l’onglet [All] et regardons la totalité du code. Les modifications suivantes ont été apportées :
<%@ Page Language= »VB » %>
<script runat= »server »>
…
Sub Button1_Click(sender As Object, e As EventArgs)
End Sub
</script>
<html>
…
<body>
<form runat= »server »>
…
<asp:Button id= »Button1″ onclick= »Button1_Click » runat= »server » Text= »Bouton1″></asp:Button>
</form>
</body>
</html>
Un nouvel attribut [onclick= »Button1_Click »] a été ajouté à la balise <asp:Button> de [Button1]. Cet attribut indique la procédure chargée de traiter l’événement [Click] sur l’objet [Button1], ici la procédure [Button1_Click]. Il ne nous reste plus qu’à écrire celle-ci :
Sub Button1_Click(sender As Object, e As EventArgs)
‘ clic sur bouton 1
lblInfo.Text= »Vous avez cliqué sur [Bouton1] »
End Sub
La procédure met dans le label [lblInfo] un message d’information. Nous procédons de la même façon pour le bouton [Bouton2] pour obtenir la nouvelle page [form3.aspx] suivante :
<%@ Page Language= »VB » %>
<script runat= »server »>
Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
‘ sauve la requte courante dans request.txt du dossier de la page
Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + « \request.txt » Me.Request.SaveAs(requestFileName, True)
End Sub
Sub Button1_Click(sender As Object, e As EventArgs)
‘ clic sur bouton 1
lblInfo.Text= »Vous avez cliqué sur [Bouton1] »
End Sub
Sub Button2_Click(sender As Object, e As EventArgs)
‘ clic sur bouton 2
lblInfo.Text= »Vous avez cliqué sur [Bouton2] »
End Sub
</script>
<html>
<head>
<title>asp:button</title>
</head>
<body>
<form runat= »server »>
<p>
<asp:Button id= »Button1″ onclick= »Button1_Click » runat= »server » Text= »Bouton1″></asp:Button> <asp:Button id= »Button2″ onclick= »Button2_Click » runat= »server » Text= »Bouton2″></asp:Button>
</p>
<p>
<asp:Label id= »lblInfo » runat= »server »></asp:Label>
</p>
</form>
</body>
</html>
Nous lançons l’exécution par [F5] pour obtenir la page suivante :
Si nous regardons le code HTML reçu, nous constaterons qu’il n’a pas changé vis à vis de celui de la version précédente de la page :
<html>
<head>
<title>asp:button</title>
</head>
<body>
<form name= »_ctl0″ method= »post » action= »form3.aspx » id= »_ctl0″>
<input type= »hidden » name= »__VIEWSTATE » value= »dDwxNTY0NjIwMjUwOzs+2mcnJczeuvF2PEfvmtv7uiUhWUw= » />
<p>
<input type= »submit » name= »Button1″ value= »Bouton1″ id= »Button1″ /> <input type= »submit » name= »Button2″ value= »Bouton2″ id= »Button2″ />
</p>
<p>
<span id= »lblInfo »></span>
</p>
</form>
</body>
</html>
Si nous cliquons sur [Bouton1], nous obtenons la réponse suivante :
Le code HTML reçu pour cette réponse est le suivant :
<html>
<head>
<title>asp:button</title>
</head>
<body>
<form name= »_ctl0″ method= »post » action= »form3.aspx » id= »_ctl0″>
<input type= »hidden » name= »__VIEWSTATE »
value= »dDwxNTY0NjIwMjUwO3Q8O2w8aTwxPjs+O2w8dDw7bDxpPDU+Oz47bDx0PHA8cDxsPFRleHQ7PjtsPFZvdXMgYXZleiBjbGlxd
cOpIHN1ciBbQm91dG9uMV07Pj47Pjs7Pjs+Pjs+Pjs+4oO98Vd244kj0lPMXReWOwJ1WW0= » />
<p>
<input type= »submit » name= »Button1″ value= »Bouton1″ id= »Button1″ /> <input type= »submit » name= »Button2″ value= »Bouton2″ id= »Button2″ />
</p>
<p>
<span id= »lblInfo »>Vous avez cliqué sur [Bouton1]</span>
</p>
</form>
</body>
</html>
Nous pouvons constater que le champ caché [__VIEWSTATE] a changé de valeur. Cela reflète le changement de valeur du composant [lblInfo].
Les événements de la vie d’une application ASP.NET
La documentation ASP.NET donne la liste des événements générés par le serveur au cours de la vie d’une application :
• lors de la toute première requête que reçoit l’application, l’événement [Start] sur l’objet [HttpApplication] de l’application va être généré. Cet événement peut être géré par la procédure [Application_Start] du fichier [global.asax] de l’application.
Ensuite nous allons avoir une série d’événements qui vont se répéter pour chaque requête reçue :
• si la requête n’a pas envoyé de jeton de session, une nouvelle session est démarrée et un événement [Start] sur l’objet [Session] associé à la requête est généré. Cet événement peut être géré par la procédure [Session_Start] du fichier [global.asax] de l’application.
• le serveur génère l’événement [BeginRequest] sur l’objet [HttpApplication]. Il peut être géré par la procédure [Application_BeginRequest] du fichier [global.asax] de l’application.
• le serveur charge la page demandée par la requête. Il va instancier un objet [Page] puis générer deux événements sur cet objet : [Init] puis [Load]. Ces deux événements peuvent être gérés par les procédure [Page_Init] et [Page_Load] de la page.
• à partir des valeurs postées reçues, le serveur va générer d’autres événements : [TextChanged] pour un composant [TextBox] qui a changé de valeur, [CheckedChanged] pour un bouton radio qui a changé de valeur, [SelectedIndexChanged] pour une liste qui a changé d’élément sélectionné, … Nous aurons l’occasion de mentionner les principaux événements pour chacun des composants serveur que nous allons présenter. Chaque événement E sur un objet nommé O peut être géré par une procédure portant le nom O_E.
• l’ordre de gestion des événements précédents n’est pas garanti. Aussi les gestionnaires ne doivent-ils faire aucune hypothèse sur cet ordre. On est cependant assuré que l’événement [Click] du bouton qui a provoqué le POST est traité en dernier.
• une fois la page prête, le serveur va l’envoyer au client. Avant, il génère l’événement [PreRender] qui peut être géré par la procédure [Page_PreRender] de la page.
• une fois la réponse HTML envoyée au client, la page va être déchargée de la mémoire. Deux événements seront générés à cette occasion [Unload] et [Disposed]. La page peut utiliser ces événements pour libérer des ressources.
L’application peut également recevoir des événements en-dehors d’une requête client :
• l’événement [End] sur un objet [Session] de l’application se produit lorsqu’une session se termine. Cela peut se produire sur une demande explicite du code d’une page soit parce que la durée de vie accordée à la session est dépassée. La procédure [Session_End] du fichier [global.asax] gère cet événement. On y libère en général des ressources obtenues dans [Session_Start].
• l’événement [End] sur l’objet [HttpApplication] de l’application se produit lorsque l’application se termine. Cela se produit notamment lorsqu’on arrête le serveur Web. La procédure [Application_End] du fichier [global.asax] gère cet événement. On y libère en général des ressources obtenues dans [Application_Start].
On retiendra les points suivants :
• le modèle événementiel précédent s’appuie sur des échanges HTTP client-serveur classiques. On le voit parfaitement lorsqu’on examine les entêtes HTTP échangés.
• le traitement des événements précédents se fait toujours côté serveur. Le clic sur un bouton peut bien sûr être traité par un script Javascript côté serveur. Mais il ne s’agit pas alors d’un événement serveur et on est là dans une technologie indépendante de ASP.NET.
A quel moment sont traités les événements, qu’ils soient traités du côté serveur (événements liés aux composants serveur) ou du côté navigateur par des scripts Javascript ?
Prenons l’exemple d’une liste déroulante. Lorsque l’utilisateur change l’élément sélectionné dans celle-ci, l’événement (changement de l’élément sélectionné) peut être traité ou non et s’il est traité il peut l’être à différents moments.
• si on souhaite le traiter immédiatement, on a deux solutions :
o il peut être traité par le navigateur à l’aide d’un script Javascript. Le serveur n’intervient alors pas. Pour que cela soit possible, il faut que la page puisse être reconstruite avec des valeurs déjà présentes dans la page.
o il peut être traité par le serveur. Pour cela, il n’y a qu’une solution : le formulaire doit être envoyé au serveur pour traitement. On a donc une opération [submit]. On verra que dans ce cas, on utilise un composant serveur appelé [DropDownList] et on fixe son attribut [AutoPostBack] à [true]. Cela veut dire qu’en cas de changement de l’élément sélectionné dans la liste déroulante, le formulaire doit être immédiatement posté au serveur. Le serveur génère dans ce cas, pour l’objet [DropDownList] un code HTML associé à une fonction Javascript chargée de faire un [submit] dès que l’événement « changement de l’élément sélectionné » se produit. Ce [submit] postera le formulaire au serveur et dans celui-ci, des champs cachés seront positionnés pour indiquer que le [post] provient d’un changement de sélection dans la liste déroulante. Le serveur génèrera alors l’événement [SelectedIndexChanged] que la page pourra gérer.
• si on souhaite le traiter mais pas immédiatement, on fixe l’attribut [AutoPostBack] du composant serveur [DropDownList]
à [false]. Le serveur génère dans ce cas, pour l’objet [DropDownList] le code HTML classique d’une liste <select> sans fonction Javascript associée. Rien ne se passe alors lorsque l’utilisateur change la sélection de la liste déroulante. Cependant, lorsqu’il va valider le formulaire par un bouton [submit] par exemple, le serveur va pouvoir reconnaître qu’il y a eu un changement de sélection. Nous avons en effet vu que le formulaire envoyé au serveur avait un champ caché [__VIEWSTATE] représentant sous une forme codée l’état de tous les éléments du formulaire envoyé. Lorsque le serveur reçoit le nouveau formulaire posté par le client, il va recevoir ce champ parmi les éléments postés. Il y trouvera l’élément qui était sélectionné dans la liste lorsque le formulaire a été envoyé au navigateur. Parmi les éléments postés par le navigateur dans la requête suivante, il y aura le nouvel élément sélectionné dans la liste. Le serveur Web / ASP.NET va ainsi pouvoir vérifier si la liste déroulante a changé ou non d’élément sélectionné. Si oui, il va générer l’événement [SelectedIndexChanged] que la page pourra alors gérer. Pour distinguer ce mécanisme du précédent, certains auteurs disent que l’événement « changement de sélection » a été mis « en cache » lorsqu’il s’est produit sur le navigateur . Il ne sera traité par le serveur que lorsque le navigateur lui postera le formulaire, à la suite souvent d’un clic sur un bouton [submit].
• enfin si on ne souhaite pas traiter l’événement, on fixe l’attribut [AutoPostBack] du composant serveur [DropDownList] à [false] et on n’écrit pas le gestionnaire de son événement [SelectedIndexChanged].
Une fois compris le mécanisme de traitement des événements, le développeur ne concevra pas une application web comme une application windows. En effet, si un changement de sélection dans un combobox d’une application windows peut être utilisé pour changer immédiatement l’aspect du formulaire dans lequel se trouve celui-ci, on hésitera davantage à traiter cet événement immédiatement dans une application web, s’il implique un « post » du formulaire au serveur donc un aller-retour réseau entre le client et le serveur. C’est pourquoi, la propriété [AutoPostBack] des composants serveur est mise à [false] par défaut. Par ailleurs, le mécanisme [AutoPostBack] qui s’appuie sur des scripts javascript générés automatiquement par le serveur web dans le formulaire envoyé au client ne peut être utilisé que si on est sûr que le navigateur client a autorisé l’exécution des scripts javascript sur son navigateur. Les formulaires sont donc souvent construits de la façon suivante :
• les composants serveur du formulaire ont leur propriété [AutoPostBack] à [false]
• le formulaire a un ou des boutons chargés de faire le [POST] du formulaire
• on écrit dans le code contrôleur de la page, les gestionnaires des seuls événements qu’on veut gérer, le plus souvent l’événement [Click] sur un des boutons.
Le composant TextBox
Utilisation
La balise <asp:TextBox> permet d’insérer un champ de saisie dans le code de présentation d’une page. Nous créons une page [form4.aspx] pour obtenir la présentation suivante :
Cette page construite avec WebMatrix a les composants suivants : n° nom type propriétés rôle
1 TextBox1 TextBox AutoPostback=true champ de saisie Text=(rien)
2 TextBox2 TextBox AutoPostback=false champ de saisie Text=(rien)
3 Label Text=(rien) message d’information sur le contenu de [TextBox1] lblInfo1
3 Label Text=(rien) message d’information sur le contenu de [TextBox2]
lblInfo2
Le code généré par WebMatrix pour cette partie est le suivant :
<%@ Page Language= »VB » %>
<script runat= »server »>
</script>
<html>
<head>
<title>asp:textbox</title>
</head>
<body>
<form runat= »server »>
<p>
Texte 1 :
<asp:TextBox id= »TextBox1″ runat= »server » AutoPostBack= »True »></asp:TextBox>
</p>
<p>
Texte 2 :
<asp:TextBox id= »TextBox2″ runat= »server »></asp:TextBox>
</p>
<p>
<asp:Label id= »lblInfo1″ runat= »server »></asp:Label>
</p>
<p>
<asp:Label id= »lblInfo2″ runat= »server »></asp:Label>
</p>
</form>
</body>
</html>
Dans l’onglet [Design], double-cliquons sur le composant [TextBox1]. Le squelette du gestionnaire de l’événement [TextChanged] de cet objet est alors généré (onglet [All]) :
<%@ Page Language= »VB » %>
<script runat= »server »>
Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
End Sub
</script>
<html>
…
<body>
…
<asp:TextBox id= »TextBox1″ runat= »server » AutoPostBack= »True »
OnTextChanged= »TextBox1_TextChanged »></asp:TextBox>
</p>
….
</form>
</body>
</html>
L’attribut [OnTextChanged= »TextBox1_TextChanged »] a été ajouté à la balise <asp:TextBox id= »TextBox1″> pour désigner le gestionnaire de l’événement [TextChanged] sur [TextBox1]. C’est la procédure [TextBox1_Changed] que nous écrivons maintenant.
Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
‘ changement de texte
lblInfo1.text=Date.now.Tostring(« T ») + « : evt [TextChanged] sur [TextBox1]. Texte 1=[« +textbox1.Text+ »] »
End Sub
Dans la procédure, nous écrivons dans le label [lblInfo1] un message signalant l’événement et indiquant le contenu de [TextBox1]. On fait de même pour [TextBox2]. Nous indiquons également l’heure pour mieux suivre le traitement des événements. Le code final de [form4.aspx] est le suivant:
<%@ Page Language= »VB » %>
<script runat= »server »>
Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
‘ sauve la requte courante dans request.txt du dossier de la page
Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + « \request.txt » Me.Request.SaveAs(requestFileName, True)
End Sub
Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
‘ changement de texte [TextChanged] sur [TextBox1]. Texte
lblInfo1.text=Date.now.Tostring(« T ») + « : evt
1=[« +textbox1.Text+ »] »
End Sub
Sub TextBox2_TextChanged(sender As Object, e As EventArgs)
‘ changement de texte [TextChanged] sur [TextBox2]. Texte
lblInfo2.text=Date.now.Tostring(« T ») + « : evt
2=[« +textbox2.Text+ »] »
End Sub
</script>
<html>
<head>
<title>asp:textbox</title>
</head>
<body>
<form runat= »server »>
<p>
Texte 1 :
<asp:TextBox id= »TextBox1″ runat= »server » AutoPostBack= »True »
OnTextChanged= »TextBox1_TextChanged »></asp:TextBox>
</p>
<p>
Texte 2 :
<asp:TextBox id= »TextBox2″ runat= »server »
OnTextChanged= »TextBox2_TextChanged »></asp:TextBox>
</p>
<p>
<asp:Label id= »lblInfo1″ runat= »server »></asp:Label>
</p>
<p>
<asp:Label id= »lblInfo2″ runat= »server »></asp:Label>
</p>
</form>
</body>
</html>
Nous avons ajouté la procédure [Page_Init] pour mémoriser la requête du client comme dans l’exemple précédent.
Tests
Nous lançons l’application sous WebMatrix par [F5]. Nous obtenons la page suivante :
Le code HTML reçu par le navigateur est le suivant :
<html>
<head>
<title>asp:textbox</title>
</head>
<body>
<form name= »_ctl0″ method= »post » action= »form4.aspx » id= »_ctl0″> <input type= »hidden » name= »__EVENTTARGET » value= » » />
<input type= »hidden » name= »__EVENTARGUMENT » value= » » />
<input type= »hidden » name= »__VIEWSTATE » value= »dDwtMTY4MDc0MTUxOTs7PoqpeSYSCX7lCiWZvw5p7u+/OrTD » />
<script language= »javascript »>
<!–
function __doPostBack(eventTarget, eventArgument) {
var theform = document._ctl0;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// –>
</script>
<p>
Texte 1 :
<input name= »TextBox1″ type= »text » id= »TextBox1″ onchange= »__doPostBack(‘TextBox1’, ») » language= »javascript » />
</p>
<p>
Texte 2 :
<input name= »TextBox2″ type= »text » id= »TextBox2″ />
</p>
<p>
<span id= »lblInfo1″></span>
</p>
<p>
<span id= »lblInfo2″></span>
</p>
</form>
</body>
</html>
Il y a beaucoup de choses dans ce code qui ont générées automatiquement par le serveur. Notons les points suivants :
• il y a trois champs cachés : [__VIEWSTATE] que nous avons déjà rencontré, [__EventTarget] et [__EventArgument]. Ces deux derniers champs sont utilisés pour gérer l’événement navigateur « change » sur le champ de saisie [TextBox1]
• les balises serveur <asp:textbox> ont donné naissance aux balises HTML <input type= »text » …> qui correspondent aux champs de saisie
• la balise serveur <asp:textbox id= »TextBox1″ AutoPostBack= »true » …> a donné naissance à une balise <input type= »text » …> ayant un attribut [onchange= »__doPostBack(‘TextBox1’, ») »]. Cet attribut dit qu’en cas de changement du contenu de [TextBox1], la fonction Javascript [_doPostBack(…)] doit être exécutée. Celle-ci est la suivante :
<script language= »javascript »> <!–
function __doPostBack(eventTarget, eventArgument) {
var theform = document._ctl0;
theform.__EVENTTARGET.value = eventTarget;
theform.__EVENTARGUMENT.value = eventArgument;
theform.submit();
}
// –>
</script>
Que fait la fonction ci-dessus ? Elle affecte une valeur à chacun des deux champs cachés [__EventTarget] et [__EventArgument] puis poste le formulaire. Celui-ci est donc envoyé au serveur. C’est l’effet [AutoPostBack]. L’événement navigateur « change » provoque l’exécution du code « __doPostBack(‘TextBox1’, ») ». On en déduit que dans le formulaire posté, le champ caché [__EventTarget] aura la valeur ‘TextBox1’ et le champ caché [__EventArgument] la valeur ». Cela permettra au serveur de connaître le composant qui a provoqué le POST.
• la balise serveur <asp:textbox id= »TextBox2″…> a donné naissance à une balise <input type= »text » …> classique parce que son attribut [AutoPostBack] n’était pas positionné à [true].
• la balise <form> indique que le formulaire sera posté à [form4.aspx] :
<form name= »_ctl0″ method= »post » action= »form4.aspx » id= »_ctl0″>
Faisons notre premier test. Tapons un texte dans le premier champ de saisie :
puis mettons le curseur dans le second champ de saisie. Aussitôt, nous obtenons une nouvelle page :
Que s’est-il passé ? Lorsque le curseur a quitté le premier champ de saisie, le navigateur a vérifié si le contenu de celui-ci avait changé. C’était le cas. Il a donc généré, côté navigateur, l’événement [change] sur le champ HTML [TextBox1]. Nous avons vu qu’alors une fonction Javascript s’exécutait et postait le formulaire à [form4.aspx]. Cette page a donc été rechargée par le serveur. Les valeurs postées par le formulaire ont permis au serveur de savoir à son tour que le contenu de la balise serveur [TextBox1] avait changé. La procédure [TextBox1_Changed] a donc été exécutée côté serveur. Elle a placé un message dans le label [lblInfo1]. Une fois cette procédure terminée, [form4.aspx] a été envoyée au navigateur. C’est pourquoi nous avons maintenant un texte dans [lblInfo1]. Ceci dit, on peut s’étonner d’avoir quelque chose dans le champ de saisie [TextBox1]. En effet, aucune procédure exécutée côté serveur n’affecte de valeur à ce champ. On a là un mécanisme général des formulaires web ASP.NET : le serveur renvoie le formulaire dans l’état où il l’a reçu. Pour cela, il réaffecte aux composants la valeur qui a été postée pour eux par le client. Pour certains composants, le client ne poste aucune valeur. C’est le cas par exemples des composants <asp:label> qui sont traduits en balises HTML <span>. On se souvient que le formulaire a un champ caché [__VIEWSTATE] qui représente l’état du formulaire lorsqu’il est envoyé au client. Cet état est la somme des états de tous les composants du formulaire y compris les composants <asp:label> s’il y en a. Comme le champ caché [__VIEWSTATE] est posté par le navigateur client, le serveur est capable de restituer l’état précédent de tous les composants du formulaire. Il ne lui reste plus qu’à modifier ceux qui ont vu leur valeur changée par le POST.
Regardons maintenant dans [request.txt] la requête qui a été faite par le navigateur :
POST /form4.aspx HTTP/1.1
……..