none
DataGridView & Lecture multithread RRS feed

  • Question

  • Bonjour,

    Je fait une classe qui permet de lire une table de base de données page par page en multithreading. Problème je n'arrive pas à afficher la table durant la lecture :/.

    Je n'arrive pas à expliquer rapidement et clairement mon problème. Donc le plus simple est de vous le montrer

    Petit code pour comprendre mon problème (enfin c'est le plus petit que j'arrive à faire ^^):
    Dans un Form (Form1) mettre un DataGridView (nommer DataGridView1 soit le nom par défaut ;))
    Dans le code de cette form mettre (en principe il n'y à rien d'autre à faire ;))

    Public Class Form1
      Private Enum E_Mode
        Merge
        Rows_Add
      End Enum
      Private Class DonneesPourThread
        Public NombreDePage As Integer
        Public NombreDeLigneParPage As Integer
        Public Mode As E_Mode
      End Class
    
      Private ThreadRempli As System.Threading.Thread
      Private WithEvents TableDonnees As DataTable
      Private Delegate Sub Delegate_DataGridView1_Refresh()
    
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Juste pour que le DataGridView remplisse tout le form ;)
        DataGridView1.Dock = DockStyle.Fill
    
        'Préparation de la DataTable
        TableDonnees = New DataTable("Table de données")
        TableDonnees.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TableDonnees.Columns.Add("Donnée", System.Type.GetType("System.String"))
    
        'Crée la liaison entre la table et le DataGridView
        DataGridView1.DataSource = TableDonnees
    
        'Préparation du thread
        ThreadRempli = New System.Threading.Thread(AddressOf SubThreadRemplisage)
        ThreadRempli.IsBackground = True 'Permet au system de tué le thread quand le conteneur se termine 
    
        'Prepare le infos pour le thread
        Dim InfoThread As New DonneesPourThread
        InfoThread.NombreDeLigneParPage = 1000
        InfoThread.NombreDePage = 100
    
        'Choix du mode de fonctionnement de l'exemple 
        '<----- Pour changer le mode de fonctionnement c'est ici que sa se passe ;) ----->
        InfoThread.Mode = E_Mode.Merge
        'InfoThread.Mode = E_Mode.Rows_Add
    
        'Lance le thread
        ThreadRempli.Start(InfoThread)
      End Sub
    
      Private Sub SubThreadRemplisage(ByVal Info As DonneesPourThread)
        'Le test du mode de fonctionnement est fait ici pour éviter de le refaire à chaque boucle
        Select Case Info.Mode
          Case E_Mode.Merge
            'Sa ne fonction pas (mais c'est rapide)
            For CompteurPage As Integer = 1 To Info.NombreDePage
              Dim TablePage As DataTable = GetPageDonnees(Info.NombreDeLigneParPage)
              'Evite que plusieurs threads accèdent à cette objet en même temps
              SyncLock TableDonnees
                TableDonnees.Merge(TablePage)
              End SyncLock
            Next
          Case E_Mode.Rows_Add
            'Sa fonctionne (mais mal : les scroll ne sont jamais mit à jours sauf quand on scroll :/)
            'Et c'est TRES TRES lent (donc inacceptable pour mon code final :'( )
            For CompteurPage As Integer = 1 To Info.NombreDePage
              Dim TablePage As DataTable = GetPageDonnees(Info.NombreDeLigneParPage)
              For CompteurLigne As Integer = 1 To Info.NombreDeLigneParPage
                SyncLock TableDonnees
                  TableDonnees.Rows.Add(TablePage.Rows(CompteurLigne - 1).ItemArray)
                End SyncLock
              Next
            Next
        End Select
      End Sub
    
      Private Function GetPageDonnees(ByVal NombreLigneParPage As Integer) As DataTable
        'Prépare la table contenant la page de données
        Dim TablePage As New DataTable("Page de données lut en base de données")
        TablePage.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TablePage.Columns.Add("Donnée", System.Type.GetType("System.String"))
        For Compteur As Integer = 1 To NombreLigneParPage
          Dim Ligne As DataRow = TablePage.NewRow
          Ligne.Item(0) = TablePage.Rows.Count + TableDonnees.Rows.Count + 1
          Ligne.Item(1) = "Donnée de la ligne : " & Ligne.Item(0)
          TablePage.Rows.Add(Ligne)
        Next
    
        Return TablePage
      End Function
    
      Private Sub DataGridView1_Refresh()
        DataGridView1.Refresh()
      End Sub
    
      Private Sub TableDonnees_RowChanged(ByVal sender As Object, ByVal e As System.Data.DataRowChangeEventArgs) Handles TableDonnees.RowChanged
        'Une erreur peut survenir quand on ferme le form ;)
        Try
          'On passe dans cet événement avec mode Merge 
          'mais rien n'est mit à jour :'(
          Invoke(New Delegate_DataGridView1_Refresh(AddressOf DataGridView1_Refresh))
        Catch
    
        End Try
      End Sub
    
      Private Sub TableDonnees_TableNewRow(ByVal sender As Object, ByVal e As System.Data.DataTableNewRowEventArgs) Handles TableDonnees.TableNewRow
        'On passe dans cet événement avec mode Rows_Add 
        'Les scrolls ne sont pas mit à jour :'(
        Invoke(New Delegate_DataGridView1_Refresh(AddressOf DataGridView1_Refresh))
      End Sub
    End Class
    

    Mon but étant d'avoir une vitesse d'exécution sensiblement identique au mode "Merge" mais avec un affichage correct

    Merci à ceux qui s'intéresseront au problème (je me casse les dents dessus depuis qq heures déjà)

    Amicalement


    :) Amicalement :)
    mardi 18 janvier 2011 17:12

