Exporter un DataGrid vers Excel en ASP.Net

Date de publication : 16/12/2004

Par Ronald VASSEUR (autres articles)
 


Introduction
1. La création d'un DataGrid
1.1. Dans la page ASPX
1.2. Dans le CodeBehind
2. Exportation d'un DataGrid simple
2.1. La méthode
2.2. Le code expliqué
3. Exportation d'un DataGrid complexe
3.1. La méthode
3.2. Le code commenté
Conclusion


Introduction

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.

<asp:DataGrid ID="dgCommande" runat="server" AutoGenerateColumns="False" BackColor="White" BorderColor="Black" CellPadding="3" Font-Name="Verdana" HeaderStyle-BackColor="#cfcfcf" EnableViewState="False" Font-Size="8pt" Font-Names="Verdana"> <AlternatingItemStyle BackColor="#D3E2EF"></AlternatingItemStyle> <HeaderStyle Font-Bold="True" HorizontalAlign="Center" BackColor="#FFFFC0"></HeaderStyle> <Columns> <asp:HyperLinkColumn DataNavigateUrlField="refarticle" DataNavigateUrlFormatString="detail.aspx?id={0}" DataTextField="refarticle" HeaderText="Référence"> <HeaderStyle HorizontalAlign="Center" Width="35px"></HeaderStyle> <ItemStyle HorizontalAlign="Center" VerticalAlign="Middle"></ItemStyle> </asp:HyperLinkColumn> <asp:BoundColumn DataField="produit" HeaderText="Produit"> <HeaderStyle HorizontalAlign="Center" Width="200px"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="quantite" HeaderText="Quantité"> <HeaderStyle HorizontalAlign="Center" Width="25px"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="prixht" HeaderText="Prix HT"> <HeaderStyle HorizontalAlign="Center" Width="75px"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="PrixTTC" HeaderText="Prix TTC"> <HeaderStyle HorizontalAlign="Center" Width="75px"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="refarticle" HeaderText="Code barre"> <HeaderStyle HorizontalAlign="Center" Width="85px"></HeaderStyle> <ItemStyle Font-Size="18pt" Font-Names="Code 3 de 9" HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> </asp:DataGrid>

1.2. Dans le CodeBehind

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 As New HyperLinkColumn Dim colNom As New BoundColumn Dim colStock As New BoundColumn Dim colHT As New BoundColumn Dim colTTC As New BoundColumn Dim toto As New 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 :
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

2.2. Le code expliqué

Code d'exportation d'un DataGrid simple
Private Sub 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'HtmlTextWriter Dim 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() End Sub

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
Private Sub 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'HtmlTextWriter Dim 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() End Sub
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
Private Sub verifColonne(ByVal monDataGrid As Control) ' On récupère le nombre de controles enfants composant le DataGrid Dim nbControls As Integer = monDataGrid.Controls.Count - 1 While nbControls >= 0 verifColonne(monDataGrid.Controls(nbControls)) nbControls = nbControls - 1 End While ' Si la cellule ne contient pas du texte simple If Not (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" If Not (monDataGrid.GetType().GetProperty("SelectedItem") Is Nothing) Then Dim 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) End Try ' 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" If Not (monDataGrid.GetType().GetProperty("Text") Is Nothing) Then Dim 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) End If End If End If End Sub

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 !



Copyright © 2004 Ronald VASSEUR. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Cette page est déposée.

 
 
 
 
Partenaires

Hébergement Web