Exporter (0) Imprimer
Développer tout

Programmation d’un blog pour périphériques mobiles

Par Antoine Devaux, Johann Simon, Etudiants stagiaires Microsoft

ASP.NET 1.1, Visual Basic .NET, SQL Server
Cet article présente une programmation simple d’un blog, dédiée tout particulièrement aux périphériques mobiles, et tenant compte des paramètres de localisation linguistique des clients. Nous utiliserons les technologies Microsoft, à savoir ASP.NET, Visual Basic, XML et un serveur SQL.

Sur cette page

Introduction Introduction
Créer un nouveau projet ASP.NET Créer un nouveau projet ASP.NET
Design du blog Design du blog
Base de données Base de données
Affichage sur Smartphone Affichage sur Smartphone
Internationalisation et XML Internationalisation et XML
Conclusion Conclusion

Introduction

Nous allons créer ensemble un projet ASP.NET Visual Basic à l'aide du logiciel Microsoft Visual Studio .net 2003. Nous avons programmé en utilisant l'ASP.NET dans sa version 1.0. Le projet comportera des liaisons avec une base de données construite à l'aide de Microsoft SQL Server 2000. Nous pouvons vous faire remarquer que MSDE convient pour notre base de données mais la gestion des droits d'utilisateurs est plus délicate que sur SQL Server.

Créer un nouveau projet ASP.NET

Pour commencer, nous allons créer un nouveau projet ASP.NET Web Application de type Visual Basic. Nous changeons le nom de la page d’accueil dans l’explorateur de solution en le renommant "MonBlog.aspx".

Design du blog

Avant de commencer la programmation, voyons le design final du blog. L’interface graphique se compose d’un titre, du corps et des éléments annexes. Nous réalisons cette étape en premier afin de régler tous les problèmes d’homogénéité des noms des objets utilisés.
Pour visualiser la forme, reportez-vous aux schémas ci-dessous. L’une des difficultés est l’adaptation du design à l’écran du périphérique, c’est pourquoi, nous définissons plusieurs schémas d’affichage (périphériques mobiles ou PC).


Le titre du blog
Le titre est l’élément principal permettant de reconnaître le blog. Il sera donc présent tout le long de la navigation. Il est personnalisable par le (ou les) administrateurs du blog. Concrètement, le titre est un label dont les propriétés à changer sont l’ID ("LblTitreBlog") et le Text ("Mon Blog").

Voici le code résultant dans le designer html :

<asp:label id="LblTitreBlog" style="Z-INDEX: 101; LEFT: 344px;
POSITION: absolute; TOP: 56px" runat="server">Mon Blog</asp:label>

Le corps
Le corps de la page varie selon les requêtes des visiteurs. En effet, le visiteur peut demander un affichage de quelques articles uniquement, classés par date, ou des commentaires en relation avec un article choisi.

Nous utilisons une Table qui regroupe :
- dans la première ligne, une DataList pour afficher les notes ("DtlCorpsBlog");
- dans la deuxième, une autre DataList pour afficher les commentaires ("DtlCom");
- dans une dernière ligne, un Panel qui affichera selon la demande, le formulaire d'édition de note ou commentaire ("NoteCommentNote").

Chaque note est composée de 4 éléments : son titre, son corps, son auteur, et sa date (heure éventuellement) de diffusion. La note est programmée en tant que Table de 4 lignes et une colonne située dans le champ ItemTemplate de la DataList"DtlCorpsBlog". Chaque commentaire est composé de 3 éléments : son corps, son auteur, et sa date de publication. Le commentaire est programmé en tant que Table de 3 lignes et une colonne située dans le champ ItemTemplate de la DataList"DtlCom".
La zone d'édition de note ou commentaire ressemble à :



Le code résultant dans le designer html est :

<form id="Form1" method="post" runat="server">
<table style="Z-INDEX: 107; LEFT: 288px; WIDTH: 454px; POSITION: absolute; TOP: 96px; HEIGHT: 1070px">
<TR><TD>
<asp:datalist id=DtlCorpsBlog runat="server" RepeatLayout="Flow" ShowFooter="False"
DataKeyField="IDNote" DataMember="T_Note" DataSource="" ShowHeader="False" Height="565px" Width="446px">
<ItemTemplate>
<TABLE id="Table1" cellSpacing="1" cellPadding="1" width="100%" border="1">
<TR><TD></TD></TR>
<TR><TD></TD></TR>
<TR><TD></TD></TR>
<TR><TD></TD></TR>
</TABLE>
</ItemTemplate></asp:datalist>
</TD></TR>
<TR><TD>
<asp:datalist id=DtlCommentaires runat="server" Width="446px" DataSource=""
DataMember="T_Commentaire" DataKeyField="IDCommentaire" Height="98px">
<ItemTemplate>
<TABLE cellSpacing="1" cellPadding="1" width="100%" border="1">
<TR><TD></TD></TR>
<TR><TD></TD></TR>
<TR><TD></TD></TR>
</TABLE>
</ItemTemplate>
</asp:datalist>
</TD></TR><TR><TD>
<asp:panel id="NoteCommentBlog" runat="server" Width="446px" Height="384px">
<BR><BR><P>
<asp:Label id="LblNoteCommentBlog" runat="server" Width="238px">LblNoteCommentBlog</asp:Label>
</P><P>
<asp:Label id="LblTitreNote" runat="server" Width="246px">LblTitreNote<asp:Label>
</P><P>
<asp:TextBox id="TxtTitreNote" runat="server" Width="438px"><asp:TextBox>
</P><P>
<asp:Label id="LblCorpsNote" runat="server" Width="222px">LblCorpsNote<asp:Label>
</P><P>
<asp:TextBox id="TxtCorpsNote" runat="server" Width="438px" Height="164px" TextMode="MultiLine"
Font-Names="Arial"><asp:TextBox>
</P><P>
<asp:Label id="LblAuteurNote" runat="server">LblAuteurNote<asp:Label>
</P><P>
<asp:TextBox id="TxtAuteurNote" runat="server"><asp:TextBox>
</P><P>
<asp:Button id="BtnValidNote" runat="server" Text="BtnValidNote"><asp:Button>
</P>
</asp:panel>
</TD></TR> </table></form>

