Comment ajouter des milliers d'éléments à une collection liée sans verrouiller l'interface graphique
J'ai une configuration où potentiellement des milliers d'articles (pensez à 3000-5000) seront ajoutés à un ObservableCollection
qui est lié à certains interface visuelle. Actuellement, le processus d'ajout d'eux est assez lent (env. 4 secondes/1000 articles), et bien sûr, l'interface graphique ne répond pas pendant ce temps. Ce qui est une bonne méthode pour gérer le déplacement que de nombreux éléments à la fois dans une collection sans se préoccuper du système de verrouillage? J'ai regardé DispatcherTimer
mais je ne sais pas si il va fournir tout ce dont j'ai besoin.
Une autre question - Est-il quelque chose que je peux faire pour accélérer la création de ces objets, afin de ne pas prendre tant de temps pour les ajouter à la collection? Actuellement, je utiliser de la sorte: Collection.Add(new Item(<params>))
Serait de générer les éléments à l'avance, dans un thread d'arrière-plan sans doute, de diminuer le temps nécessaire à l'ajout d'une quantité notable?
Edit: la Virtualisation n'est pas possible. Les exigences de spécifier un WrapPanel
regard, de sorte que l'écran est en fait un ListBox
qui est basé sur un modèle ItemsPanel
Edit2: Selon le chronomètre, le goulot d'étranglement est en fait de mettre des objets dans mon ObservableCollection
. Je vais essayer de changer ce type de collection et de faire de mon propre notification, afin de voir si les vitesses il considérablement.
Edit3: la réponse est Donc dans un même endroit, j'ai résolu ce problème (avec l'aide de ci-dessous) par la création d'une classe qui hérite de ObservableCollection
. Cette classe a deux choses - exposer une méthode pour ajouter des collections à la fois, et ajouté la possibilité de supprimer le CollectionChanged
Événement. Avec ces changements, le temps qu'il faut pour ajouter 3000 articles est à peu près .4 secondes (97% d'amélioration). Cette lien détails de la mise en œuvre de ces changements.
source d'informationauteur steveg89
Vous devez vous connecter pour publier un commentaire.
Vous l'ai dit 1000, donc je vais m'en tenir à ce nombre juste pour l'exemple.
IIRC, de la collection observable a un petit inconvénient: si vous ajoutez les éléments un par un, il soulève informe une fois par chaque élément. Cela signifie que vous avez 1000 notifications pour 1000 des éléments et le thread de l'INTERFACE utilisateur sera mortelle de vitesse, juste pour garder avec redessiner l'écran.
Avez-vous besoin de redessiner le plus vite possible? Peut-être que vous pouvez traiter les ajouts? Diviser le 1000 des éléments dans les quelques paniers de 100 éléments, ou un peu plus de paquets de 50 ou 20 éléments. Alors, au lieu de mettre tous les éléments un par un, les mettre dans des paquets. Mais attention: vous devez utiliser des méthodes comme la AddRange mis en œuvre par la collection elle-même, pas par LINQ, sinon tu va encore, un-à-un à l'insertion. Si vous trouvez ce genre de méthode, il est nécessaire de réduire le nombre d'événements de manière significative, car la collection devrait soulever l'événement a Changé qu'une seule fois par AddRange appel.
Si collection observable n'a pas AddRange, soit utiliser une collection différente, ou écrire votre propre, juste un wrapper sera probablement suffisant. L'objectif est de ne PAS soulever un événement a Changé à chaque Add(), mais après un nombre raisonnable d'entre eux, ou peut-être juste de sauter de sensibilisation Changé lorsque des éléments sont ajoutés et d'élever Changé à certains intervalles de temps réguliers? Ce serait bénéfique surtout, si vos données "flux" indéfiniment à un taux constant.
Bien sûr, au fait que le nombre d'articles à venir sur l'écran, vous pouvez tout aussi bien être tenue au rendu de lui-même. Si votre ItemTemplates sont compliquées, un 1000 fois 1000 objets d'instances de visual calques/propriétés peuvent tout simplement tuer l'expérience de l'utilisateur. Avez-vous simplifié la ItemTemplates au strict minimum?
Dernière chose: pensez à utiliser la virtualisation StackPanels comme le ItemPanels dans votre ItemsControl/zones de liste. Cela peut réduire considérablement l'empreinte mémoire et le nombre d'éléments dessinés à un seul point du temps. Cela ne l'aidera pas nécessairement dans le nombre ou les événements déclenchés, mais il peut aider beaucoup quand vous avez des complexes modèles d'élément!
Edit: vous utilisez ObservableCollection, donc j'ai supposé WPF/Silverlight.. mise à jour de la question de savoir si ce n'est pas correct
WPF
Binding
prend en charge l'accès simultané pour cette raison. Essayez de définirLiaison.IsAsync
de vrai. En outre.ObservableCollection<T>
il est lent pour cela, car chaque fois qu'un élément est ajouté, il déclenche des événements. Utiliser quelque chose de plus commeList<T>
et augmenter votre notification de modification de propriété après tous vos articles sont ajoutés.Une autre chose que vous pouvez essayer: sous-classe ObservableCollection et la faire soutenir le chargement en vrac (AddRange). Voici un article:
AddRange et ObservableCollection
À la demande, voici comment j'ai résolu ce problème. J'ai commencé par créer une classe qui hérite de
ObservableCollection
. Cette classe a deux choses - exposer une méthode pour ajouter des collections entières à la fois, et ajouté la possibilité de supprimer leCollectionChanged
Événement. Avec ces changements, le temps qu'il faut pour ajouter 3000 articles est à peu près .4 secondes (97% d'amélioration). Cette lien détails de la mise en œuvre de ces changements.pour la deuxième question
si dans votre interface utilisateur graphique vous sont l'utilisation de WPF technologie, vous pouvez augmenter les performances à l'aide de VirualizingStackPanel vous permettant de créer des éléments visibles uniquement