Réponses

  • Bonjour,

    Je n'ai pas recherché en détail mais cela semble mieux fonctionner en terme d'affichage en faisant le Merge sur le thread de l'UI. La grille reste difficilement utilisable (la position n'est pas préservée) et il semble tout de même plus efficace de charger les 100000 lignes d'un coup ce qui reste étonnamment rapide.

    Je ne suis pas un super spécialiste du sujet mais je dirais qu'une tâche d'arrière plan n'est pas très intéressante si on mets à jour l'UI trop souvent (l'utilisateur et le code vont être en compétition pour l'utilisation de la grille).

    Si le problème est que la grille va avoir beaucoup de lignes, ma préférence personnelle serait sans doute d'aller voir plutôt du côté du mode virtuel : http://msdn.microsoft.com/fr-fr/library/ms171622.aspx


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Marqué comme réponse Polack77 vendredi 21 janvier 2011 14:33
    mardi 18 janvier 2011 19:07
    Modérateur
  • Re-bonjour,

    Merci à Patrice Scribe sans qui je ne me serais pas pencher sur le virtual mode tout de suite :).

    Voila un code qui fonctionne :

    Public Class Form1
      Private Class DonneesPourThread
        Public NombreDePage As Integer
        Public NombreDeLigneParPage As Integer
      End Class
    
      Private ThreadRempli As System.Threading.Thread
      Private WithEvents TableDonnees As DataTable
      Private Delegate Sub Delegate_DataGridView1_RowCount(ByVal NewRowsCount As Integer)
      Private Delegate Sub Delegate_DataGridView1_Colums_Add(ByRef Colonne As DataGridViewColumn)
    
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Juste pour que le DataGridView remplisse tout le form ;)
        DataGridView1.Dock = DockStyle.Fill
        'Active le mode virtuelle
        DataGridView1.VirtualMode = True
    
        'Préparation du thread
        ThreadRempli = New System.Threading.Thread(AddressOf SubThreadRemplisage)
        ThreadRempli.IsBackground = True 'Permet au system de tué le thread quand le conteneur se termine 
    
        'Prepare les infos pour le thread
        Dim InfoThread As New DonneesPourThread
        InfoThread.NombreDeLigneParPage = 1000
        InfoThread.NombreDePage = 100
    
        'Lance le thread
        ThreadRempli.Start(InfoThread)
      End Sub
    
      Private Sub SubThreadRemplisage(ByVal Info As DonneesPourThread)
    
        'Prépare la table recevant les données
        TableDonnees = New DataTable("Table de données")
        TableDonnees.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TableDonnees.Columns.Add("Donnée", System.Type.GetType("System.String"))
        'Remarque :
        'En base de données, on peut executer la requete :
        'RequeteAExecuter = "SELECT * FROM (" & RequeteReel & ") a WHERE 1 = 0"
        'Ainsi on ne récupére que les colonnes et aucune données (ce qui peut être pratique ;))
    
        'On ajoute un colonne pour chaque colonne de la table
        '/!\ Ici seul des colonne de type textbox sont ajouter (il faudras tester le type de colonne de la table pour ajouter' d'autre type de colonne, tél que DataGridViewCheckBoxColumn par exemple
        For Each ColonneTable As DataColumn In TableDonnees.Columns
          Dim NewDataGridViewColumn As New DataGridViewTextBoxColumn()
          NewDataGridViewColumn.Name = ColonneTable.ColumnName
          NewDataGridViewColumn.HeaderText = ColonneTable.ColumnName
          Invoke(New Delegate_DataGridView1_Colums_Add(AddressOf DataGridView1_Colums_Add), NewDataGridViewColumn)
        Next
        'On lit les pages de données
        For CompteurPage As Integer = 1 To Info.NombreDePage
          Dim TablePage As DataTable = GetPageDonnees(Info.NombreDeLigneParPage)
          'Evite que plusieurs threads accèdent à cette objet en même temps
          SyncLock TableDonnees
            TableDonnees.Merge(TablePage)
          End SyncLock
          If DataGridView1.AllowUserToAddRows Then
            Invoke(New Delegate_DataGridView1_RowCount(AddressOf DataGridView1_RowCount), TableDonnees.Rows.Count + 1)
          Else
            Invoke(New Delegate_DataGridView1_RowCount(AddressOf DataGridView1_RowCount), TableDonnees.Rows.Count)
          End If
        Next
      End Sub
    
      Private Function GetPageDonnees(ByVal NombreLigneParPage As Integer) As DataTable
        'Prépare la table contenant la page de données
        Dim TablePage As New DataTable("Page de données lut en base de données")
        TablePage.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TablePage.Columns.Add("Donnée", System.Type.GetType("System.String"))
        'Sumule une attente de donnée du serveur (3 secondes)
        System.Threading.Thread.Sleep(3000)
        For Compteur As Integer = 1 To NombreLigneParPage
          Dim Ligne As DataRow = TablePage.NewRow
          Ligne.Item(0) = TablePage.Rows.Count + TableDonnees.Rows.Count + 1
          Ligne.Item(1) = "Donnée de la ligne : " & Ligne.Item(0)
          TablePage.Rows.Add(Ligne)
        Next
    
        Return TablePage
      End Function
    
      Private Sub DataGridView1_RowCount(ByVal NewRowsCount As Integer)
        DataGridView1.RowCount = NewRowsCount
      End Sub
    
      Private Sub DataGridView1_Colums_Add(ByRef Colonne As DataGridViewColumn)
        DataGridView1.Columns.Add(Colonne)
      End Sub
    
      Private Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
        'Si l'ajout est autorisé
        If DataGridView1.AllowUserToAddRows Then
          'Si cette ligne est la ligne d'ajout
          If e.RowIndex = Me.DataGridView1.RowCount - 1 Then
            'On sort de la fonction
            Return
          End If
        End If
        SyncLock TableDonnees
          e.Value = TableDonnees.Rows(e.RowIndex).Item(e.ColumnIndex)
        End SyncLock
      End Sub
    End Class
    
    Comme dans le 1ér code il faut simplement mettre un DataGridView sur un form (Form1) d'une nouvelle application et mettre le code ci-dessous dans le code de cette form :

    Tout n'est pas fait dans ce code, seul l'affichage de texte est fait (pas d'ajout, de suppression, modification, de données, ni de colonne de type ChekBox ou autre). Mais bon je pense que sa reste un bonne exemple ;). Pour faire le reste il faut se référer à la rubrique d'aide fournis par Patrice Scribe : http://msdn.microsoft.com/fr-fr/library/ms171622.aspx

    Voili voilou ^^


    :) Amicalement :)
    • Marqué comme réponse Polack77 vendredi 21 janvier 2011 14:33
    • Modifié Polack77 vendredi 21 janvier 2011 14:47 Mauvaise mise en page du code (sa deviens énervant mnt :( )
    vendredi 21 janvier 2011 14:33

Toutes les réponses

  • Bonjour,

    Je n'ai pas recherché en détail mais cela semble mieux fonctionner en terme d'affichage en faisant le Merge sur le thread de l'UI. La grille reste difficilement utilisable (la position n'est pas préservée) et il semble tout de même plus efficace de charger les 100000 lignes d'un coup ce qui reste étonnamment rapide.

    Je ne suis pas un super spécialiste du sujet mais je dirais qu'une tâche d'arrière plan n'est pas très intéressante si on mets à jour l'UI trop souvent (l'utilisateur et le code vont être en compétition pour l'utilisation de la grille).

    Si le problème est que la grille va avoir beaucoup de lignes, ma préférence personnelle serait sans doute d'aller voir plutôt du côté du mode virtuel : http://msdn.microsoft.com/fr-fr/library/ms171622.aspx


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Marqué comme réponse Polack77 vendredi 21 janvier 2011 14:33
    mardi 18 janvier 2011 19:07
    Modérateur
  •  

    Bonjour,

    Déjà merci de vous intéresser à mon problème :).

    Le but de ce code est double : charger un table de données en vue de l'utiliser dans le code et/ou de l'afficher. Et ce, sans que l'utilisateur de ma classe final n'est quoi que se soit à gérer de complexe. Soit avoir une classe connexion contenant une procédure "ExecuteQuery_Asyc" recevant comme paramètre une requête, la table de sortie par référence, et éventuellement un nombre de ligne par page de chargement.

    Sachant que les requêtes exécuter sur ce mode contiendront des calculs lourd fait sur de grosse quantité de données.

    Exemple d'une requête :

    SELECT
     CASE NomTable1.Colonne1
      WHEN 1 THEN
       CASE NomTable2.Colonne2
        WHEN 1 THEN 
         'Col1 = 1 & Col2 = 1'
        ELSE
         'Col1 = 1 & Col2 <> 1'
       END
      ELSE
       CASE NomTable2.Colonne2
        WHEN 1 THEN
         'Col1 <> 1 & Col2 = 1'
        ELSE
         'Col1 <> 1 & Col2 <> 1'
      END
     END AS "Valeur calculer"
    FROM
     NomTable1,
     NomTable2
    WHERE
     NomTable1.Id_Tbl2 = NomTable2.Id
    Évidament ce n'est qu'un exemple, j'ai conscience que cette requête est débile ;)

    Ce genre de requête est particulièrement long à être exécute (surtout sur de grosse table, soit entre 1 million et 10 millions de ligne). J'ai beau insister sur le faite qu'il ne fraudais pas faire ce genre de requête, ou les faire sur une quantité de données plus petite, mais en final c'est sa qui sera fait :/.

    Tout sa pour dire que UI ne sera pas mit à jour 'trop' souvent.

    Je vais m'intéresser au mode virtuel. Même si je continu de penser que le mieux serais d'afficher une DataTable charger par un thread différent de celui de UI. Je me trompe peut être mais je pense que la solution ne se trouve pas là. Le chargement d'une page pouvant prendre plusieurs secondes, le "juste-à-temps " est à exclure d'emblée (sauf erreur de ma part). Mais le mode virtuel n'est pas forcément à exclure au complet, il faut que je m'intéresse au sujet.


    :) Amicalement :)
    • Modifié Polack77 jeudi 20 janvier 2011 13:36 Mauvaise mise en page du code SQL
    jeudi 20 janvier 2011 11:16
  • Bonjour,

    Désolé d'avoir mit un peut de temps à répondre. J'ai du faire d'autre choses urgente entre temps.

    Alors oui, c'est bien le virtual mode que je vais utiliser. Par contre ATTENTION avec l'exemple données dans MSDN car si on exécute la ligne de code ci dessous les temps de traitement devienne TRÈS long.
    Me
    .dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells

    Pour preuve :

      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load<br/>
        Me.DataGridView1.VirtualMode = True<br/>
        For CptCol As Int16 = 1 To 10<br/>
          Dim NewCol As DataGridViewTextBoxColumn<br/>
          NewCol = New DataGridViewTextBoxColumn()<br/>
          Me.DataGridView1.Columns.Add(NewCol)<br/>
        Next<br/>
        Dim DureeAjout As DateTime = Now<br/>
        Me.DataGridView1.RowCount = 100000<br/>
        MsgBox("Durée de l'ajout : " & DateDiff(DateInterval.Second, DureeAjout, Now) & " sec")<br/>
      End Sub
    

    Affiche 0 secondes.

    Alors que :

      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Me.DataGridView1.VirtualMode = True
        For CptCol As Int16 = 1 To 10
          Dim NewCol As DataGridViewTextBoxColumn
          NewCol = New DataGridViewTextBoxColumn()
          Me.DataGridView1.Columns.Add(NewCol)
        Next
        DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
        RemoveHandler DataGridView1.CellValueNeeded, AddressOf dataGridView1_CellValueNeeded<br/>
        Dim DureeAjout As DateTime = Now<br/>
        Me.DataGridView1.RowCount = 100000<br/>
        MsgBox("Durée de l'ajout : " & DateDiff(DateInterval.Second, DureeAjout, Now) & " sec")<br/>
        AddHandler DataGridView1.CellValueNeeded, AddressOf dataGridView1_CellValueNeeded<br/>
      End Sub
    
    Affiche 13 secondes !!! (la puissance de la machine executant ce code peut évidament faire varié ces temps de traitement ;))

    De plus si cette même ligne est active toute les ligne seront interroger (par le biais de l'événement CellValueNeeded). Vous noterez quand même que j'ai désactiver cette événement la durée de l'ajout (ce qui devrais accélérer mon traitement, dans la réalité ce n'est pas forcément vrais)

    En conclusion :

    Cette ligne de code est à proscrire pour avoir un temps d'exécution valable :

    Me
    .dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells

    Je met à jour le code que j'ai posté plus haut en utilisant le Virtual mode (histoire que ceux qui voudront faire le même chose que moi est un exemple complet et valable ;)


    :) Amicalement :)
    vendredi 21 janvier 2011 13:32
  • Ok et merci du retour... A+ peut-être.
    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    vendredi 21 janvier 2011 13:56
    Modérateur
  • Re-bonjour,

    Merci à Patrice Scribe sans qui je ne me serais pas pencher sur le virtual mode tout de suite :).

    Voila un code qui fonctionne :

    Public Class Form1
      Private Class DonneesPourThread
        Public NombreDePage As Integer
        Public NombreDeLigneParPage As Integer
      End Class
    
      Private ThreadRempli As System.Threading.Thread
      Private WithEvents TableDonnees As DataTable
      Private Delegate Sub Delegate_DataGridView1_RowCount(ByVal NewRowsCount As Integer)
      Private Delegate Sub Delegate_DataGridView1_Colums_Add(ByRef Colonne As DataGridViewColumn)
    
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        'Juste pour que le DataGridView remplisse tout le form ;)
        DataGridView1.Dock = DockStyle.Fill
        'Active le mode virtuelle
        DataGridView1.VirtualMode = True
    
        'Préparation du thread
        ThreadRempli = New System.Threading.Thread(AddressOf SubThreadRemplisage)
        ThreadRempli.IsBackground = True 'Permet au system de tué le thread quand le conteneur se termine 
    
        'Prepare les infos pour le thread
        Dim InfoThread As New DonneesPourThread
        InfoThread.NombreDeLigneParPage = 1000
        InfoThread.NombreDePage = 100
    
        'Lance le thread
        ThreadRempli.Start(InfoThread)
      End Sub
    
      Private Sub SubThreadRemplisage(ByVal Info As DonneesPourThread)
    
        'Prépare la table recevant les données
        TableDonnees = New DataTable("Table de données")
        TableDonnees.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TableDonnees.Columns.Add("Donnée", System.Type.GetType("System.String"))
        'Remarque :
        'En base de données, on peut executer la requete :
        'RequeteAExecuter = "SELECT * FROM (" & RequeteReel & ") a WHERE 1 = 0"
        'Ainsi on ne récupére que les colonnes et aucune données (ce qui peut être pratique ;))
    
        'On ajoute un colonne pour chaque colonne de la table
        '/!\ Ici seul des colonne de type textbox sont ajouter (il faudras tester le type de colonne de la table pour ajouter' d'autre type de colonne, tél que DataGridViewCheckBoxColumn par exemple
        For Each ColonneTable As DataColumn In TableDonnees.Columns
          Dim NewDataGridViewColumn As New DataGridViewTextBoxColumn()
          NewDataGridViewColumn.Name = ColonneTable.ColumnName
          NewDataGridViewColumn.HeaderText = ColonneTable.ColumnName
          Invoke(New Delegate_DataGridView1_Colums_Add(AddressOf DataGridView1_Colums_Add), NewDataGridViewColumn)
        Next
        'On lit les pages de données
        For CompteurPage As Integer = 1 To Info.NombreDePage
          Dim TablePage As DataTable = GetPageDonnees(Info.NombreDeLigneParPage)
          'Evite que plusieurs threads accèdent à cette objet en même temps
          SyncLock TableDonnees
            TableDonnees.Merge(TablePage)
          End SyncLock
          If DataGridView1.AllowUserToAddRows Then
            Invoke(New Delegate_DataGridView1_RowCount(AddressOf DataGridView1_RowCount), TableDonnees.Rows.Count + 1)
          Else
            Invoke(New Delegate_DataGridView1_RowCount(AddressOf DataGridView1_RowCount), TableDonnees.Rows.Count)
          End If
        Next
      End Sub
    
      Private Function GetPageDonnees(ByVal NombreLigneParPage As Integer) As DataTable
        'Prépare la table contenant la page de données
        Dim TablePage As New DataTable("Page de données lut en base de données")
        TablePage.Columns.Add("Id", System.Type.GetType("System.Int32"))
        TablePage.Columns.Add("Donnée", System.Type.GetType("System.String"))
        'Sumule une attente de donnée du serveur (3 secondes)
        System.Threading.Thread.Sleep(3000)
        For Compteur As Integer = 1 To NombreLigneParPage
          Dim Ligne As DataRow = TablePage.NewRow
          Ligne.Item(0) = TablePage.Rows.Count + TableDonnees.Rows.Count + 1
          Ligne.Item(1) = "Donnée de la ligne : " & Ligne.Item(0)
          TablePage.Rows.Add(Ligne)
        Next
    
        Return TablePage
      End Function
    
      Private Sub DataGridView1_RowCount(ByVal NewRowsCount As Integer)
        DataGridView1.RowCount = NewRowsCount
      End Sub
    
      Private Sub DataGridView1_Colums_Add(ByRef Colonne As DataGridViewColumn)
        DataGridView1.Columns.Add(Colonne)
      End Sub
    
      Private Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
        'Si l'ajout est autorisé
        If DataGridView1.AllowUserToAddRows Then
          'Si cette ligne est la ligne d'ajout
          If e.RowIndex = Me.DataGridView1.RowCount - 1 Then
            'On sort de la fonction
            Return
          End If
        End If
        SyncLock TableDonnees
          e.Value = TableDonnees.Rows(e.RowIndex).Item(e.ColumnIndex)
        End SyncLock
      End Sub
    End Class
    
    Comme dans le 1ér code il faut simplement mettre un DataGridView sur un form (Form1) d'une nouvelle application et mettre le code ci-dessous dans le code de cette form :

    Tout n'est pas fait dans ce code, seul l'affichage de texte est fait (pas d'ajout, de suppression, modification, de données, ni de colonne de type ChekBox ou autre). Mais bon je pense que sa reste un bonne exemple ;). Pour faire le reste il faut se référer à la rubrique d'aide fournis par Patrice Scribe : http://msdn.microsoft.com/fr-fr/library/ms171622.aspx

    Voili voilou ^^


    :) Amicalement :)
    • Marqué comme réponse Polack77 vendredi 21 janvier 2011 14:33
    • Modifié Polack77 vendredi 21 janvier 2011 14:47 Mauvaise mise en page du code (sa deviens énervant mnt :( )
    vendredi 21 janvier 2011 14:33