Les annexes
On peut rajouter au blog, des éléments optionnels qui enrichissent les articles comme par exemple un champ qui permet à l’administrateur de se présenter aux visiteurs, ou d’afficher une photo (non réalisé dans notre exemple).
De plus, en particulier sur Smartphone où l’affichage est réduit, on peut rajouter des liens permettant de personnaliser l’affichage ou d’atteindre un endroit particulier de la page (la tête ou le pied de page, ou la zone où se situe le calendrier, non réalisés dans notre exemple).
Le calendrier est très utile à la navigation pour permettre à l’utilisateur de choisir d’afficher les notes du jour qui l’intéresse. Cela restreint le nombre de notes et économise de la place, "vitale" pour les navigateurs mobiles.
Les visiteurs et administrateurs pourront éditer un commentaire ou une note à l'aide d'un formulaire. De même, les utilisateurs pourront s'identifier s'ils sont administrateurs.
L'ordre dans lequel nous procédons est important pour l'affichage sur périphériques mobiles. L'affichage suit l'ordre d'apparition dans le code html. Il sera aisé de changer cet ordre avec des glisser déplacer.
Nous allons donc rajouter un calendrier de forme simple nommé "CalendrierBlog".

De plus nous allons créer un Panel ("IdentificationBlog") contenant un formulaire d'identification :



Le code résultant dans le designer html est :

<form id="Form1">

[…]

<asp:panel id="IdentificationBlog" style="Z-INDEX: 103; LEFT: 792px; POSITION: absolute; 
TOP: 312px" runat="server" Height="176px" Width="176px">
<asp:Label id="LblTitreIdent" runat="server" Width="168px"
Font-Italic="True">LblTitreIdent</asp:Label>
<BR><BR>
<asp:Label id="LblLoginIdent" runat="server">LblLoginIdent</asp:Label>
<BR>
<asp:TextBox id="TxtLoginIdent" runat="server" Width="150px"></asp:TextBox><BR>
<asp:Label id="LblPwdIdent" runat="server">LblPwdIdent</asp:Label>
<BR>
<asp:TextBox id="TxtPwdIdent" runat="server" Width="120px" TextMode="Password"></asp:TextBox>
<asp:Button id="BtnValidIdent" runat="server" Text="BtnValidIdent"></Button>
</asp:panel>
</form>

Pour un accès simplifié aux dernières notes publiées et aussi afin d'optimiser notre blog sur Smartphone, nous avons créé une Datalist qui affiche les titres, auteurs et dates de chacune des 10 dernières notes publiées.
Nous avons inséré cette Datalist nommée "DtlTitres" dans la case inférieure d'un tableau à 2 cellules. L'autre cellule contient un Label nommé "LblTitres" qui nous servira à afficher le texte : "Les 10 dernières notes:"

Remarque : Pour faciliter la traduction ultérieure de notre blog il est préférable d'afficher le texte "Les 10 dernières notes:" dans un label que dans l'entête de la Datalist. Reportez-vous au chapitre Internationalisation et XML de cet article.

Dans le corps ItemTemplate de notre Datalist nous insérons une table qui contient dans sa première case le titre de la note puis dans sa seconde la date, l'heure et l'auteur de la note. Nous utilisons aussi AlternatingItemTemplate afin de programmer une mise en forme alternée sur fond gris afin de bien séparer les différents éléments de la Datalist.

Voici le code correspondant dans le designer html :

<TABLE id="Table2" style="Z-INDEX: 107; LEFT: 32px; WIDTH: 224px; POSITION: absolute; 
TOP: 96px" cellSpacing="1" cellPadding="1" width="224" border="0">
<TR><TD>
<asp:label id="LblTitres" runat="server" Font-Bold="True"></asp:label>
</TD></TR><TR><TD>
<asp:datalist id=DtlTitres runat="server" Width="216px" DataSource="<%# DsTitre1 %>"
DataMember="T_Note" DataKeyField="IDNote">
<ItemTemplate>
<table width="100%" border="0" cellspacing="0">
<TR bgcolor="Gainsboro">
<TD><asp:linkbutton Text=
'<%# Databinder.Eval(Container.DataItem,"Titre") %>' CommandName="Go" runat="server"ID="Linkbutton1" />
</td></tr>
<tr bgcolor="Gainsboro"> 
<td>
<%# Databinder.Eval(Container.DataItem,"DateHeure") %>
<%# Databinder.Eval(Container.DataItem,"Auteur") %>
</TD></TR></table> 
</ItemTemplate>
<AlternatingItemTemplate>
<table width="100%" border="0" cellspacing="0">
<TR><TD>
<asp:linkbutton Text=
'<%# Databinder.Eval(Container.DataItem,"Titre") %>' CommandName="Go" runat="server" ID="Linkbutton1" />
</td></tr><tr><td>
<%# Databinder.Eval(Container.DataItem,"DateHeure") %>
<%# Databinder.Eval(Container.DataItem,"Auteur") %>
</TD></TR></table>
</AlternatingItemTemplate>
</asp:datalist>
</TD></TR></TABLE>

Cette Datalist est très utile sur Smartphone car elle nous permet de ne pas afficher toutes les notes d'un coup ce qui serait trop long à faire défiler. Au lieu de cela, nous n'affichons au départ que les titres, auteurs et dates de publications des 10 dernières notes pour obtenir un affichage condensé. De plus le titre contient un lien qui renvoie vers la note en question suivie de ses commentaires.

Voila pour ce qui est de la présentation graphique du blog. Nous allons maintenant nous pencher sur le code qui permet de remplir les pages.

Base de données

Nous utilisons une base de données SQL Server 2000 pour stocker toutes les données relatives aux contenus des différents champs du blog. Notre serveur s'appelle "t-jsimon100" et nous avons défini un utilisateur "Blog" avec un mot de passe "Blog" pour accéder à la base de données "MonBlogMobileSQL".
Remarque : n'utilisez pas le login et le mot de passe administrateur de votre serveur pour des raisons de sécurité, donnez les droits minimums à votre utilisateur en l'enregistrant uniquement pour votre base.

Création des tables de la base
Nous créons une table ("T_Note") pour les notes publiées avec comme champs : l'"IDNote" (int autoincrémenté), le "Titre" de la note (char 50 caractères), le "Corps" de la note (char 1000 caractères, remarque : ne pas trop augmenter le nombre de caractères, car sur Smartphone, les notes ne se mettent pas à jour, c'est un problème de mémoire), l'"Auteur" de la note (char 50 caractères), la "DateHeure" de publication. Observez la capture d'écran ci-dessous :




Puis, nous créons une table ("T_Commentaire") pour les commentaires d'une note : l'"IDCommentaire" (int autoincrémenté), l'"IDNote" de la note concernée, l'"Auteur" du commentaire (char 50 caractères), le "Corps" du commentaire (char 1000 caractères), la "DateHeure" de publication. Observez la capture d'écran ci-dessous :




Enfin, nous créons une table ("T_Administrateurs") répertoriant l'ensemble des logins ("login" clé de 50 caractères) des administrateurs ainsi que leur mot de passe ("MotDePasse" 10 caractères). Observez la capture d'écran ci-dessous :




