I. Introduction

Dans de nombreuses situations, il est nécessaire de créer une gridview à la volée avec des données qui risquent de changer en cours de route. Cet article montre comment créer un gridview, y rajouter ses évènements de modification, maj et cancel. Et surtout la création de colonne templates à la volée avec la méthode databind personnalisée selon le type de contrôle dans le template.

II. Avant de commencer

Vous démarrez idéalement d'une page vierge que nous appellerons Visualisation.Aspx. Placez dans cette page, un contrôle PlaceHolder qu'on nommera Placeholder1. Dans votre code HTML il devrait y avoir :

 
Sélectionnez

<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>

Assurez-vous d'avoir une base de donnée SQL pour tester (NorthWind sera utilisée dans cet exemple). Ceci étant la base utilisée dans cet exemple. Maintenant que nous avons la base, nous pouvons nous concentrer sur le " code behind "

III. Création de la gridview dynamiquement

Le gridview, comme n'importe quel autre contrôle du framework, peut être créé à l'aide d'un simple Dim Dans un premier temps, on va créer le contrôle, modifier ses propriétés et le lier à un datasource. Ensuite, vous allez voir, que les colonnes créées ne seront pas associé au gridview, mais au DataSource. Dans cet exemple, je me sers de la base exemple NorthWind sur SQL server 2000.

 
Sélectionnez

Dim cnn As New System.Data.SqlClient.SqlConnection("Data Source=Serveur;Initial Catalog=Northwind;User ID=userId;password=MotDePasse")

Dim myDataset As New DataSet
Dim myDataset2 As New DataSet
Dim MyTable As DataTable = New DataTable
Dim MyDatarow As DataRow

Dim dtr As New SqlClient.SqlDataAdapter("SELECT Products.ProductID, Products.ProductName, Products.CategoryID Products ON Categories.CategoryID = Products.CategoryID", cnn)
Dim dtrCategory As New SqlClient.SqlDataAdapter("SELECT Categories.CategoryID, Categories.CategoryName FROM Categories ", cnn)

dtr.Fill(myDataset)
dtrCategory.Fill(myDataset2)

Dim GrdDynamic As New GridView

GrdDynamic.DataSource = myDataset.Tables(0)
GrdDynamic.DataBind()
PlaceHolder1.Controls.Add(GrdDynamic)

OK, le résultat ressemble à ceci :

Image non disponible
Figure 1

Simple non? Mais, comment modifier les lignes ? Et également avoir plusieurs choix pour la catégorie ? C'est là que la création dynamique des templates est obligatoire.

IV. Ajout d'une classe Itemplate

Un template, pour vulgariser, est une description particulière d'un rendu au moment de l'exécution. Il détermine l'aspect " layout " et la partie liée " binding " d'un contrôle. Parce que nous ne savons pas, a priori, quels champs seront dans notre datagrid, nous devons utiliser des templates dynamiques. Ceci se fait avec l'implémentation de Itemplate. Nous devons générer le ItemTemplate et le EditItemTemplate dynamiquement pour chacun des champs.

ITemplate a une méthode InstantiateIn que je décrirai plus bas. La classe GridViewTemplate qui implémente cette interface, expose n'importe quelle propriété de la gridview comme la sienne, alors le "layout " par défaut est surpassé. Pour pouvoir réutiliser la classe dans d'autres situations, j'ai décidé de l'extentier dans une classe à part.

Voici la structure générale de la classe GridViewTemplate :

 
Sélectionnez

Public Class GridViewTemplate
    Implements ITemplate

    Dim _templateType As ListItemType
    Dim _columnName As String
    Dim _TypeControl As String = "TextBox"
    Dim _Dts As DataSet

Public Sub New(ByVal Type As ListItemType, ByVal colname As String, ByVal TypeControl As String)

        _templateType = Type
        _columnName = colname
        _TypeControl = TypeControl

End Sub

Public Sub InstantiateIn
End Sub

Sub DataBinding (ByVal sender As Object, ByVal e As EventArgs)
End Sub

_templateType est le type de template (Item, Edit etc…), _columnName le nom de la colonne, et _TypeControl le type de contrôle qui sera rendu dans notre template. Vous pouvez avoir plusieurs constructeurs, moi j'ai choisi d'en avoir deux. Ceci pour maîtriser si un template contient une liste de valeurs passée comme un dataset que je peux associer à un listbox ou un autre contrôle.

 
Sélectionnez

Public Sub New(ByVal Type As ListItemType, ByVal colname As String, ByVal TypeControl As String)

        _templateType = Type
        _columnName = colname
        _TypeControl = TypeControl

End Sub

Public Sub New(ByVal Type As ListItemType, ByVal colname As String, ByVal TypeControl As String, ByVal dts As DataSet)

        _templateType = Type
        _columnName = colname
        _TypeControl = TypeControl
        _Dts = dts

End Sub

