Excel étant un outil très utilisé, il peut être utile d'exporter des données depuis une page ASP.Net (nous utiliserons le langage VB.Net)
vers une feuille Excel. Nous allons voir ici, qu'il s'agît d'une chose aisée en ASP.Net. Cela
était déjà possible avec ASP (ce cher ancêtre, n'ayant par ailleurs, plus grand-chose à voir avec son successeur)
mais au prix d'un bon mal de tête.
Il n'est désormais plus nécessaire de passer par un composant COM, quelques lignes de code suffisent.
Le composant qui s'apparente le plus à une feuille de calcul Excel est le DataGrid. C'est donc tout naturellement
lui que nous allons utiliser pour exporter nos données.
Je tiens à préciser que tout cela a été testé avec le Framework 1.1 (SP1) et Excel 2003, je ne peux
donc certifier le fonctionnement avec une plateforme différente.
1. La création d'un DataGrid
1.1. Dans la page ASPX
Pour créer un DataGrid dans une page ASPX, il y a deux voies possibles : soit l'on utilise une
solution WYSIWYG (What You See Is What You Get) comme Web Matrix, ou Visual Studio qui lui permet
beaucoup plus, soit vous êtes très motivés (trop ?) et vous le faites à la main en tapant les
balises une à une
Ce tutoriel n'ayant pas pour but la création de DataGrid, je vais ici me contenter de vous donner
un copier/coller du code permettant d'afficher un tel composant dans une page ASPX.
Cette technique a ma préférence; en effet, créer le DataGrid directement dans le code permet,
selon moi, de mieux maîtriser l'apparence du composant. De plus il est beaucoup plus facile
de le maintenir et de le rendre dynamique.
Nous allons maintenant voir un morceau de code commenté en VB.Net, permettant de créer un
DataGrid, de le lier à des données et de modifier son apparence. Votre page ASPX doit déjà
contenir un DataGrid nommé monDataGrid. Vous pourriez aussi utiliser un composant
PlaceHolder (qui est un conteneur vide que l'on peut positionner où l'on veut dans sa page,
et dans lequel, on peut placer le composant que l'on souhaite (DataGrid, bouton, lien ) pour
ne pas avoir à créer "par avance" votre DataGrid; mais une fois de plus, ce n'est pas
l'objet de ce tutoriel.
Création d'un DataGrid dans le CodeBehind
' La source de données du DataGrid est un OracleDataReader portant le nom monReader
monDG.DataSource = monReader
' Définition des caractéristiques graphiques générales du DataGrid
monDG.BorderColor = Color.Black
monDG.CellPadding = 3
monDG.CellSpacing = 0
monDG.HeaderStyle.ForeColor = Color.Black
monDG.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
monDG.HeaderStyle.BackColor = Color.FromName("FFCC33")
monDG.AutoGenerateColumns = False
monDG.AlternatingItemStyle.BackColor = Color.FromName("FFFF99")
' Instanciation des colonnes du DataGrid ' (on voit qu'elles sont de types différents)Dim colRef AsNew HyperLinkColumn
Dim colNom AsNew BoundColumn
Dim colStock AsNew BoundColumn
Dim colHT AsNew BoundColumn
Dim colTTC AsNew BoundColumn
Dim toto AsNew ButtonColumn
'Ce DataGrid comportera donc 5 colonnes
toto.ButtonType = ButtonColumnType.PushButton
toto.Text = "ddjhdj"
monDG.Columns.Add(toto)
colRef.DataTextField = "CODE"
colRef.DataNavigateUrlField = "CODE"
colRef.DataNavigateUrlFormatString = "./../details.aspx?ref={0}"
colRef.HeaderText = "Référence"
colRef.HeaderStyle.Width = Unit.Pixel(150)
colRef.HeaderStyle.Font.Bold = True
colRef.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
colRef.ItemStyle.HorizontalAlign = HorizontalAlign.Center
monDG.Columns.Add(colRef)
' ------ Etudions la création de cette colonne ------ ' Les données affichées dans cette colone sont récupérées dans ' le DataReader dans le champ NOM
colNom.DataField = "NOM" ' On définit le texte d'en-tête de la colonne
colNom.HeaderText = "Descriptif du produit" ' On définit la largeur de la colonne
colNom.HeaderStyle.Width = Unit.Pixel(650)
' On mets en gras le corps du texte de l'en-tête
colNom.HeaderStyle.Font.Bold = True ' On aligne le texte de l'en-tête au milieu
colNom.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
' On aligne les données dans la colonne à gauche
colNom.ItemStyle.HorizontalAlign = HorizontalAlign.Left
' On "rattache" la colonne au DataGrid
monDG.Columns.Add(colNom)
'---> Il existe bien évidemment beaucoup d'autres propriétés qui ' peuevent être définies dans le codebehind
colStock.DataField = "STOCKPHYS"
colStock.HeaderText = "En stock"
colStock.HeaderStyle.Width = Unit.Pixel(100)
colStock.HeaderStyle.Font.Bold = True
colStock.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
colStock.ItemStyle.HorizontalAlign = HorizontalAlign.Center
monDG.Columns.Add(colStock)
colHT.DataField = "PRIXBASEHT"
colHT.HeaderText = "Prix HT"
colHT.HeaderStyle.Width = Unit.Pixel(90)
colHT.HeaderStyle.Font.Bold = True
colHT.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
colHT.ItemStyle.HorizontalAlign = HorizontalAlign.Center
monDG.Columns.Add(colHT)
colTTC.DataField = "PRIXBASETTC"
colTTC.HeaderText = "Prix TTC"
colTTC.HeaderStyle.Width = Unit.Pixel(90)
colTTC.HeaderStyle.Font.Bold = True
colTTC.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
colTTC.ItemStyle.HorizontalAlign = HorizontalAlign.Center
monDG.Columns.Add(colTTC)
' Les données contenues dans le OracleDataReader sont liées au DataGrid
monDG.DataBind()
Remarque : je pars du principe que vous avez créé un DataReader (ou autre) qui contient les données à
afficher dans le DataGrid, en effet cette étape n'est pas l'objet de ce tutoriel.
2. Exportation d'un DataGrid simple
2.1. La méthode
Nous allons utiliser l'objet Response qui permet de récupérer le flux de sortie d'une
page ASP.Net en le plaçant dans une mémoire tampon, puis lors de la fermeture de cet
objet les données collectées sont envoyées au client. Pour copier le contenu du DataGrid
dans la mémoire tampon, nous allons utiliser une méthode de l'objet DataGrid qui permet en
quelque sorte d'extraire son contenu. Il s'agit de la méthode RenderControl. Cette méthode
place les informations dans un HtmlTextWriter.
Pour spécifier au client qu'il s'agît d'une feuille de calcul Excel, et non d'un fichier
de données quelconques, il faut définir son type MIME. Les types MIME sont issus d'une
standardisation des transferts de fichier en utilisant le protocole HTTP.
Voici un récapitulatif simplifié de la méthode employée.
Récupération des données dans le DataGrid
Spécification du type des données (Excel) récupérées
Envoie du fichier Excel au client
Remarque : comme vous avez tous dû en faire les frais un jour, les différents jeux de
caractères sont de véritables pièges à développeurs Bref, même ici vous n'y échapperez pas.
En effet, il se peut que vos données soient altérées (les caractères accentués par exemple)
lors du passage de la page ASPX à Excel. Pour cela, je n'ai trouvé qu'une seule solution fiable.
J'ai défini, dans ma page ASPX, le jeu de caractères qu'elle doit utiliser. Ainsi, j'ai pu conserver
mes accents et mes caractères spéciaux dans Excel. Sans définir le jeu utilisé dans ma page ASPX, je
perdais systématiquement tous les caractères accentués. Pour cela, dans la balise HEAD, j'ai rajouté
" charset=iso-8859-1 " comme suit :
PrivateSub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' On efface les éventuelles données déjà dans la mémoire tampon
Response.Clear()
' On place tout ce qui est destiné au client dans la mémoire tampon
Response.Buffer = True ' On définit le type d'informations renvoyée, ici des données au format Excel
Response.ContentType = "application/vnd.ms-excel" ' On efface le jeu de caractères actuellement défini
Response.Charset = "" ' On instancie deux objets qui vont nous permettre de récupérer les données du DataGrid : ' le StringWriter et l'HtmlTextWriterDim monStringWriter As StringWriter = New StringWriter
Dim monHtmlTextWriter As HtmlTextWriter = New HtmlTextWriter(monStringWriter)
' On extrait le contenu du DataGrid dans l'HtmlTextWriter
monDG.RenderControl(monHtmlTextWriter)
' On copie le contenu extrait dans la mémoire tampon
Response.Write(monStringWriter.ToString())
' On ferme "le flux" de données et envoie les données au client
Response.End()
EndSub
3. Exportation d'un DataGrid complexe
3.1. La méthode
Tout d'abord, il faut se mettre d'accord sur l'expression "DataGrid complexe", je fais cet
"abus de langage" pour décrire un DataGrid contenant autre chose que du texte. Cela peut,
par exemple, être des boutons ou des liens hypertextes.
Que le DataGrid soit simple ou complexe, la méthode d'exportation des données sera rigoureusement
la même, sauf que, dans ce dernier cas, il faudra appliquer un traitement aux données avant
d'appliquer la méthode RenderControl. Si ce traitement n'est pas effectué, alors une exception
sera levée.
Le traitement à effectuer consiste à remplacer chaque contrôle non littéral par sa représentation
sous forme de texte. Par exemple, un bouton sera remplacé par son texte, idem pour un lien
hypertexte, un contrôle offrant des choix multiples sera remplacé par la valeur sélectionnée.
3.2. Le code commenté
Le code d'exportation ne change pas, à l'exception de l'appel de verifColonne( ) qui va
effectuer le traitement.
Code d'exporation d'un DataGrid compelxe
PrivateSub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' On appelle de verifColonne avec le nom du DataGrid concerné en paramètre
verifColonne(monDG)
' On efface les éventuelles données déjà dans la mémoire tampon
Response.Clear()
' On place tout ce qui est destiné au client dans la mémoire tampon
Response.Buffer = True ' On définit le type d'informations renvoyée, ici des données au format Excel
Response.ContentType = "application/vnd.ms-excel" ' On efface le jeux de caractères actuellement défini
Response.Charset = "" ' On instancie deux objets qui vont nous permettre de récupérer les données du DataGrid : ' le StringWriter et l'HtmlTextWriterDim monStringWriter As StringWriter = New StringWriter
Dim monHtmlTextWriter As HtmlTextWriter = New HtmlTextWriter(monStringWriter)
' On extrait le contenu du DataGrid dans l'HtmlTextWriter
monDG.RenderControl(monHtmlTextWriter)
' On copie le contenu extrait dans la mémoire tampon
Response.Write(monStringWriter.ToString())
' On ferme "le flux" de données et envoi les données au client
Response.End()
EndSub
On peut rapidement expliquer le fonctionnement de verifColonne() de la façon
suivante : chaque contrôle composant le DataGrid sera testé, s'il s'agît d'une cellule
standard (contenant du texte) alors aucun traitement ne sera effectué. S'il ne s'agît
pas d'une cellule standard alors deux possibilités :
Si le contrôle concerné a une propriété "SelectedItem" (c'est le cas des contrôles offrant des choix multiples) alors on récupérera la valeur associée, elle sera ensuite mise dans le DataGrid en lieu et place du contrôle original.
Si le contrôle concerné n'a pas de propriété "SelectedItem" alors, il aura forcément (enfin dans 99% des cas) une propriété "Text", c'est donc cette propriété qui est récupérée et mise à la place du contrôle origine.
Code de traitement du contenu du DataGrid
PrivateSub verifColonne(ByVal monDataGrid As Control)
' On récupère le nombre de controles enfants composant le DataGridDim nbControls AsInteger = monDataGrid.Controls.Count - 1
While nbControls >= 0
verifColonne(monDataGrid.Controls(nbControls))
nbControls = nbControls - 1
EndWhile ' Si la cellule ne contient pas du texte simple IfNot (TypeOf monDataGrid Is TableCell) Then ' Si le controle concerné à une prorpiété "Selected Item" alors... ' Remarque : Seul les controles offrant des choix multiples ont une propriété "SelectedItem"IfNot (monDataGrid.GetType().GetProperty("SelectedItem") IsNothing) ThenDim controleLitteral1 As LiteralControl = New LiteralControl
monDataGrid.Parent.Controls.Add(controleLitteral1)
Try ' La cellule prend alors pour valeur le texte correspondant à la propriété "SelectedItem"
controleLitteral1.Text = _
CType(monDataGrid.GetType().GetProperty("SelectedItem").GetValue(monDataGrid, Nothing), String)
Catch monException As Exception
' On récupère l'exception en cas de problème
Response.Write(monException.Message)
EndTry ' Le controle concerné est retiré
monDataGrid.Parent.Controls.Remove(monDataGrid)
Else ' Si le controle concerné n'a pas de propriété "SelectedItem" alors on récupère le ' texte (s'il y en a un) de sa propriété "Text"IfNot (monDataGrid.GetType().GetProperty("Text") IsNothing) ThenDim controleLitteral2 As LiteralControl = New LiteralControl
monDataGrid.Parent.Controls.Add(controleLitteral2)
' On attribue le texte de la propriété "Text" à la cellule concernée
controleLitteral2.Text = _
CType(monDataGrid.GetType().GetProperty("Text").GetValue(monDataGrid, Nothing), String)
monDataGrid.Parent.Controls.Remove(monDataGrid)
EndIfEndIfEndIfEndSub
Conclusion
Voilà, vous savez désormais comment exporter le contenu d'un DataGrid, qu'il soit simple ou plus
complexe, vers Excel. Comme d'habitude, avec le Framework .Net, il n'y a rien de bien sorcier,
ici, la difficulté est essentiellement d'ordre algorithmique. Ce tutoriel a pour
but de faire une exportation basique et intégrale d'un DataGrid. Libre à vous d'améliorer tout cela.
Je vous souhaite de bonnes exportations vers Excel, et vous donne rendez-vous dans un prochain tutoriel.
Un grand merci à FreeGreg pour la relecture de cet article !