Connexion avec la base de données
Pour se connecter à une table de la base de données, il faut faire glisser le dossier Table contenant toutes les tables créées, sur le WebForm du projet. Une SqlConnection et autant de SqlDataAdapter que de tables (ici 3) se créent automatiquement.
Nous allons changer la ConnectionString de la SqlConnection en cliquant sur nouveau. On peut y changer les paramètres de connexion : le serveur ("t-jsimon100"), le login ("Blog"), le mot de passe ("Blog"). Une fois cette étape réalisée, il faut enlever : "workstation id" et sa valeur, par défaut c'est le nom de votre ordinateur, ce n'est donc pas à indiquer dans la ConnectionString. Voici ce que ça donne :

packet size=4096;user id=Blog;data source="t-jsimon100";
persist security info=True;initial catalog=MonBlogMobileSQL;password=Blog

Nous allons renommer la SqlConnection et les SqlDataAdapter pour s'y retrouver plus tard (il est nécessaire de connaître la table en cours pour chacun des adaptateurs en cliquant sur preview data).
Nous obtenons alors "SqlConnectionBlog", "AdapterNote", "AdapterCommentaire", "AdapterAdministrateur".

Premier remplissage de l'ensemble des notes
Ensuite, nous créons le premier DataSet qui permettra de remplir la liste des notes. On peut le faire en cliquant sur l'adaptateur concerné ("AdaptaterNote") et on génère un nouveau DataSet que l'on nomme "DSNote".
Nous lions donc la DataList "DtlCorpsBlog" en sélectionnant en premier sa DataSource (choisir "DSNote1"), son DataMember (choisir "T_Note") et son DataKeyField (choisir "IDNote").

Ces quelques lignes de code permettent le remplissage du DataSet, il n'est nécessaire de le remplir qu'une seule fois, au chargement de la page, en raison des nombreux rafraîchissements provoqués par les différentes requêtes que nous serons amenés à effectuer (nous rafraîchirons après avoir exécuté chacune des commandes Sql, reportez-vous aux chapitres suivants). C'est pourquoi nous plaçons l'appel de la fonction "RemplirDataList" dans la boucle s'exécutant lorsque la page n'est pas rafraîchie :

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

If Page.IsPostBack = False Then

'Fonction qui remplit la liste des notes au démarrage
RemplirDataList()

End If

End Sub

'Fonction qui remplit la liste des notes
Private Sub RemplirDataList()

AdapterNote.Fill(DsNote1)
DtlCorpsBlog.DataBind()

End Sub

Reste à remplir la Table de l'ItemTemplate. Il faut inscrire ces quelques lignes de code dans le designer html, dans chaque ligne de la Table affichant les notes :

Pour le champ titre :

<%# DataBinder.Eval(Containers.DataItem,"Titre") %>

Pour le champ corps :

<%# DataBinder.Eval(Containers.DataItem,"Corps") %>

Pour le champ auteur:

<%# DataBinder.Eval(Containers.DataItem,"Auteur") %>

Pour le champ date de publication :

<%# DataBinder.Eval(Containers.DataItem,"DateHeure") %>

Recherche d'informations sur les 10 dernières notes postées
Pour remplir la Datalist "DtlTitres" qui sert à l'affichage des informations (titre, auteur, date) nous utilisons une requête qui extrait de la base de données les 10 dernières notes publiées.

Voici le code de la requête en question:

'Fonction qui récupère les 10 dernières notes
Private Sub DernieresNotes()
'Les 10 dernières notes
Me.SqlConnectionBlog.Open()
Me.AdapterNote.SelectCommand.CommandText = "SELECT Top 10 DateHeure, IDNote, Titre, Corps, Auteur
FROM T_Note ORDER by DateHeure DESC"
Me.AdapterNote.SelectCommand.ExecuteNonQuery()
Me.SqlConnectionBlog.Close()
AdaptaterNote.Fill(DsTitre1)
DtlTitres.DataBind()
End Sub

Il faut noter l'utilisation de la fonction SQL Server "Top 10" qui permet de récupérer seulement les 10 dernières notes.

De plus, Datalist "DtlTitres" contient des liens vers les notes qu'elle répertorie. Pour accéder à ces notes, nous utilisons la fonction "SelectNote(x)" nécessitant un paramètre (l'ID de la note sélectionnée) que nous traiterons ultérieurement (reportez-vous au chapitre "Affichage des commentaires et de la note choisie").

Code associé à notre Datalist "DtlTitres":

'Fonction qui affiche la note avec ses commentaires
Private Sub DtlTitres_ItemCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DtlTitres.ItemCommand

'Sélectionne la note avec ses commentaires
SelectNote(DtlTitres.DataKeys(e.Item.ItemIndex))

End Sub

Dans la Datalist, nous définissons:
- la source : DataSource="DsTitre1"
- la table : DataMember="T_Note"
- la clé : DataKeyField="IDNote"

A l'aide de l'objet "e" créé automatiquement dans la fonction "DtlTitres_ItemCommand" nous pouvons extraire l'ID de la note sélectionnée : "DtlTitres.DataKeys(e.Item.ItemIndex)" est utilisé dans ce but.

Identification des administrateurs
Afin que les administrateurs puissent écrire et publier une nouvelle note, il est nécessaire de les identifier. Nous allons donc permettre cette identification au moyen d'un formulaire et de la base de données. Les visiteurs non identifiés ne peuvent pas publier des notes, donc on n'affiche pas le formulaire d'édition de note pour ces utilisateurs.
Nous utilisons ce moyen simple d'identification en raison de la faible nécessité de sécurité. Le blog est totalement contrôlé par un des administrateurs qui a accès à la base de données.

L'idée est de créer une variable de session qui aura comme valeur le login d'un administrateur, rendant possible quelques actions réservées. De plus, le fait que cette variable possède une durée de vie limitée est intéressante du point de vue sécurité d'utilisation sur une machine à accès publique.

La variable de session est créée côté serveur et se désactive lors d'une période (20 minutes par défaut) d'inactivité du client. On peut régler cette valeur en minutes par Session.Timeout. Nous appellerons cette variable "Admin" qui vaut l'un des logins des administrateurs ou Nothing.

Attention à "l'injection SQL"
Lors de la validation du formulaire d'identification, une requête SQL détermine si le login et le mot de passe sont corrects. Pour indication le Label "Erreur" affiche la réussite ou l'échec de l'identification.
Le code suivant traite ce point en réalisant une commande SQL par concaténation des champs "login" et "mot de passe". Ce code n'est pas sécurisé, nous ne sommes pas à l'abri d'une commande SQL néfaste par intrusion.

'Fonction qui permet à l'administrateur de s'identifier auprès du blog
Private Sub BtnValidIdent_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles BtnValidIdent.Click
Dim login As String
Dim MotDePasse As String
login = TxtLoginIdent.Text
MotDePasse = TxtPwdIdent.Text