La méthode InstantiateIn est la première partie de ma classe. Cette méthode s'assure que le type de template est créé par rapport à son contrôle prédéfini. Je vais dans cet exemple m'occuper type ItemTemplate et de EditTemplate. Il y en a d'autre: HeaderTemplate etc. Regardons mon exemple :

 
Sélectionnez

Select Case _templateType

    Case ListItemType.Item

        Select Case UCase(_TypeControl)
            Case "BUTTON"
				Dim tb1 As Button = New Button()
				AddHandler tb1.Click, AddressOf tb1_EditClik
				tb1.CommandName = "EDIT"
				container.Controls.Add(tb1)
            Case "LABEL"
				Dim tb1 As Label = New Label()
				tb1.BorderStyle = BorderStyle.None
				AddHandler tb1.DataBinding, AddressOf tb1_DataBindingLabel
				container.Controls.Add(tb1)
            Case "LISTBOX"
				Dim mylistbox As DropDownList = New DropDownList
				mylistbox.DataSource = _Dts.Tables(0)
				AddHandler mylistbox.DataBinding, AddressOf tb1_DataBindingListBox
				mylistbox.DataTextField = _columnName
				mylistbox.DataValueField = _columnName2
				mylistbox.ID = ("lstDynamique")
				mylistbox.Enabled = False
				container.Controls.Add(mylistbox)
				End Select
        End Select

Un point important à ne pas manquer c'est que j'initialise la propriété CommandName de mon bouton à " EDIT ". Ceci aura pour effet de démarrer la méthode associée au gridview.

L'autre point important c'est que j'ai rajouté des AddHandlers. C'est là que j'effectue mon databinding. Remarquez bien la partie DataBinder.Eval.

Pour l'étiquette :

 
Sélectionnez

Sub tb1_DataBindingLabel(ByVal sender As Object, ByVal e As EventArgs)

        Dim lbldata As Label = CType(sender, Label)
        Dim container As GridViewRow = CType(lbldata.NamingContainer, GridViewRow)
        Dim dataValue As Object = DataBinder.Eval(container.DataItem, _columnName)

        If Not IsNothing(dataValue) Then
            lbldata.Text = WrappableText(dataValue.ToString)
        End If

    End Sub

Pour le listBox :

 
Sélectionnez

Sub tb1_DataBindingListBox(ByVal sender As Object, ByVal e As EventArgs)

        Dim lst As DropDownList = CType(sender, DropDownList)
        Dim container As GridViewRow = CType(lst.NamingContainer, GridViewRow)
        Dim dataValue As Object = DataBinder.Eval(container.DataItem, _columnName)

        If Not IsNothing(dataValue) Then
            lst.SelectedValue = dataValue.ToString
        End If

    End Sub

Aucune différence !!!!!!!!!!!!!!! OK cela c'est pour le ITEMTEMPLATE, celui du EDIT est un peut différent. Regardez :

 
Sélectionnez

Case ListItemType.EditItem
	
	Select Case UCase(_TypeControl)
		Case "BUTTON"
			Dim tb1 As Button = New Button()
			tb1.Visible = True
			tb1.CommandName = "Update"
			If HttpContext.Current.Session("InsertFlag") = 1 Then
				tb1.Text = "Ajouter"
			Else
				tb1.Text = "MAJ"
			End If
			tb1.OnClientClick = "return confirm('Etes vous sûre de MAJ?')"
			container.Controls.Add(tb1)
			Dim tb2 As Button = New Button()
			tb2.CommandName = "Cancel"
			container.Controls.Add(tb2)
		Case "LABEL"
			Dim tb1 As Label = New Label()
			tb1.BorderStyle = BorderStyle.None
			AddHandler tb1.DataBinding, AddressOf tb1_DataBindingLabel
			tb1.Visible = True
			container.Controls.Add(tb1)
		Case "LISTBOX"
			Dim mylistbox As DropDownList = New DropDownList
			mylistbox.DataSource = _Dts.Tables(0)
			AddHandler mylistbox.DataBinding, AddressOf tb1_DataBindingListBox
			mylistbox.DataTextField = _columnName
			mylistbox.DataValueField = _ColumnName2
			mylistbox.ID = ("lstDynamique")
			mylistbox.Enabled = True
			container.Controls.Add(mylistbox)
		Case "TEXTBOX"
			Dim tb1 As TextBox = New TextBox()
			tb1.BorderStyle = BorderStyle.None
			AddHandler tb1.DataBinding, AddressOf tb1_DataBindingTextBox
			tb1.Columns = 4
			tb1.Visible = True
			container.Controls.Add(tb1)
	End Select
End Select

J'ai deux boutons au lieu d'un: Update et Cancel. Les deux sont associés aux CommandName Update et Cancel. Le Listbox est actif et il y a un Textbox. De plus, remarquez que ce sont les mêmes AddHandlers… C'est parce que le databinding est bidirectionnel. C'est la même méthode qui gère la récupération et la sauvegarde !

