Grégory Renard
La réflection au Quotidien
Optimisation de votre développement grâce à la Reflection. Reflection - Génération et gestion de formulaires web dynamiques
Par Grégory Renard publié le 02/01/2005 à 23:27, lu 10712 fois, 6 pages
 5 | Explications
Explications


Note: Ces exemples se veulent simple ainsi j'ai clairement négligé l'approche architecte au profit d'une focalisation sur la compréhension des concepts de Reflection. Nous pourrons nous soucier d'inclure cette approche dans une méthodologie digne de ce nom dans de futurs articles.

Comme vous pouvez le constater au travers de la Reflection ci-dessus de mon assembly « introdotnet » via l'outil .NET Reflector de Lutz Roeder's, le projet que nous allons ainsi créer sera constitué de :
  • 3 classes représentant la structure de nos formulaires
    • Clients.vb : Contenant les propriétés de l'objet client (nom, prénom, ...)
    • Fournisseurs.vb : Contenant les propriétés de l'objet fournisseur
    • Produits.vb : Contenant les propriétés de l'objet produit
  • 1 formulaire web, conteneur physique de nos futurs formulaires.
    • ReflectionAuQuotidien.aspx
  • 1 classe vb contenant
    • ReflectionAuQuotidienVB.vb : Contenant notre mini moteur de Reflection des classes vers une datatable
Note : Les noms de fichiers se veulent volontairement explicites.Abordons d'abord de notre moteur de Réflection...
  • ReflectionAuQuotidienVB.vb
'importation de l'espace 
Imports System.Reflection

Public Class ReflectionAuQuotidienVB

    ' fonction recuperant le nom de la classe  reflectionner, retournant un objet de type datatable
    Public Function getPropTodtTable(ByVal sClassName As String) As DataTable

        'declaration d'un objet de type Assembly, vous remarquerez les [] permettant de palier
        ' au fait que le Assembly est un mot reserve de VB.NET
        Dim asm As [Assembly]
        'obtient l'assembly  partir duquel le code en cours est execute
        asm = Reflection.Assembly.GetExecutingAssembly

        'declaration d'un objet Type
        Dim t As Type
        'obtention du type  partir de son nom, attention au respect de la casse !
        ' ex : introdotnet.clients
        t = Type.GetType(asm.GetName.Name & "." & sClassName)
        'declaration de deux objets de type "PropertyInfo", une collection et un objet
        ' PropertyInfo permet d'identifier les attributs d'une propriete et permet d'acceder aux metadonnees de propriete
        Dim propInfo As PropertyInfo(), propI As PropertyInfo

        'recuperation de la collection des proprietes de notre classe
        propInfo = t.GetProperties

        'declaration d'un objet de type datatable
        Dim myDt As New DataTable

        'parcours de proprietes de la classe afin de creer les colonnes de la datatable
        For Each propI In propInfo
            'declaration d'un objet de type datatcolumn
            Dim myCol As New DataColumn
            'definition du nom de la colonne
            myCol.ColumnName = propI.Name
            'definition du type de la colonne
            myCol.DataType = Type.GetType(propI.PropertyType.FullName)
            'ajout de la colonne  la datatable
            myDt.Columns.Add(myCol)
        Next

        'retour de la datatable
        Return myDt

    End Function

End Class
Notre moteur de Reflection étant en place, voyons maintenant la classe associée à notre formulaire web «ReflectionAuQuotidien.aspx ».
  • ReflectionAuQuotidien.aspx.vb
Public Class ReflectionAuQuotidien
    Inherits System.Web.UI.Page

#Region " Code genere par le Concepteur Web Form "

    'Cet appel est requis par le Concepteur Web Form.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

    End Sub

    'REMARQUE: la declaration d'espace reserve suivante est requise par le Concepteur Web Form.
    'Ne pas supprimer ou deplacer.
    Private designerPlaceholderDeclaration As System.Object

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: cet appel de methode est requis par le Concepteur Web Form
        'Ne le modifiez pas en utilisant l'editeur de code.
        InitializeComponent()
    End Sub