'Connexion à la base de données
SqlConnectionBlog.Open()
AdapterAdministrateur.SelectCommand.CommandText = "SELECT dbo.T_Administrateurs.*
FROM dbo.T_Administrateurs WHERE (Login = '" & login & "') AND (MotDePasse = '" & MotDePasse & "')"
AdapterAdministrateur.SelectCommand.ExecuteNonQuery()
Dim DSAdmin As New DataSet
AdapterAdministrateur.Fill(DSAdmin)
'On cherche la valeur du login trouvé
Dim Admin As String
Try
Admin = DSAdmin.Tables.Item(0).Rows(0).Item(0)
'On crée une variable de session valant le login de l'administrateur
Session("Admin") = Admin
TxtAuteurNote.Text = Admin
'on confirme l'identification
Erreur.Text = "réussite de l'identification"
NoteCommentBlog.Visible = True
Catch ex As Exception
'On vient ici si il n'y a pas de réponse à la requête SQL
Erreur.Text = "échec de l'identification"
Session("Admin") = Nothing
TxtAuteurNote.Text = ""
NoteCommentBlog.Visible = False
End Try
SqlConnectionBlog.Close()
End Sub

Remarque : il est possible que votre requête attende déjà des paramètres créés automatiquement par Visual Studio. Si c'est le cas, passez les lignes de déclarations de paramètres en commentaire.

Remède contre "l'injection SQL"
Pour éviter les injections SQL, nous allons utiliser des paramètres qui indiqueront au serveur de ne pas interpréter les valeurs entrantes. Voici le même code que précédemment mais les requêtes SQL sont sécurisées.

'Fonction qui permet à l'administrateur de s'identifier auprès du blog
Private Sub BtnValidIdent_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles BtnValidIdent.Click

Dim Login As String
Dim MotDePasse As String
Login = TxtLoginIdent.Text
MotDePasse = TxtPwdIdent.Text

'parade injection
AdapterAdministrateur.SelectCommand.CommandText = "SELECT dbo.T_Administrateurs.*
FROM dbo.T_Administrateurs WHERE (Login = @ParamLogin) AND (MotDePasse = @ParamMotdePasse)"
AdapterAdministrateur.SelectCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamLogin", System.Data.SqlDbType.VarChar, 50, "Login"))
AdapterAdministrateur.SelectCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamMotdePasse", System.Data.SqlDbType.VarChar, 10, "MotDePasse"))
AdapterAdministrateur.SelectCommand.Parameters
("@ParamLogin").Value = Login
AdapterAdministrateur.SelectCommand.Parameters
("@ParamMotdePasse").Value = MotDePasse

'Connexion à la base de données
SqlConnectionBlog.Open()
AdapterAdministrateur.SelectCommand.ExecuteNonQuery()
SqlConnectionBlog.Close()

Dim DSAdmin As New DataSet
AdapterAdministrateur.Fill(DSAdmin)
'On cherche la valeur du login trouvé

Dim Admin As String

Try
Admin = DSAdmin.Tables.Item(0).Rows(0).Item(0)

'On crée une variable de session valant le login de l'administrateur
Session("Admin") = Admin
TxtAuteurNote.Text = Admin

'On confirme l'identification
Erreur.Text = "Réussite de l'identification"
NoteCommentBlog.Visible = True

Catch ex As Exception

'On vient ici si il n'y a pas de réponse à la requête SQL
Erreur.Text = "échec de l'identification"
Session("Admin") = Nothing
TxtAuteurNote.Text = ""
NoteCommentBlog.Visible = False
End Try
End Sub

Dorénavant nous appliquerons cette méthode pour les requêtes qui contiennent des valeurs de champs remplis par l'utilisateur.

Fin de session administrateur
Une fois l'administrateur reconnu, il peut se déloguer quand il le souhaite lorsqu'il a fini ses opérations.
Nous allons donc modifier le comportement du bouton de validation de l'identité de l'administrateur :

'Fonction qui permet à l'administrateur de s'identifier auprès du blog
Private Sub BtnValidIdent_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles BtnValidIdent.Click

'on teste d'abord si une session est ouverte à un login existant
If Session("Admin") = Nothing Then 'session non ouverte

'la session est ouverte, on peut déloguer
BtnValidIdent.Text = "Log Out"

Else 'session déjà ouverte, on peut la fermer si l'utilisateur le désire

Session("Admin") = Nothing
BtnValidIdent.Text = "Ok"
TxtAuteurNote.Text = Nothing

'si on était sur la page principale lors du log out on efface la zone d'édition, sinon on peut la laisser
If Session("Note") = Nothing Then

NoteCommentBlog.Visible = False

End If
End If
End Sub

L'administrateur peut désormais se loguer et se déloguer comme il le souhaite.

Edition d'une note (réservé aux administrateurs du blog)
Si un administrateur a été correctement identifié, il a s'il le souhaite la possibilité de remplir le formulaire d'édition de note. Le code n'est donc qu'une commande SQL qui ajoute une note :
- connexion à la base
- écriture de la commande
- exécution
- remplissage du DataSet
- déconnexion
- nettoyage des champs utilizes

'Fonction qui ajoute une note
Private Sub BtnValidNote_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles BtnValidNote.Click

If Session("Admin") <> Nothing Then
AdapterNote.InsertCommand.CommandText = "INSERT INTO dbo.T_Note(Titre, Corps, Auteur, DateHeure)
VALUES (@ParamTitre,@ParamCorps,@ParamAuteur,getdate())"
AdapterNote.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamTitre", System.Data.SqlDbType.VarChar, 50, "Titre"))
AdapterNote.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamCorps", System.Data.SqlDbType.VarChar, 1000, "Corps"))
AdapterNote.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamAuteur", System.Data.SqlDbType.VarChar, 50, "Auteur"))
AdapterNote.InsertCommand.Parameters("@ParamTitre").Value = TxtTitreNote.Text
AdapterNote.InsertCommand.Parameters("@ParamCorps").Value = TxtCorpsNote.Text
AdapterNote.InsertCommand.Parameters("@ParamAuteur").Value = TxtAuteurNote.Text
SqlConnectionBlog.Open()
AdapterNote.InsertCommand.ExecuteNonQuery()
RemplirDataList()
SqlConnectionBlog.Close()
TxtCorpsNote.Text = ""
TxtTitreNote.Text = ""
Else
'La variable de session est périmée (lorque l'administrateur a oublié de se déloguer)
Erreur.Text = "Session terminée, identification requise"
NoteCommentBlog.Visible = False
End If
End Sub

