1.Introduction▲
Vous êtes un développeur C#, vous travaillez avec ASP.NET et vous souhaitez pouvoir gérer l'historique de navigation et les bookmarks sur un site Ajax ?
Alors, ce tutoriel est pour vous.
À travers cet article, nous allons présenter comment utiliser le contrôle ScriptManager pour gérer un état et permettre ainsi la navigation entre points d'historiques Ajax ou simplement le bookmarking de certains états.
Tout au long de ce cours, je vais utiliser Visual C# 2008.
2.Le problème▲
2.1.L'exemple d'une navigation par menu▲
Commençons par réaliser un petit menu tout simple où nous disposons d'un lien pour afficher la page Accueil et un autre pour afficher la page Contact.
Pour ce faire, on va créer une simple page Menu.aspx avec deux LinkButton. Lors du clic sur l'un d'eux, on affiche dans un PlaceHolder le contenu correspondant au menu choisi.
<%@ Page
Language
=
"C#"
AutoEventWireup
=
"false"
CodeBehind
=
"Menu.aspx.cs"
Inherits
=
"DemoHistory.Menu"
%>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
[...un peu de code en moins pour un peu plus de lisibilité...]
<body>
<form
id
=
"form1"
runat
=
"server"
>
<ul
id
=
"menu"
>
<li>
<
asp
:
LinkButton
ID
=
"hpaccueil"
runat
=
"server"
OnClick
=
"ClickLinkButton"
Text
=
"Accueil"
/>
</li>
<li>
<
asp
:
LinkButton
ID
=
"hpcontact"
runat
=
"server"
OnClick
=
"ClickLinkButton"
Text
=
"Contact"
/>
</li>
</ul>
<
asp
:
Label
runat
=
"server"
ID
=
"labelTemoin"
/>
<
asp
:
PlaceHolder
runat
=
"server"
ID
=
"phaccueil"
Visible
=
"false"
>
<
asp
:
Label
ID
=
"Label1"
runat
=
"server"
Text
=
"Page d'accueil"
/><br />
<
asp
:
Label
runat
=
"server"
ID
=
"dateAccueil"
/>
</
asp
:
PlaceHolder>
<
asp
:
PlaceHolder
runat
=
"server"
ID
=
"phcontact"
Visible
=
"false"
>
<
asp
:
Label
ID
=
"Label2"
runat
=
"server"
Text
=
"Page de contact"
/><br />
<
asp
:
Label
runat
=
"server"
ID
=
"dateContact"
/>
</
asp
:
PlaceHolder>
</form>
</body>
Le code behind associé renseigne l'heure courante dans le Label témoin et affiche/masque les PlaceHolder en fonction de l'élément du menu cliqué.
Notez que chaque PlaceHolder affiche simplement un message signalant quel lien a été cliqué et la date d'affichage.
public
partial
class
Menu :
Page
{
protected
override
void
OnLoad
(
EventArgs e)
{
labelTemoin.
Text =
DateTime.
Now.
ToLongTimeString
(
);
base
.
OnLoad
(
e);
}
protected
void
ClickLinkButton
(
object
sender,
EventArgs e)
{
phaccueil.
Visible =
false
;
phcontact.
Visible =
false
;
dateAccueil.
Text =
DateTime.
Now.
ToLongTimeString
(
);
dateContact.
Text =
DateTime.
Now.
ToLongTimeString
(
);
if
(
sender ==
hpaccueil)
phaccueil.
Visible =
true
;
else
phcontact.
Visible =
true
;
}
}
2.2.Chargement partiel des pages▲
Superbe menu n'est-ce pas ? Sauf qu'on aimerait bien que le chargement des PlaceHolder bénéficie d'un rendu partiel.
Très simple, rajoutons le fameux UpdatePanel et son acolyte le ScriptManager.
<form
id
=
"form1"
runat
=
"server"
>
<
asp
:
ScriptManager
ID
=
"ScriptManager1"
runat
=
"server"
EnablePartialRendering
=
"true"
/>
<ul
id
=
"menu"
>
<li>
<
asp
:
LinkButton
ID
=
"hpaccueil"
runat
=
"server"
OnClick
=
"ClickLinkButton"
Text
=
"Accueil"
/>
</li>
<li>
<
asp
:
LinkButton
ID
=
"hpcontact"
runat
=
"server"
OnClick
=
"ClickLinkButton"
Text
=
"Contact"
/>
</li>
</ul>
<
asp
:
Label
runat
=
"server"
ID
=
"labelTemoin"
/>
<br />
<
asp
:
UpdatePanel
ID
=
"UpdatePanel1"
runat
=
"server"
UpdateMode
=
"Always"
>
<ContentTemplate>
<
asp
:
PlaceHolder
runat
=
"server"
ID
=
"phaccueil"
Visible
=
"false"
>
<
asp
:
Label
ID
=
"Label1"
runat
=
"server"
Text
=
"Page d'accueil"
/><br />
<
asp
:
Label
runat
=
"server"
ID
=
"dateAccueil"
/>
</
asp
:
PlaceHolder>
<
asp
:
PlaceHolder
runat
=
"server"
ID
=
"phcontact"
Visible
=
"false"
>
<
asp
:
Label
ID
=
"Label2"
runat
=
"server"
Text
=
"Page de contact"
/><br />
<
asp
:
Label
runat
=
"server"
ID
=
"dateContact"
/>
</
asp
:
PlaceHolder>
</ContentTemplate>
</
asp
:
UpdatePanel>
</form>
Aucun changement à faire dans le code behind, tout est automatiquement pris en charge par l'UpdatePanel.
Lors du clic sur un menu, on constate le rechargement partiel, comme l'indiquent les heures différentes du Label témoin et du Label du PlaceHolder.
2.3.Et le bouton « Précédent » de mon navigateur ?▲
Rajoutons une page Default.aspx à notre site comme point d'entrée de celui-ci. Cette page comportera un lien vers la page qui contient le menu, à savoir :
<%@ Page
Language
=
"C#"
AutoEventWireup
=
"false"
CodeBehind
=
"Default.aspx.cs"
Inherits
=
"DemoHistory.Default"
%>
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html
xmlns
=
"http://www.w3.org/1999/xhtml"
>
<head
runat
=
"server"
>
<title></title>
</head>
<body>
<form
id
=
"form1"
runat
=
"server"
>
<
asp
:
HyperLink
runat
=
"server"
Text
=
"Aller à la page de menu"
NavigateUrl
=
"~/Menu.aspx"
/>
</form>
</body>
</html>
Naviguons sur cette page, cliquons sur le lien. On arrive sur la page de Menu. On clique sur l'élément de menu « Accueil » qui nous affiche la page d'accueil. Puis, cliquons sur l'élément de menu « Contact » qui nous affiche la page de contact.
Sauf qu'on a cliqué trop vite, on s'est trompé. On veut revenir en arrière sur la page d'accueil. Cliquons donc en toute logique sur le bouton « Précédent » de notre navigateur préféré… Et là, c'est le drame.
On se retrouve sur la page Default.aspx, alors qu'on s'attendait à retourner sur la page d'accueil…
En effet, pour le navigateur, il n'y a que deux pages. La page Default.aspx et la page Menu.aspx alors que notre utilisation de l'UpdatePanel pourrait faire croire à l'utilisateur qu'il y en a plus.
De la même façon, si l'utilisateur bookmarque la page de menu et y revient ultérieurement, il sera impossible de savoir dans quel menu l'utilisateur était.
En effet, aucune notion d'état n'est associée à cette page.
2.4.Téléchargement▲
Vous pouvez télécharger ici les sources du projet de démo : version rar (656 Ko) , version zip (782 Ko).
3.Maintenir l'état de navigation Ajax▲
Comment faire alors pour maintenir l'état de navigation ?
C'est là qu'interviennent les points d'historiques.
3.1.Maintenir l'état du menu▲
Pour maintenir l'état, on va utiliser plusieurs choses.
Il faut tout d'abord renseigner la propriété du scriptmanager EnableHistory à true.
<
asp:
ScriptManager ID=
"ScriptManager1"
runat=
"server"
EnablePartialRendering=
"true"
EnableHistory=
"true"
/>
Ensuite, lors du clic sur le bouton, on va rajouter un point d'historique :
if
(
sender ==
hpaccueil)
{
phaccueil.
Visible =
true
;
ScriptManager1.
AddHistoryPoint
(
"Menu"
,
"Accueil"
);
}
else
{
phcontact.
Visible =
true
;
ScriptManager1.
AddHistoryPoint
(
"Menu"
,
"Contact"
);
}
Ainsi, lorsqu'on clique sur un des éléments du menu, on peut observer que l'url a changé, comme on peut le voir sur l'image ci-dessous :
L'état a été sérialisé (et crypté) et persiste ainsi dans l'url. En cliquant sur le menu Accueil, on a créé un dictionnaire où la clé « Menu » est associée à la valeur « Accueil ».
C'est à ça que nous a servi la méthode AddHistoryPoint.
De la même façon, si on clique sur le menu Contact, on va persister la clé « Menu » associée à la valeur « Contact ».
3.2.Relire l'état persisté▲
Faire persister l'état c'est bien, encore faut-il savoir le relire.
C'est ici qu'intervient l'événement OnNavigate du ScriptManager :
<
asp:
ScriptManager ID=
"ScriptManager1"
runat=
"server"
EnablePartialRendering=
"true"
EnableHistory=
"true"
OnNavigate=
"Navigate"
/>
Un événement est levé lorsqu'on doit traiter un point d'historique. Le paramètre HistoryEventArgs permet d'aller lire le dictionnaire sérialisé.
Ainsi, on pourra faire :
protected
void
Navigate
(
object
sender,
HistoryEventArgs e)
{
phaccueil.
Visible =
false
;
phcontact.
Visible =
false
;
if
(
e.
State[
"Menu"
]
==
"Accueil"
)
{
phaccueil.
Visible =
true
;
}
else
{
phcontact.
Visible =
true
;
}
}
Désormais, si vous naviguez entre les menus et que vous cliquez sur le bouton précédent de votre navigateur, le bon PlaceHolder sera affiché.
3.3.Et la date ?▲
Ceux qui ont fait l'essai se sont rendu compte que la date n'était pas mise à jour. En effet, on ne l'a pas demandé. Et pour cause, nous ne l'avons pas fait persister.
Qu'à cela ne tienne, il est possible d'ajouter plusieurs points d'historiques et ainsi, faire persister plusieurs informations. Rajoutons donc la date :
protected
void
ClickLinkButton
(
object
sender,
EventArgs e)
{
if
(
sender ==
hpaccueil)
{
Show
(
"Accueil"
,
DateTime.
Now.
ToLongTimeString
(
));
ScriptManager1.
AddHistoryPoint
(
"Menu"
,
"Accueil"
);
ScriptManager1.
AddHistoryPoint
(
"DateAccueil"
,
dateAccueil.
Text);
}
else
{
Show
(
"Contact"
,
DateTime.
Now.
ToLongTimeString
(
));
ScriptManager1.
AddHistoryPoint
(
"Menu"
,
"Contact"
);
ScriptManager1.
AddHistoryPoint
(
"DateContact"
,
dateContact.
Text);
}
}
private
void
Show
(
string
page,
string
date)
{
if
(
page ==
"Accueil"
)
{
phcontact.
Visible =
false
;
phaccueil.
Visible =
true
;
dateAccueil.
Text =
date;
}
else
{
phaccueil.
Visible =
false
;
phcontact.
Visible =
true
;
dateContact.
Text =
date;
}
}
protected
void
Navigate
(
object
sender,
HistoryEventArgs e)
{
if
(
e.
State[
"Menu"
]
==
"Accueil"
)
{
Show
(
"Accueil"
,
e.
State[
"DateAccueil"
]
);
}
else
{
Show
(
"Contact"
,
e.
State[
"DateContact"
]
);
}
}
Et le tour est joué.
3.4.Fonctionnement▲
Le clic sur les boutons précédent ou suivant du navigateur ne donne pas lieu à une requête serveur. Comment ASP.NET est-il capable de générer l'événement Navigate qui permet de restaurer notre état ?
Et bien c'est côté client que ça se passe. Le javascript généré par le contrôle ScriptManager va détecter que l'on vient d'une page en ayant cliqué sur précédent ou suivant.
Il va ensuite faire une requête serveur qui va lever cet événement et nous permettre de mettre notre code en réponse à cet événement.
3.5.Téléchargement▲
Vous pouvez télécharger ici les sources du projet de démo : version rar (656 Ko) , version zip (782 Ko).
4.Conclusion▲
Cet article montre comment utiliser les points d'historiques pour maintenir des états lors de la navigation Ajax d'un site web.
Tout ce qui a été vu ici concernant les boutons précédent ou suivant de votre navigateur est valable également lors de l'ajout aux favoris de votre navigateur. L'url qui est enregistrée contient l'état sérialisé, ainsi la page ASP.NET a la possibilité de restaurer l'état de la page.
Comme on peut le voir, la mise en place de cette persistance est très simple et apporte un confort de navigation très appréciable dans certains contextes.
N'hésitez pas à vous en servir.
Remerciements▲
Je remercie 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.