OK l'implémentation de l'ITemplate est terminée. Allons voir comment s'en servir.

V. Utilisation de ITemplate

Vous avez créé la gridview et créé la classe qui implémente ITemplate. Maintenant on va voir comment s'en servir !

En premier lieu il faut modeler la table et les colonnes qui vont structurer notre gridview.

 
Sélectionnez

Dim MyTable As DataTable = New DataTable
Dim MyDatarow As DataRow

Dim dcol As Data.DataColumn = New Data.DataColumn("ProductId", GetType(System.Int32))
MyTable.Columns.Add(dcol)

dcol = New Data.DataColumn("ProductName", GetType(System.String))
MyTable.Columns.Add(dcol)

dcol = New Data.DataColumn("CategoryID", GetType(System.Int32))
MyTable.Columns.Add(dcol)

Ensuite, y rajouter les lignes :

 
Sélectionnez

For Each MyDatarow In myDataset.Tables(0).Rows
	Dim drow As Data.DataRow = MyTable.NewRow
            
	drow("ProductId") = MyDatarow("ProductId")
    drow("ProductName") = MyDatarow("ProductName")
    drow("CategoryID") = MyDatarow("CategoryID")
    MyTable.Rows.Add(drow)
Next

Notre table est maintenant modélisée. Maintenant, attardons-nous au gridview. Premièrement, il faut lui dire que les colonnes ne seront pas générées automatiquement . Et ensuite, lui rajouter les méthodes Update, Edit et Cancel:

 
Sélectionnez

GrdDynamic.AutoGenerateColumns = False

AddHandler GrdDynamic.RowEditing, AddressOf GrdDynamic_RowEditing
AddHandler GrdDynamic.RowUpdated, AddressOf GrdDynamic_RowUpdated
AddHandler GrdDynamic.RowCancelingEdit, AddressOf GrdDynamic_RowCancelingEdit

OK tout est prêt pour la magie… Il faut rajouter dans notre table (et ensuite dans notre gridview) les champs Template. C'est assez facile. Commençons par les boutons de commande :

 
Sélectionnez

Dim cmdfield As TemplateField = New TemplateField

cmdfield.ItemTemplate = New GridViewTemplate(ListItemType.Item, "...", "button")
cmdfield.EditItemTemplate = New GridViewTemplate(ListItemType.EditItem, "...", "button")

GrdDynamic.Columns.Add(cmdfield)

Et maintenant pour chaque colonne de la table :

 
Sélectionnez

For Each col As DataColumn In MyTable.Columns

	Dim bfield As TemplateField = New TemplateField
	
	If col.ColumnName = "CategoryID" Then
		Dim ColumnName2 As String = "CategoryName"
		bfield.ItemTemplate = New GridViewTemplate(ListItemType.Item, col.ColumnName, ColumnName2, "ListBox", myDataset2)
		bfield.EditItemTemplate = New GridViewTemplate(ListItemType.EditItem, col.ColumnName, ColumnName2, "ListBox", myDataset2)
	ElseIf col.ColumnName = "ProductId" Then
		bfield.ItemTemplate = New GridViewTemplate(ListItemType.Item, col.ColumnName, "Label")
	ElseIf col.ColumnName = "ProductName" Then
		bfield.ItemTemplate = New GridViewTemplate(ListItemType.Item, col.ColumnName, "Label")
		bfield.EditItemTemplate = New GridViewTemplate(ListItemType.EditItem, col.ColumnName, "textbox")
	End If
	
	GrdDynamic.Columns.Add(bfield)

Next

Et finalement je lie le tout au Gridview

 
Sélectionnez

GrdDynamic.DataSource = myDataset.Tables(0)
GrdDynamic.DataBind()
PlaceHolder1.Controls.Add(GrdDynamic)

Il ne faut surtout pas oublier de créer les méthodes GrdDynamic_RowUpdated, GrdDynamic_RowEdited et GrdDynamic_RowCancelingEdit. Dans la méthode GrdDynamic_RowEditing ne pas oublier de modifier l'index et d'effectuer le databind du gridview :

 
Sélectionnez

Sub GrdDynamic_RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs)

CType(sender, GridView).EditIndex = e.NewEditIndex
CType(sender, GridView).DataBind()
End Sub

Vous devriez maintenant avoir ceci:

Image non disponible

VI. Conclusion

La création d'un gridview avec ses évènements traditionnels et des templates de manière dynamique peut s'avérer parfois très utile. J'ai, dans cet article essayé de vous démontrer de manière simple comment le faire. J'ai volontairement mis de côté des bouts qui auraient amené de la confusion. L'essentiel est pourtant la. Vous pouvez jouez du côté du datasource, des évènements et rajouter n'importe quel contrôle dans les templates.

Amusez-vous bien!