Edition d'un commentaire (pour les administrateurs ou non)
Plusieurs parties du code sont à modifier pour permettre l'édition d'un commentaire. En effet, nous avons fixé que les non administrateurs n'avaient pas accès au formulaire d'édition. Il faut donc permettre aux utilisateurs d'y avoir accès lorsqu'ils demandent à voir les commentaires d'une note précise, où ils pourront ajouter leur commentaire à la note choisie.

Premièrement, nous ajoutons une ligne pour chaque note. Le code à insérer dans le designer html est très simple, il se situe après la dernière ligne du tableau de l'ItemTemplate du DataList "DtlCorpsBlog" :

<TR><TD>
<asp:LinkButtonid="LienCommentaires" CommandName="VoirCommentaires"
runat="server">LinkButton</asp:LinkButton>
</TD></TR>

Le texte affiché fera l'objet d'une traduction. Nous laissons pour l'instant "LinkButton" (reportez-vous au chapitre Internationalisation et XML).

Nous allons maintenant procéder à l'affichage de la zone d'édition de message en utilisant celle déjà réalisée pour l'édition des notes. Quelques modifications sont nécessaires :
- pas de titre pour les commentaries
- tout visiteur peut accéder à l'édition

Lorsque l'utilisateur clique sur le lien défini ci-dessus, nous utilisons la variable de session "Note" valant l'"IDNote" de la note choisie :

'Fonction qui récupère la clé de la note où l'utilisateur a cliqué
Private Sub DtlCorpsBlog_ItemCommand(ByVal source As Object,
ByVal e As System.Web.UI.WebControls.DataListCommandEventArgs) Handles DtlCorpsBlog.ItemCommand

Session("Note") = DtlCorpsBlog.DataKeys(e.Item.ItemIndex)
NoteCommentBlog.Visible = True
'On n'a pas besoin de remplir le champ titre car c'est le titre de la note qui est déjà fixé
LblTitreNote.Visible = False
TxtTitreNote.Visible = False

End Sub

La fonction qui gère l'affichage de la zone d'édition se programme ainsi, une partie a déjà été réalisée :

'Fonction qui ajoute une note ou un commentaire suivant les droits
Private Sub BtnValidNote_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles BtnValidNote.Click

If Session("Note") = Nothing Then
'Aucune note n'a été choisie, seul l'administrateur peut publier une nouvelle note
NoteCommentBlog.Visible = True

Else 'Une note été choisie (la clé est contenue dans la variable de session)
'On affiche la Panel d'édition
NoteCommentBlog.Visible = True
AdapterCommentaire.InsertCommand.CommandText = "INSERT INTO T_Commentaire(IDNote, Auteur,
Corps, DateHeure)VALUES (@ParamIDNote,@ParamAuteur,@ParamCorps,getdate())"
AdapterCommentaire.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamIDNote", System.Data.SqlDbType.Int, 4, "IDNote"))
AdapterCommentaire.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamCorps", System.Data.SqlDbType.VarChar, 1000, "Corps"))
AdapterCommentaire.InsertCommand.Parameters.Add(New System.Data.SqlClient.SqlParameter
("@ParamAuteur", System.Data.SqlDbType.VarChar, 50, "Auteur"))
AdapterCommentaire.InsertCommand.Parameters("@ParamIDNote").Value = Session("Note")
AdapterCommentaire.InsertCommand.Parameters("@ParamCorps").Value = TxtCorpsNote.Text
AdapterCommentaire.InsertCommand.Parameters("@ParamAuteur").Value = TxtAuteurNote.Text
SqlConnectionBlog.Open()
AdapterCommentaire.InsertCommand.ExecuteNonQuery()
SqlConnectionBlog.Close()
TxtCorpsNote.Text = ""
TxtTitreNote.Text = ""
'on efface l'auteur si il n'est pas administrateur
If Session("Admin") = Nothing Then
TxtAuteurNote.Text = ""
End If
SelectNote(Session("Note"))
End If
'Actualise les 10 dernières notes
DernieresNotes()
Traduction()
End Sub

Affichage des commentaires et de la note choisie
Lorsque l'utilisateur clique sur le lien permettant d'accéder à la zone d'édition de commentaires, il est intéressant que sur la page s'affichent :
la note concernée par le futur commentaire
les commentaires précédents traitant de la note choisie

La fonction "SelectNote(x)" sert à afficher la note dont l'ID est égal à "x" ainsi que tous les commentaires qui lui sont associé. Pour retrouver l'ID d'une note vous pouvez vous référer au paragraphe nommé "Recherche d'informations sur les 10 dernières notes postées".

Voici les détails de la fonction :

'Fonction qui selectionne la note avec ses commentaires
Private Sub SelectNote(ByVal id As Integer)

SqlConnectionBlog.Open()

AdapterNote.SelectCommand.CommandText = "SELECT IDNote, Titre, Corps, Auteur, DateHeure
FROM T_Note
WHERE IDNote=" & id & " ORDER BY DateHeure DESC"
AdapterNote.SelectCommand.ExecuteNonQuery()
AdapterNote.Fill(DsNote1)
DtlCorpsBlog.DataBind()

AdapterCommentaire.SelectCommand.CommandText = "SELECT IDCommentaire, IDNote,
Auteur, Corps, DateHeure FROM T_Commentaire WHERE IDNote=" & id & ""
AdapterCommentaire.SelectCommand.ExecuteNonQuery()
AdapterCommentaire.Fill(DsCommentaire1)
DtlCommentaires.DataBind()

SqlConnectionBlog.Close()

End Sub

Cette fonction est basée sur deux requêtes: la première sélectionne la note dont l'ID est égal au paramètre passé à l'appel de la fonction, la deuxième sélectionne tous les commentaires dont la caractéristique "IDNote" est égale au paramètre passé à l'appel de la fonction. Ensuite, les Datasets et les Datalists correspondants sont remplis.

Retour à l'affichage des notes
Lorsque l'utilisateur a fini sa lecture de note avec ses commentaires, un bouton permet de revenir à l'accueil du blog où l'affichage est restreint aux notes sans leurs commentaires.
Concrètement, dans la Table de gauche, en plus de la liste des notes, nous ajoutons une ligne où nous affichons un LinkButton "LBRetour".

Le code à rajouter dans le designer html se présente ainsi :

<TR><TD>
<asp:LinkButton id="LBRetour" runat="server">LinkButton</asp:LinkButton>
</TD></TR>

Et le code à insérer :

'Fonction qui permet de revenir des commentaires aux notes
Private Sub LBRetour_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles LBRetour.Click

'On annule l'édition de commentaires
Session("Note") = Nothing
TxtTitreNote.Visible = True
LblTitreNote.Visible = True

'si l'utilisateur n'est pas administrateur, on l'empêche de voir l'éditeur de notes
If Session("Admin") = Nothing Then

