12
votes

Est-ce que Windows Forms DataGridView implémente un vrai mode virtuel?

J'ai une table SQL contenant actuellement 1 million de lignes qui augmentera dans le temps.

Il existe une exigence d'utilisateur spécifique de présenter une grille de tri qui affiche toutes les lignes sans pagination. L'utilisateur s'attend à pouvoir sauter très rapidement de la ligne à la rangée et de haut en bas en utilisant la barre de défilement. P>

Je connais des grilles "Mode virtuel" qui ne présentent qu'un sous-ensemble visible des données globales. Ils peuvent fournir une excellente performance d'interface utilisateur et des exigences de mémoire minimales, (j'ai même mis en œuvre une application à l'aide de cette technique il y a de nombreuses années). P>

Le fichier Windows Forms DataGridView fournit un mode virtuel qui semble être la réponse. . Cependant, contrairement à d'autres modes virtuels que j'ai rencontrés, il attribue toujours la mémoire pour chaque rangée (confirmée dans ProcessExplorer). De toute évidence, cela provoque une utilisation globale de la mémoire d'augmenter inutilement et, tout en affectant ces lignes, il existe un délai notable. Les performances de défilement souffrent également de 1 million + rangées. P>

Un vrai mode virtuel n'aurait pas besoin d'allouer une mémoire pour les lignes non affichées. Vous venez de lui donner le nombre total de lignes (par exemple, 1 000 000) et toute la grille fait l'échelle de la barre de défilement en conséquence. Lorsqu'il est affiché pour la première fois, la grille demande simplement des données les premières lignes visibles (disons 30) uniquement, l'affichage instantané. P>

Lorsque l'utilisateur fait défiler la grille, un décalage de ligne simple et le nombre de lignes visibles sont fourni et peut être utilisé pour récupérer des données à partir du magasin de données. P>

Voici un exemple du code DataGridView J'utilise actuellement: P>

public void AddVirtualRows(int rowCount)
{
    dataGridList.ColumnCount = 4;


    dataGridList.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
    dataGridList.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

    dataGridList.VirtualMode = true;

    dataGridList.RowCount = rowCount;

    dataGridList.CellValueNeeded += new DataGridViewCellValueEventHandler(dataGridList_CellValueNeeded);


}
void dataGridList_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    e.Value = e.RowIndex;
}


0 commentaires

4 Réponses :



1
votes

La réponse est non

Voir le premier commentaire ici

Si quelqu'un sait une meilleure façon, veuillez nous dire


2 commentaires

Je pense que le lien indique la version la plus récente et le commentaire n'est pas visible là-bas. Est-ce le commentaire qui commence "Cet exemple ne semble pas fonctionner avec .NET 4.0"?


Je ne sais plus, mais je suppose que c'était ".NET Framework 3.0" Notions "Visual Studio 2010" est également intéressant



17
votes

Nous venons d'avoir une exigence similaire de pouvoir afficher des tables de rangée 1M + de 1 m + arbitraires dans notre application avec des performances "très bonnes", à l'aide du stock dataGridView . Au début, je pensais que ce n'était pas possible, mais avec suffisamment de têtes, nous avons proposé quelque chose qui fonctionne très bien après avoir passé des jours à verser sur le réflecteur et le profileur .NET. C'était difficile à faire, mais les résultats valaient la peine.

