Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 2019
-
18 janv. 2011 à 11:52
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 2019
-
21 janv. 2011 à 15:43
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
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo
Polack77
Messages postés1098Date d'inscriptionmercredi 22 mars 2006StatutMembreDernière intervention22 octobre 20191 21 janv. 2011 à 15:43
Bonjour,
Merci à Patrice Scribe sur le forum MSDN sans qui je ne me serais pas pencher sur le virtual mode tout de suite .
Voila un code qui fonctionne : Comme dans le 1ér code il faut simplement mettre un DataGridView (DataGridView1) sur un form (Form1) d'une nouvelle application et mettre le code ci-dessous dans le code de cette form :
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 faudra 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
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 que Patrice Scribe m'a indiquer : http://msdn.microsoft.com/fr-fr/library/ms171622.aspx
Est impérativement à éviter cela provoque de TRÈS GROS ralentissement
Amicalement
1000 recherches sur Google = 1Km de voiture en CO² (réfuté par Google )
1000 recherches sur Forestle = 100 m² de forêt tropicale sauvé .
Surfez écolo