NoteCommentBlog.Visible = False

End If

End Sub

Affichage des notes en fonction du choix sur le calendrier
Le choix d'une date sur le calendrier permet de montrer toutes les notes publiées à cette date. Le problème essentiel est la requête SQL qui doit contenir la date choisie dans le format de la culture du serveur. Pour cela nous déclarons "CI" qui représente la culture du serveur, "DTFI" qui représente le format de date utilisé par le serveur. Ainsi, nous pouvons convertir la date dans le format de date du serveur :

'Fonction qui affiche les notes de la date choisie
Private Sub CalendrierBlog_SelectionChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles CalendrierBlog.SelectionChanged

Dim choix As Date
choix = CalendrierBlog.SelectedDate


Dim CI As CultureInfo
CI = CultureInfo.CurrentUICulture

Dim DTFI As DateTimeFormatInfo
DTFI = CI.DateTimeFormat


Dim jour As String
jour = choix.ToString("G", DTFI)

'on affiche les notes de la date choisie
SqlConnectionBlog.Open()
AdaptaterNote.SelectCommand.CommandText = "SELECT IDNote, Titre, Corps, Auteur,
DateHeure FROM dbo.T_Note WHERE DateHeure>= '" & jour & "' AND DateHeure<=DATEADD(day,1,'" & jour & "')
ORDER BY DateHeure DESC"
AdaptaterNote.SelectCommand.ExecuteNonQuery()
RemplirDataList()
SqlConnectionBlog.Close()
End Sub

Observez la manipulation de la date choisie, valable dans tous les formats de culture du calendrier.

Affichage sur Smartphone

En raison de la faible capacité du Smartphone à afficher beaucoup de données, il est nécessaire d'agir en conséquence et de limiter l'affichage. C'est pourquoi, nous n'afficherons pas sur Smartphone l'ensemble des notes représentées dans la DataList "DtlCorpsBlog" mais l'utilisateur choisira parmi les dernières notes ou utilisera le calendrier pour visionner la note qui l'intéresse.

Détection du périphérique
Lors du premier affichage du blog, le code détecte si le client est un Smartphone et utilise une variable de session pour garder le résultat de ce test en mémoire. Le code à insérer dans le PageLoad est :

'Fonction qui analyse le type de périphérique
IsSmartphone()

Ce code appelle la sous-fonction qui teste le client :

'Fonction qui détermine si le client est un Smartphone
Private Sub IsSmartphone()
If Not InStr(Request.UserAgent, "Smartphone") = 0 Then
Session("Smartphone") = "Smartphone"
Else
Session("Smartphone") = Nothing
End If
End Sub

Restrictions d'affichage
Nous allons donc modifier le code pour restreindre l'affichage sur Smartphone. Cela concerne en premier lieu, l'affichage de la DataList des notes. Dans le IsPostBack=False du PageLoad, on insère la boucle If :

Private Sub LBRetour_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles LBRetour.Click

Internationalisation et XML

Cette partie vous permettra de réaliser le site web en plusieurs langages. Pour cela nous programmerons dans des fichiers XML les différentes traductions possibles.

Objectif de l’internationalisation
L’internationalisation permet l’affichage de notre site en plusieurs langues facilitant ainsi sa lecture. Nous programmerons donc un fichier XML par langue. Pour commencer, nous nous occuperons seulement du français et de l’anglais. De plus il faudra configurer certains paramètres afin que l’affichage soit optimal (date, heure, calendrier…)

Fichiers XML de traduction
Le code des fichiers XML est organisé et hiérarchisé par des balises. Ces dernières sont choisies par l’utilisateur afin de faciliter la lecture et de retrouver rapidement les éléments dont il a besoin.

Exemple de fichier XML de traduction:
Voici l’arborescence que nous utiliserons dans nos fichiers XML : TEXTES > NomDeLaLangue > NomDeLaZoneDeTexte
Fichier fr.xml dans le répertoire /XML du projet:

<?xml version="1.0" encoding="utf-8" ?> 
<TEXTES>
<FR>
<LblTitreIdent>Login et Mot de passe</LblTitreIdent>
<LblLoginIdent>Login</LblLoginIdent>
<LblPwdIdent>Mot de passe</LblPwdIdent>
<BtnValidIdent>Ok</BtnValidIdent>
<LblNoteCommentBlog>Tapez votre message</LblNoteCommentBlog>
<LblTitreNote>Titre</LblTitreNote>
<LblCorpsNote>Message</LblCorpsNote>
<LblAuteurNote>Auteur</LblAuteurNote>
<BtnValidNote>Envoyer</BtnValidNote>
</FR>
</TEXTES>

Entre chacune des balises <NomDeLaZoneDeTexte> et </NomDeLaZoneDeTexte> il faut insérer le texte traduit dans la langue souhaitée. Il est possible d’associer plusieurs traductions à un même contrôle mais il faudra penser à modifier les textes au bon moment.
Dans notre page "MonBlog.aspx", on va donc créer le code qui nous permettra d’ouvrir le fichier XML adapté. Pour cela on ajoute une Dropdownlist qui nous servira à modifier le langage de la page.
Voici le code HTML associé à cette Dropdownlist que nous avons nommé "ListeLangues"

<asp:dropdownlist id="ListeLangues" runat="server" AutoPostBack="True">
<asp:ListItem Value="fr-FR">FR</asp:ListItem>
<asp:ListItem Value="en-US">EN</asp:ListItem>
<asp:ListItem Value="de-DE">DE</asp:ListItem>
</asp:dropdownlist>

On a donc programmé 3 choix, FR, EN et DE pour Français, Anglais, Allemand. L'option AutoPostBack="True" n'est pas indispensable mais cela évite d'avoir a rajouter un bouton de validation.

On ajoute ensuite :
- sept Labels (LblTitreIdent, LblLoginIdent, LblPwdIdent, LblNoteCommentBlog, LblTitreNote, LblCorpsNote, LblAuteurNote)
- deux Buttons (BtnValidIdent, BtnValidNote)

La page est donc prête du point de vue design. Il nous reste donc à modifier le code dans la page "MonBlog.aspx.vb" pour commander l'ouverture du fichier XML.

Ouverture d'un fichier XML
L'ouverture du fichier XML est relativement simple, elle consiste à charger le document puis à se promener dans la hiérarchie des balises précédemment définies.

Voici un exemple de code:

'Déclaration de doc comme document XML
Dim doc As New System.Xml.XmlDocument

'Ouverture du fichier français
doc.Load(Server.MapPath("XML\fr.xml"))

'Accès à la racine du fichier <TEXTES>
Dim mNodeRoot As System.Xml.XmlNode
mNodeRoot = doc.DocumentElement