La façon dont nous avons abordé ce problème consistait à créer une classe qui implémente iTypedlist et ibindinglist (vous pouvez l'appeler largetableview , par exemple) Pour gérer la récupération asynchrone et la mise en cache des informations de la base de données. Nous avons également créé une catégorie de biens immobiliers (E.G. LargeBablecolumnDescriptor ) pour extraire des données de chaque colonne.

lorsque la propriété datagridview.datasource est définie sur une classe implémentation de la classe ibindinglist , il passe dans un mode pseudo-virtuel qui diffère de régular VirtualMode, où, comme lorsque chaque ligne est peinte (comme lorsque l'utilisateur défile), le DataGridView accède à l'indexer [] sur le ibindinglist et dans les méthodes getValue sur chaque colonne PropertyDescriptor Pour récupérer les valeurs si nécessaire. L'événement CellValuenéededed (CODE> n'est pas soulevé. Dans notre cas, nous accédons à la base de données lorsque l'indexeur est accessible, puis cache la valeur, de sorte que les re-peintures suivantes ne frappent pas la base de données.

J'ai effectué des tests similaires Re: Utilisation de la mémoire. Le DataGridView attribue un tableau qui correspond à la taille de la liste (lignes I.E. 1M), mais chaque élément de la matrice références initialement un seul DataGridViewOWOWROW, donc l'utilisation de la mémoire est acceptable. Je ne sais pas si le comportement est identique lorsque VirtualMode est vrai. nous avons pu éliminer le retard de défilement en retournant immédiatement string.empty dans la méthode getvalue si la ligne n'est pas mise en cache, puis effectuez la base de données interrogez asynchroneusement. Lorsque la demande ASYNC est terminée, vous pouvez augmenter l'événement ibindinglist.listchanged sur le signal sur DataGridView qu'il doit repeindre les cellules, sauf la lecture de ce temps à partir du cache qui est facilement disponible. De cette façon, l'interface utilisateur n'est jamais bloquée en attente des appels de base de données.

Une chose que nous avons remarquée, c'est que la performance est significativement meilleure si vous définissez la source de données ou le nombre de lignes virtuelles avant Ajout du dataGridView au formulaire - il a coupé l'heure d'initialisation en deux. En outre, assurez-vous de disposer de l'autosisation de la ligne et de la colonne définie sur Aucun ou d'autre, vous aurez des problèmes de performance supplémentaires.

Note latérale: La façon dont nous avons accompli une "chargement" une telle grande table dans notre application .NET était en créant une table temporaire sur le serveur SQL qui a répertorié les touches principales de l'ordre de tri souhaité avec une identité ( numéro de ligne), puis persistant la connexion des demandes de lignes ultérieures. Cela prend naturellement du temps pour initialiser (environ 3-5s sur un serveur SQL raisonnablement rapide), mais sans connaissance des index disponibles, nous n'avons aucune meilleure alternative. Ensuite, dans notre implémentation iTypedList, nous demandons des lignes dans des pages de 100 lignes, où la 50ème rangée est la rangée qui est peinte, de sorte que nous limitons le nombre de requêtes effectuées chaque fois que l'indexeur est accessible et que nous donnons l'apparence d'avoir toutes les données disponibles dans notre application.

Lecture ultérieure:

http://msdn.microsoft.com/en-us/library/ MS404298.aspx

http://msdn.microsoft.com/fr- US / Bibliothèque / System.componentModel.ibindingList.aspx


2 commentaires

J'ai essayé de reproduire la mise en œuvre que vous décrivez, mais j'ai frappé plusieurs problèmes. 1) Quand j'ai défini Grid.DataSource à ma liaison, il demande le comte et toutes les entités immédiatement 2) Je ne pouvais pas réussir les appels à l'indexeur tandis que les données sont toujours récupérées 3) Invalidation du cache lorsque le mandat est modifié, Whild Data est toujours récupéré. Renvoi des résultats escaliers


Essayez de retourner un nombre de 0 si vous n'avez pas encore terminé l'arrière-plan. Si vous souhaitez m'envoyer une partie de votre code, je serais heureux de jeter un coup d'œil.



0
votes

Je dirais oui ... Tant que vous vous en tenez à des événements déclenchés par le comportement de mode virtuel (par exemple Cellvaluiséeded) et que vous prenez bien soin de nettoyer votre tampon intégré à la main. J'ai déjà affiché une grande quantité de données, plus de 1 m sans fausse.

Je suis un peu curieux de la mise en œuvre de Kevin McCormick à l'aide d'une source de données basée sur ITypedList ou de toute implémentation d'interface associée iList. Je suppose que c'est tout simplement une autre couche d'abstraction qui permet d'utiliser un tampon interne et transparent en plus de laisser l'utilisateur ou le développeur pouvant pouvoir utiliser la DataGridView avec cela, mais toujours en interne avec le Native VirtualMode pour afficher les informations que vous avez chargées dans le tampon.

Outre la manière de la mode de contournement du mode virtuel, à moi, le seul problème difficile restant avec la DataGridView est la limitation de la rangée: c'est toujours un int32.max. Il est probablement due à l'héritage du système de dessin Winforms ... Tout comme les images ou même tous les membres de la taille, la largeur, la hauteur des commandes WinForm ... Pourquoi ne pas coller à un type UINT32?

Je suppose que personne n'a vu un contrôle ou une image avec des dimensions négatives, mais le type n'est toujours pas approprié au contexte d'utilisation.

Voir ma réponse là-bas ci-dessous, pourrait vous aider si vous êtes toujours coincé avec ce problème, événement si, je suppose que cela est déjà résolu depuis des siècles maintenant. https://stackoverflow.com/a/16373108/1906567


0 commentaires