j'ai vu peu de classes l'utilisant, j'en déduis qu'elle n'apporte pas grand chose par rapport aux collections les plus usités
enfin je ne connais pas trop cette classe, ca se trouve elle a le .toarray aussi
Version imprimable
j'ai vu peu de classes l'utilisant, j'en déduis qu'elle n'apporte pas grand chose par rapport aux collections les plus usités
enfin je ne connais pas trop cette classe, ca se trouve elle a le .toarray aussi
Bonjour,
j'ai fais comme vous me l'avez conseillé (et comme le forum MSDN me l'a également conseillé) Cependant un problème demeure, mon application consomme toujours autant pour afficher les données dans la listbox. De plus, contrairement à l'ancien code tant que l'update de la listbox n'est pas terminé, les items ne sont pas visibles mais sont bien présents, la lecture des fichiers est très longue (plus 20 minutes minimum).
Voici les variables déclarées (hors sub) je ne me rappel plus du terme :
Et le code (les commentaires sont l'ancien code fonctionnel) :Code:
1
2
3 Dim ListeDeSiteCaracteresSexuels As New List(Of String) Dim ListeDeSiteContenusDangereux As New List(Of String) Dim ListeDeSiteContenusPublicitaires As New List(Of String)
Voici les captures d'écran du rapport de performance Visual Studio 2013 :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 Private Sub ChargementListeSitesInterdits() ListBoxSitesInterdits.BeginUpdate() For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteCaracteresSexuels.txt") ListeDeSiteCaracteresSexuels.Add(lLigne) ListBoxSitesInterdits.Items.AddRange(ListeDeSiteCaracteresSexuels.ToArray) Next ListBoxSitesInterdits.EndUpdate() ListBoxSitesInterdits.BeginUpdate() For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteContenusDangereux.txt") ListeDeSiteContenusDangereux.Add(lLigne) ListBoxSitesInterdits.Items.AddRange(ListeDeSiteContenusDangereux.ToArray) Next ListBoxSitesInterdits.EndUpdate() ListBoxSitesInterdits.BeginUpdate() For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteContenusPublicitaires.txt") ListeDeSiteContenusPublicitaires.Add(lLigne) ListBoxSitesInterdits.Items.AddRange(ListeDeSiteContenusPublicitaires.ToArray) Next ListBoxSitesInterdits.EndUpdate() 'For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteCaracteresSexuels.txt") ' ListBoxSitesInterdits.Items.Add(lLigne) 'Next 'For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteContenusDangereux.txt") ' ListBoxSitesInterdits.Items.Add(lLigne) 'Next 'For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteContenusPublicitaires.txt") ' ListBoxSitesInterdits.Items.Add(lLigne) 'Next End Sub
http://nsa34.casimages.com/img/2013/...5553387429.png
http://nsa33.casimages.com/img/2013/...5538413243.png
Merci de votre aide ! :ccool:
Bonjour.
Mon principal conseil avait été de ne lire qu'une fois le fichier. Ce n'est pas ce que tu fais, tu continues à mêler lecture du fichier et mise à jour de l'UI : chaque fois que tu dois mettre à jour l'UI tu lis tout ton fichier. Ecris une méthode qui remplit ListeDeSiteCaracteresSexuels et une autre méthode qui utilise cette liste pour remplir l'UI sans lire le fichier. Puis fais en sorte que la première ne soit appelée qu'une seule fois au cours de la vie de l'application, alors que la seconde le sera chaque fois qu'il faudra initialiser l'UI.
Ensuite il y a une erreur dans ton code : à chaque fois que tu ajoutes un élément à ListeDeSiteCaracteresSexuels, tu ajoutes à ton UI tous les sites chargés jusqu'ici. Autrement dit si tu lis 10k sites, tu vas ajouter 50M d'éléments à l'UI. Pas surprenant que ça prenne des siècles.
PS : tel quel le rapport de performances n'est pas pertinent. Ce qui nous intéresse c'est l'analyse de ce qui se déroule dans la dll, or pour je ne sais quelle raison le rapport n'en fournit pas le détail. Mais de toute façon le rapport ne sera pas utile tant que tu n'auras pas dissocié lecture du fichier et maj de l'UI puisqu'on ne pourra pas savoir laquelle de ces deux tâches pose problème.
D'accord, j'ai modifié mon code afin de séparer les deux actions.
Est-ce que cela te semble correct ? :
Cependant, je précise que c'est toujours long.Code:
1
2
3
4
5
6 For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteCaracteresSexuels.txt") ListeDeSiteCaracteresSexuels.Add(lLigne) Next ListBoxSitesInterdits.BeginUpdate() ListBoxSitesInterdits.Items.AddRange(ListeDeSiteCaracteresSexuels.ToArray) ListBoxSitesInterdits.EndUpdate()
Troxsa sur le forum MSDN à proposé je cite :Tu en penses quoi ?Citation:
Pour peupler vos ListBox il serait peut-être mieux d'utiliser le DataSource ?
J'ai fait un essais avec un fichier de 50Mo cela a pris -1 minutes
Il y a du mieux, tu as notamment réparé le bogue qui te faisait ajouter plusieurs fois certains éléments à l'UI. Même s'il y a toujours un problème j'imagine que tu vois une amélioration par rapport aux précédentes versions? J'aimerais d'ailleurs savoir quel est ton nouveau temps d'exécution.
* Tu as séparé les deux activités mais tu n'as pas été jusqu'au bout de la démarche. Depuis le début le but est de faire en sorte que ton application ne lise qu'une seule fois la liste blanche et pas à chaque fois qu'elle voudra mettre à jour l'UI puisque ces listes de sites doivent être utilisées à plusieurs endroits et pas seulement pour l'UI et puisque l'UI n'est peut-être pas toujours affichée et peut sans doute être rechargée fois. Tu comprends pourquoi je veux séparer les deux et pourquoi ça peut être intéressant ? Ça n'accélérera par le premier chargement mais ça évitera les chargements suivants.
Par exemple déplace le code de lecture du fichier et la liste correspondante dans une classe statique appelée par exemple "Données". Pour écris une méthode telle que "Données.ObtenirSitesCaractèresSexuels()". La première fois qu'elle sera appelée elle chargera le fichier et stockera le résultat. La deuxième fois elle retournera directement ce résultat.
En C# ça donnerait:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 Class Données Public Shared ReadOnly Property ApplicationDataPath() As String Get Return Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) End Get End Property Private Shared _sitesCaractèresSexuels As [String]() Public Shared ReadOnly Property SitesCaractèresSexuels() As [String]() Get If _sitesCaractèresSexuels Is Nothing Then Dim chemin = System.IO.Path.Combine(ApplicationDataPath, "Documents\ListeDeSiteCaracteresSexuels.txt") _sitesCaractèresSexuels = File.ReadAllLines(chemin) End If Return sitesCaractèresSexuels End Get End Property End Class
* Une fois que tes deux activités sont bien séparées, que le code UI est dans une méthode et le code de chargement dans une propriété, l'utilisation du profileur permettra de savoir laquelle de ces deux étapes prend du temps. Est-ce le chargement du fichier ou ou la mise à jour de l'UI ? Si tu ne parviens pas à faire fonctionner correctement le profileur, vois-tu une amélioration en continuant à lire le fichier mais sans mettre à jour l'UI ?
* Au passage note l'utilisation de Environment pour déterminer le bon chemin d'accès. Ta méthode actuelle aurait échoué sur certaines versions de Windows.
* Enfin je n'ai pas fait de Winforms depuis longtemps mais je doute que le passage par DataSource change quoi que ce soit, au contraire. Mais dans le doute c'est rapide à tester.
Bonjour DonQuiche,
je ne comprends pas pourquoi crée une classe car je stock déjà ma liste de site dans un listofstring que j'utiliserai plus tard si besoin.
Je ne peux malheureusement te donner un temps d'exécution car c'est très long, plus de 10 minutes, je n'ai pas attendu au delà.
C'est bien la mise à jour de l'UI qui utilise le CPU car j'ai enlevé le code du begin update, j'ai juste laissé la lecture du fichier et le stockage dans la listofstring et le processeur n'est utilisé qu'à environ 3%.
A l'évidence tu as besoin de ces listes à plusieurs endroits du code qui n'ont rien à voir entre eux : le moteur chargé de filtrer les sites et l'UI. D'où ma proposition de stocker ça dans un endroit neutre. Bref, peu importe, fais comme tu veux. Mais l'essentiel est de ne pas systématiquement recharger les fichiers, de ne le faire qu'une fois durant la vie de l'application. Le chargement des fichiers et le remplissage de l'UI sont deux choses qui n'ont rien à voir entre elles et devraient être séparées.
Maintenant si c'est bien l'UI qui pose pb (on se fiche du CPU, c'est le temps qui compte : un disque dur est lent mais ne bouffe pas de CPU), alors plusieurs causes possibles :
* Tu peux avoir trop d'éléments dans ta ListBox.
* Tu as des événements qui réagissent aux additions de nouveaux éléments et consomment du temps CPU.
Si c'est bien la première cause, alors combien de lignes as-tu ? Es-tu sûr qu'il est raisonnable d'afficher autant de lignes ? Est-ce correctement utilisable par l'utilisateur ? Ne peux-tu pas trouver un meilleur système à base par exemple de champ de recherche ?
Si tu es sûr que tout afficher est la bonne chose à faire, tel quel ce contrôle ne convient pas. Je ne suis pas familier de Winforms mais il ne semble y avoir que deux choses à faire :
* Utiliser ce contrôle avec DisplayMode placé à OwnerDrawFixed. Il te faudra alors spécifier manuellement la taille de chaque élément et mettre en oeuvre ta propre logique de dessin. Je te laisse voir la doc de cette propriété.
* Ou utiliser un ListView, sans doute en mode virtuel (voir la doc de ListView.VirtualMode).
Pour ma part je testerais la seconde possibilité mais peut-être as-tu une raison de vouloir rester sur une ListBox.
Salut,
le fichier le plus gros fait exactement 873 871 lignes, je pense que la listbox n'est pas prévu pour gérer autant de lignes. Ta seconde proposition m'interpelle car c'est ce que l'on m'a conseillé sur le forum MSDN. Cependant, comme je l'ai signalé, je cite :Après, je ne suis pas contre pour changer le système de recherche, voici comment c'est fait sur mon programme (panneau de droite) :Citation:
je n'ai pas très bien compris comment utiliser le mode virtuel et surtout son réel intérêt dans mon cas. J'ai regardé en plus de la documentation MSDN cette vidéo et si j'ai bien compris je dois mettre mon code de mise à jour de la listview dans l'évènement "Retrieve Virtual Item" ?
http://nsa34.casimages.com/img/2013/...0506507663.png
Merci :ccool:
Pour ListView il existe déjà un exemple dans la doc officielle et on doit en trouver des milliers d'autres sur le web, je ne vais pas en rajouter un.
Maintenant il ne sert à rien d'afficher une liste avec 800k éléments. Ajoute une boîte de texte et dès que l'utilisateur a tapé au moins trois caractères tu affiches les sites qui contiennent cette suite de caractères.
Est-ce que je pourrais avoir encore de l'aide pour l'utilisation du virtual mode car même en regardant des projets, je bloque :oops:
Merci.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 // Initialisation du contrôle listView1.VirtualMode = true; listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(OnRetrieveVirtualItem); ... // Après chargement du fichier listView1.VirtualListSize = sitesCaractèresSexuels.Length; ... // Handler pour RetrieveVirtualItem void OnRetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) { string site = sitesCaractèresSexuels[e.ItemIndex]; e.Item = new ListViewItem(site); }
Code en C# non-testé.
Salut,
j'ai essayé de me dépatouiller avec des projets prit sur le web et tout, j'ai un peu compris et j'en ai déduis le code suivant qui évidement ... ne marche pas :mrgreen:
J'obtiens l'erreur :
Citation:
Une exception non gérée du type 'System.InvalidOperationException' s'est produite dans System.Windows.Forms.dll
Informations supplémentaires : Lorsque le ListView est en mode virtuel, vous ne pouvez pas ajouter des éléments à la collection des éléments ListView. Utilisez plutôt la propriété VirtualListSize pour redimensionner la collection d'éléments ListView.
Qu'est-ce que je devrais faire pour que cela fonctionne ?Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 Private Sub ChargementListeSitesInterdits() For Each lLigne As String In File.ReadAllLines("C:\Users\" & System.Environment.UserName & "\Documents\ListeDeSiteCaracteresSexuels.txt") ListeDeSiteCaracteresSexuels.Add(lLigne) Next ListView1.VirtualListSize = ListeDeSiteCaracteresSexuels.Count ListView1.BeginUpdate() ListView1.Items.Add(ListeDeSiteCaracteresSexuels.ToString) ListView1.EndUpdate() End Sub Private Sub ListView1_RetrieveVirtualItem(sender As Object, e As RetrieveVirtualItemEventArgs) Handles ListView1.RetrieveVirtualItem Dim it As New ListViewItem(ListeDeSiteCaracteresSexuels(e.ItemIndex).ToString) it.SubItems.Add("This is a subitem") e.Item = it End Sub
Merci.
bonjour CLeBeR
Comme dit par Pol63 et Don Quiche,il faut separer l'action de lecture et la virtualisation du ListView ...c'est de la virtualization UI ou Affichage
Le ListView en mode virtual UI
- mets à jour l'UI uniquement(scrolling bas ou haut) pour les elements apparus dans l'affichage.
- le petit cache (array de string)que nous mettons à sa disposition par code contient ses elements...Cnsequence : la taille du cache est "manage" par ses soins...
- les bornes du cache vont de : e.StartIndex à e.EndIndex ("delta" du scrolling)...
La tache la plus delicate est d'initialiser le cache a partir de ton tableau de strings ...
Quand à SearchForVirtualItem il retrouve e.Index à partir de e.Text via ListView.Items.IndexOf(lvitem) car meme en Mode Virtual,cette collection est "peuplée" ...
Mais DataSource & ListView.Items.Add() sont prohibes...
code vb du class MyData (deja mentionne par donquiche):
code du form (tiree du Msdn Doc):Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 Imports System.IO Public Class MyData Public Shared ReadOnly Property ApplicationDataPath() As String Get Return Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData) End Get End Property Private Shared _sitesCaractèresSexuels() As String Public Shared ReadOnly Property SitesCaractèresSexuels() As String() Get If _sitesCaractèresSexuels Is Nothing Then Dim chemin = System.IO.Path.Combine(ApplicationDataPath, "Documents\ListeDeSiteCaracteresSexuels.txt") _sitesCaractèresSexuels = File.ReadAllLines(chemin) End If Return _sitesCaractèresSexuels End Get End Property End Class
bon code...Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 Public Class frmVirtualFichierTxt Private myCache() As ListViewItem 'array to cache items for the virtual list Private firstItem As Integer 'stores the index of the first item in the cache Public Sub New() ' Cet appel est requis par le concepteur. InitializeComponent() ' Ajoutez une initialisation quelconque après l'appel InitializeComponent(). MyListView.View = View.SmallIcon MyListView.VirtualMode = True MyListView.VirtualListSize = MyData.SitesCaractèresSexuels.Length MyListView.Scrollable = True '------NB:CE CODE DU SDK EST MIS EN COMMENTAIRES----------------- 'CAR IL ENTRAINERA UN DEPASSEMENT DE BORNE DE LA VIRTUALLISTSIZE 'Dim lvi As ListViewItem = MyListView.FindItemWithText("111111") ''Select the item found and scroll it into view. 'If Not (lvi Is Nothing) Then ' MyListView.SelectedIndices.Add(lvi.Index) ' MyListView.EnsureVisible(lvi.Index) 'End If End Sub Private Sub MyListView_RetrieveVirtualItem(ByVal sender As Object, ByVal e As RetrieveVirtualItemEventArgs) Handles MyListView.RetrieveVirtualItem If Not (myCache Is Nothing) AndAlso e.ItemIndex >= firstItem AndAlso e.ItemIndex < firstItem + myCache.Length Then ' Obtient l'item du cache . e.Item = myCache((e.ItemIndex - firstItem)) Else 'le cache ne contient pas l'item , on cree un nouveau ListViewItem & le renvoie à ListView. Dim s As String = MyData.SitesCaractèresSexuels(e.ItemIndex) e.Item = New ListViewItem(s) End If End Sub 'Manages the cache. Private Sub MyListView_CacheVirtualItems(ByVal sender As Object, ByVal e As CacheVirtualItemsEventArgs) Handles MyListView.CacheVirtualItems 'SI LE CACHE A ETE DEJA CREE & L'ITEM EST PRESENT ? . If Not (myCache Is Nothing) AndAlso e.StartIndex >= firstItem AndAlso e.EndIndex <= firstItem + myCache.Length Then ' rien à faire.retour. Return End If ' SINON ON LE CREE ET REMPLIT. firstItem = e.StartIndex Dim length As Integer = e.EndIndex - e.StartIndex + 1 'indexes are inclusive myCache = New ListViewItem(length) {} 'Remplir le cache avec les ListViewItems appropries. Dim s As String Dim i As Integer ' ICI LES LIMITES D'ITERATION DOIVENT ETRE APPROPRIES AU TABLEAU DE STRINGS ' DE MYDATA For i = e.StartIndex To e.EndIndex s = MyData.SitesCaractèresSexuels(i) myCache(i - e.StartIndex) = New ListViewItem(s) Next i End Sub 'This event handler enables search functionality Private Sub MyListView_SearchForVirtualItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.SearchForVirtualItemEventArgs) Handles MyListView.SearchForVirtualItem Dim item As New ListViewItem(e.Text) e.Index = MyListView.Items.IndexOf(item) End Sub End Class
@Cleber
Ce sont les trois lignes de BeginUpdate à EndUpdate qui doivent être supprimées. Le principe de la virtualisation est de ne pas ajouter les éléments mais de les fournir à la demande, seulement quand ils sont nécessaires. La seule concession est le nombre total d'éléments qui doit être fourni pour ajuster l’ascenseur de la liste.
Merci à vous deux, donc il y a du mieux. Maintenant mes données s'affichent rapidement et je peux les voir. Sauf si je mets en mode "détail" où là aucune donnée n'apparait. Je ne peux donc pas avoir de liste. De plus, il m'est difficile de récupérer l'item sélectionné.
Je pense que je vais suivre les conseils de DonQuiche et faire un système de recherche dans ma listof string qui fait apparaitre tous les mots qui contiennent les lettres de la recherche dans ma listbox.
Le problème d'affiche sera résolu comme ça. Je me renseigne et je vous fait un retour. :ccool:
Bonjour,
après réflexion, je pense qu'il est plus sage de ne pas afficher plus de 800 000 sites dans une listbox mais plus tôt de mettre un système de filtre, c'est donc chose faite :
Merci encore à vous tous et http://www.jujube-en-cuisine.fr/wp-c...2/noel2007.jpgCode:
1
2
3
4
5
6
7 If TextBoxSiteInterditPersonnalisé.TextLength < 10 Then MsgBox("Veuillez ajouter encore " & 10 - TextBoxSiteInterditPersonnalisé.TextLength & " pour lancer la recherche") Else MsgBox("Veuillez patienter, la recherche est en cours, celà peut prendre plus de deux minutes", MsgBoxStyle.Information) ListBoxSitesInterdits.Items.Clear() ListBoxSitesInterdits.Items.AddRange((From element In ListeDeSite Where element Like "*" & TextBoxSiteInterditPersonnalisé.Text & "*" Select element).ToArray) End If
Bonnes fêtes à toi aussi, heureux que ton problème soit finalement résolu. :D