'Accès à l'enfant c'est-à-dire <FR>
Dim mNodeChild As System.Xml.XmlNode
mNodeChild = mNodeRoot.FirstChild()

'Accès aux différents textes de la page
LblTitreIdent.Text = mNodeChild("LblTitreIdent").InnerText
LblLoginIdent.Text = mNodeChild("LblLoginIdent").InnerText
LblPwdIdent.Text = mNodeChild("LblPwdIdent").InnerText
BtnValidIdent.Text = mNodeChild("BtnValidIdent").InnerText
LblNoteCommentBlog.Text = mNodeChild("LblNoteCommentBlog").InnerText
LblTitreNote.Text = mNodeChild("LblTitreNote").InnerText
LblCorpsNote.Text = mNodeChild("LblCorpsNote").InnerText
LblAuteurNote.Text = mNodeChild("LblAuteurNote").InnerText
BtnValidNote.Text = mNodeChild("BtnValidNote").InnerText

Il faut savoir que la propriété FirstChild() accède à la première balise enfant du dossier où l'on se trouve. De plus, mNodeChild("LblPwdIdent").InnerText Va rechercher dans les enfants de "mNodeChild" l'enfant qui s'appelle "LblPwdIdent" puis en extrait son texte.

Nous venons donc de réaliser une page en français sans avoir eu à définir les textes dans le code HTML. Il est aussi possible de traduire la page en anglais en modifiant un peu le code:

doc.Load(Server.MapPath("XML\en.xml"))

Fichier en.xml dans le répertoire /XML du projet:

<?xml version="1.0" encoding="utf-8" ?> 
<TEXTES>
<US>
<LblTitreIdent>Login and Password</LblTitreIdent>
<LblLoginIdent>Login</LblLoginIdent>
<LblPwdIdent>Password</LblPwdIdent>
<BtnValidIdent>Ok</BtnValidIdent>
<LblNoteCommentBlog>Enter your message</LblNoteCommentBlog>
<LblTitreNote>Title</LblTitreNote>
<LblCorpsNote>Message</LblCorpsNote>
<LblAuteurNote>Author</LblAuteurNote>
<BtnValidNote>Send</BtnValidNote>
</US>
</TEXTES>

La page se chargera alors en anglais.

Pour alléger cela nous allons donc utiliser la Dropdownlist "ListeLangues" créée précédemment.

Choix de la langue
Pour faciliter le changement de langue en cours d'utilisation, il suffit de modifier le nom du fichier à charger à l'aide du résultat renvoyé par la Dropdownlist lorsque celle-ci est modifiée.

Voici le code permettant l'ouverture:

doc.Load(Server.MapPath("XML\" & Left(ListeLangues.SelectedValue.
ToString(), 2) & ".xml"))

Cette ligne de commande extrait les deux premiers caractères du texte correspondant à la langue sélectionnée dans la liste puis les utilise afin de recomposer le nom du fichier. Il est donc normal que le choix "DE" provoque une erreur puisque le fichier de.xml n'existe pas.

Nous allons donc effectuer quelques tests afin de gérer les erreurs.

Gestion des erreurs de lecture de fichiers XML
Dans cette partie nous traiterons donc les deux erreurs les plus courantes afin de les traiter au mieux pour ne pas perturber le fonctionnement du blog. Ces deux erreurs sont :" Impossible de trouver le fichier " et " La référence d'objet n'est pas définie à une instance d'un objet".

Voici notre code complet du traitement d'ouverture du fichier XML, il faut penser à créer un nouveau Label nommé "Erreur":

'Ouverture le fichier XML du langage approprié
Dim doc As New System.Xml.XmlDocument
'Ouverture du fichier dans la langue de l'utilisateur
Try
doc.Load(Server.MapPath("XML\" &
Left(ListeLangues.SelectedValue._ ToString(), 2) & ".xml"))
Catch ex1 As Exception
'Sinon ouverture du fichier anglais
Try
doc.Load(Server.MapPath("XML\en.xml"))
Catch ex2 As Exception
Erreur.Text = ex2.Message '"XML not found!"
End Try
Erreur.Text = ex1.Message '"Language not found!"
End Try

'Recherche des textes à traduire
Try
'Accès à la racine du fichier
Dim mNodeRoot As System.Xml.XmlNode
mNodeRoot = doc.DocumentElement

'Accès à l'enfant
Dim mNodeChild As System.Xml.XmlNode
mNodeChild = mNodeRoot.FirstChild()

'Accès aux différents textes de la page
LblTitreIdent.Text = mNodeChild("LblTitreIdent").InnerText
LblLoginIdent.Text = mNodeChild("LblLoginIdent").InnerText
LblPwdIdent.Text = mNodeChild("LblPwdIdent").InnerText
BtnValidIdent.Text = mNodeChild("BtnValidIdent").InnerText
LblNoteCommentBlog.Text = mNodeChild("LblNoteCommentBlog").InnerText
LblTitreNote.Text = mNodeChild("LblTitreNote").InnerText
LblCorpsNote.Text = mNodeChild("LblCorpsNote").InnerText
LblAuteurNote.Text = mNodeChild("LblAuteurNote").InnerText
BtnValidNote.Text = mNodeChild("BtnValidNote").InnerText
 
Catch ex1 As Exception
Erreur.Text = Erreur.Text & ex1.Message '" XML Error!"
End Try

Ce code permet la gestion d'un fichier introuvable, charge l'anglais par défaut en cas d'erreur et renvoie un texte d'erreur en cas de problème.

Impossible de trouver le fichier
Nous utilisons donc la fonction "Try, Catch, End Try" pour tester si les fichiers sont bien présents sur le server. Le premier test sert à ouvrir le fichier correspondant au choix de la Dropdownlist"ListeLangues". Si ce dernier ne peut être trouvé alors nous affichons un message d'erreur: vous pouvez en créer un ou utiliser la propriété du type Exception qui se nomme Message ce qui nous donne:

Catch ex2 As Exception
Erreur.Text = ex2.Message '"XML not found!"

Sinon nous essayons d'ouvrir le fichier anglais par défaut:

Try
doc.Load(Server.MapPath("XML\en.xml"))
Catch ex2 As Exception
Erreur.Text = ex2.Message '"XML not found!"
End Try

Si ce fichier ne peut être trouvé alors, nous affichons un message d'erreur dans le Label "Erreur". Une fois ces tests accomplis, nous vérifions alors la possibilité de lecture du fichier.

La référence d'objet n'est pas définie à une instance d'un objet
L'erreur "la référence d'objet n'est pas définie à une instance d'un objet" est souvent due à un problème de balise dans le fichier XML. En effet, si le nom appelé par " mNodeChild ("NomDeBalise")" est introuvable, le server renvoie ce type de message d'erreur. Nous devons donc effectuer le test suivant:

Try
'Accès à la racine du fichier
Dim mNodeRoot As System.Xml.XmlNode
mNodeRoot = doc.DocumentElement

'Accès à l'enfant
Dim mNodeChild As System.Xml.XmlNode
mNodeChild = mNodeRoot.FirstChild()

'Accès aux différents textes de la page
LblTitreIdent.Text = mNodeChild("LblTitreIdent").InnerText

Catch ex1 As Exception
Erreur.Text = Erreur.Text & ex1.Message '" XML Error!"
End Try

Tous ces tests facilitent la compréhension des erreurs rencontrées lors de l'exécution du code et permettent aussi de les identifier plus facilement.

Traductions dans des contrôles du type Datalist ou Datagrid
Les paragraphes précédents permettent la traduction de textes de vos différents contrôles mais il arrive que nous ayons besoin de traduire des textes de contrôles eux-mêmes inclus dans des contrôles: par exemple un bouton qui se répète pour chaque élément d'une Datalist ou d'un Datagrid.
Pour illustrer ce problème nous créons une Datalist nommée "DtlCorpsBlog" qui contient un LinkButton afin de nous renvoyer les commentaires associés à l'article sélectionné dans notre blog. Pour créer cette Datalist vous pouvez vous référez au paragraphe Design du blog et Connexion avec la base de données.

Il suffit alors d'insérer le code suivant à la suite des traductions:

'Traduction des liens dans la datalist
Dim i As Integer = 0
For i = 0 To DtlCorpsBlog.Items.Count() - 1
CType(DtlCorpsBlog.Items(i).FindControl("LienCommentaires"),-LinkButton)
Text = mNodeChild("LienCommentaires").InnerText
Next i

Ce code sert à rechercher dans un contrôle un autre contrôle. Ici, nous recherchons dans "DtlCorpsBlog" le contrôle "LienCommentaires" que nous convertissons en un contrôle de type LinkButton: CType(…, LinkButton). Cette opération nous permet d'accéder aux propriétés classiques d'un contrôle de ce type. Nous pouvons donc utiliser sa propriété Text afin de la modifier.
Le problème réside dans le fait que DtlCorpsBlog.Items(i) correspond à l'affichage n°i dans la Datalist, c'est-à-dire au premier élément renvoyé par la requête effectuée. Donc il faut remplacer le texte dans chacun de ces Items et c'est pour cela que nous utilisons une boucle For. La limite supérieure de cette boucle étant définie par la nombre d'Items obtenu à l'aide de DtlCorpsBlog.Items.Count().

Remarque: Il faut penser à exécuter la fonction "Traduction()" après avoir rempli la Datalist. Sinon les Items de la Datalist n'existent pas encore et Items.Count() renvoie la valeur 0.

Grâce à ces fonctions nous avons réussi à traduire tous nos textes personnalisés de la page. Il ne nous reste plus qu'à adapter certains affichages tels que le format des dates ou le calendrier.

Culture: formats des dates et ducalendrier
Afin de faciliter la lecture de notre blog aux utilisateurs étrangers nous avons pensé à convertir le format des dates ainsi que l'affichage du calendrier (Calendar sous Visual Studio).

Pour finaliser la traduction nous utiliserons donc une fonction qui gère la culture de la session:

'Vérifie la langue sélectionnée
System.Threading.Thread.CurrentThread.CurrentCulture =
New CultureInfo(ListeLangues.SelectedValue.ToString())

En effet, System.Threading.Thread.CurrentThread.CurrentCulture renvoie la culture courante mais cette dernière n'est pas une variable en lecture seule. Nous pouvons donc la modifier en lui assignant comme valeur la culture correspondant à la sélection dans "ListeLangues". Pour cela nous créons une culture à l'aide de New CultureInfo(…).que nous associons au choix du menu déroulant.
Pour que tout se déroule correctement, il suffit de réactualiser la page (AutoPostBack=True pour le menu déroulant "ListeLangues" pour que cela soit automatique) en ayant inséré le code précédent au tout début du Page_Load. Il faut alors remplir les Datalists et le tour est joué. Si vous rencontrez des problèmes de réactualisation, il est possible d'y remédier en modifiant la fonction associée à la sélection d'une langue dans la liste déroulante "ListeLangues".

Voici le code à ajouter:

'Fonction qui lance la traduction
Private Sub ListeLangues_SelectedIndexChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ListeLangues.SelectedIndexChanged

'Fonction qui remplit les listes après changement de langue

'Fonction qui remplit la liste des notes
RemplirDataList()

'Les 10 dernières notes
DernieresNotes()

'Fonction qui traduit les textes
Traduction()
 
End Sub

La culture de la page s'actualise donc à chaque changement de sélection dans la liste. Mais il arrive parfois que nous ayons besoin d'un format de date très précis (d'une certaine culture) sans pour autant changer la culture de tous les éléments de la page…

Déclaration d'une nouvelle culture
Il est parfois nécessaire de déclarer une nouvelle culture afin d'en extraire certaines propriétés comme le format de date ou l'affichage de l'heure. Pour cela il est possible de créer une nouvelle culture.Tout d'abord il faut déclarer une variable comme étant une nouvelle CultureInfo. Ensuite, nous déclarons une deuxième variable qui correspond à un type d'information donnée, ici nous prendrons DateTimeFormatInfo qui gère le format de la date et de l'heure.

Voici un exemple de code pour illustrer un affichage de date en format américain:

Dim US As New CultureInfo("en-US")
Dim DTFI As DateTimeFormatInfo
DTFI = US.DateTimeFormat
LabelCulture.Text = DateTime.Now.ToString("f", DTFI)

Remarque: Il faudra créer dans votre page un Label nommé "LabelCulture" pour vérifier le résultat.

Changer le format d'affichage peut être utile dans certains cas, par exemple si vous exécutez des requêtes dans une base de données et que le format des dates doit être du type mm/jj/aaaa.

La traduction de notre blog est maintenant complète. Tous les textes en dehors des notes et des commentaires sont donc disponibles en plusieurs langues et le format des dates est au choix du visiteur.

Conclusion

Nous avons essayé de vous faire construire un blog visualisable sur un Smartphone comme sur un PC classique. Il reste néanmoins à personnaliser le design et éventuellement à rajouter des fonctionnalités que vous jugerez utiles.
Nous vous informons que nous avons aussi réalisé un article concernant l'envoi automatique d'une note contenant par exemple une photo prise par le téléphone portable. Ce dernier est disponible à cette adresse:
http://www.microsoft.com/france/msdn/aspnet/publication_images_blog.mspx.

Afficher:
© 2014 Microsoft