#End Region

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        If Not (Request.QueryString("classe") Is Nothing) Then
            ' Page.FindControl("form1") : permet d'instancier l'objet form1
            ' .Controls.Add(loadForm("Clients")) : ajoute le placeholder a la collection des contrles de form1
            Page.FindControl("form1").Controls.Add(loadForm(Request.QueryString("classe")))
            ' association de l'evenement recupDatas avec le contrle button 'btSend'
            AddHandler CType(Me.FindControl("btSend"), Button).Click, New EventHandler(AddressOf recupDatas)
        End If
    End Sub

    ' function de chargement du formulaire a partir d'un placeholder
    Private Function loadForm(ByVal myClasse As String) As PlaceHolder
        ' ATTENTION : je ne gere pas la verification de la presence de la classe
        Dim MyReflection As New introdotnet.ReflectionAuQuotidienVB
        Dim MyDt As DataTable = MyReflection.getPropTodtTable(myClasse)

        'declaration d'un objet de type PlaceHolder servant de container des differents contrles web 
        ' couples "literalcontrol - textbox"
        Dim MyPH As New PlaceHolder
        MyPH.ID = "phRedo"

        For Each myColumn As DataColumn In MyDt.Columns
            MyPH.Controls.Add(New LiteralControl(myColumn.ColumnName & " : "))
            Dim MyTb As New TextBox
            MyTb.ID = myColumn.ColumnName
            MyPH.Controls.Add(MyTb)
            MyPH.Controls.Add(New LiteralControl("<br>"))
        Next

        Dim MyBt As New Button
        MyBt.ID = "btSend"
        MyBt.Text = "Valider"
        MyPH.Controls.Add(MyBt)

        Return MyPH

    End Function

    ' recuperation des donnees de mon formulaire
    Private Sub recupDatas(ByVal sender As System.Object, ByVal e As System.EventArgs)
        ' verification prealable de la presence ou non de mon datatable en session
        Dim myDt As DataTable
        If Not (Session("dt" & Request.QueryString("classe")) Is Nothing) Then
            myDt = CType(Session("dt" & Request.QueryString("classe")), DataTable).Copy
        Else
            Dim MyReflection As New introdotnet.ReflectionAuQuotidienVB
            myDt = MyReflection.getPropTodtTable(Request.QueryString("classe"))
        End If

        ' recuperation des donnees du formulaire (via le placeholder) et insertion en ligne
        Dim myRow As DataRow
        myRow = myDt.NewRow
        For Each ct As Control In CType(Page.FindControl("phRedo"), PlaceHolder).Controls
            If ct.GetType.ToString = "System.Web.UI.WebControls.TextBox" Then
                ' recuperation du type, ATTENTION, je ne gere pas la verification du Type de la donnee recuperee !!!
                myRow(ct.ID) = CType(ct, TextBox).Text
            End If
        Next

        ' ajout de la ligne a mon datatable
        myDt.Rows.Add(myRow)

        ' mise en session de mon datatable
        Session("dt" & Request.QueryString("classe")) = myDt

        ' affichage des donnees dans la page par un datagrid
        Dim myDg As New DataGrid
        myDg.DataSource = CType(Session("dt" & Request.QueryString("classe")), DataTable)
        myDg.DataBind()
        Page.FindControl("form1").Controls.Add(myDg)
    End Sub

End Class
Notre moteur de Reflection et notre page web son maintenant en place, prenons la classe produits.vb pour exemple.
  • produits.vb
Public Class produits

    Private _libelle As String
    Private _prix As Integer
    Private _stock As Integer
    Private _detail As String

    Public Property libelle() As String
        Get
            Return (Me._libelle)
        End Get
        Set(ByVal Value As String)
            Me._libelle = Value
        End Set
    End Property

    Public Property prix() As Integer
        Get
            Return (Me._prix)
        End Get
        Set(ByVal Value As Integer)
            Me._prix = Value
        End Set
    End Property

    Public Property stock() As Integer
        Get
            Return (Me._stock)
        End Get
        Set(ByVal Value As Integer)
            Me._stock = Value
        End Set
    End Property

    Public Property detail() As String
        Get
            Return (Me._detail)
        End Get
        Set(ByVal Value As String)
            Me._detail = Value
        End Set
    End Property

End Class
Observons maintenant le résultat à la compilation pour cette classe produit :



Et enfin lors de la saisie des informations :



Testons maintenant la manipulation à partir de la classe « clients.vb »



Et toujours le résultat lors de la saisie de informations :



 
» Démarrer une discussion