Streaming & # 8221; les résultats à un DataGridView à partir d'un BackgroundWorker

StackOverflow https://stackoverflow.com/questions/252955

  •  05-07-2019
  •  | 
  •  

Question

Existe-t-il un moyen de "diffuser" " un ensemble de résultats (par exemple, un DataTable) d'un BackgroundWorker à un DataGridView. Ce que je veux faire, c'est interroger les données et les renseigner dans un DataGridView au fur et à mesure qu'elles arrivent (comme les résultats de la grille de requête dans SQL Server Management Studio). Ma première pensée a été d'utiliser BackgroundWorker (pour éviter l'effet de gel de l'interface utilisateur), mais il y aurait toujours un "retard" perceptible. lorsque BackgroundWorker charge les résultats.

Quelle serait la meilleure façon de s'y prendre?

Était-ce utile?

La solution

Vous pourriez:

Liez le DataGridView à un DataTable initialement vide.

Ensuite, dans votre thread de travail, utilisez une collection sécurisée pour le thread (une file d'attente synchronisée par exemple) et appelez Control.BeginInvoke pour transmettre les informations d'enregistrement au thread de l'interface utilisateur.

Dans le fil de l'interface utilisateur, vous extrayez des éléments de la file d'attente et ajoutez les lignes correspondantes au DataTable. Grâce à la magie de la liaison de données, celles-ci seraient ajoutées à gridview.

Cependant, en utilisant le multithreading, vous rendez immédiatement votre programme beaucoup plus susceptible d’être rompu! Je n'ai pas essayé ce schéma spécifique, et je ne sais pas si GridView serait rendu effectivement inutilisable pendant l'ajout d'éléments. J'ai peuplé une arborescence en multithreading, et c'est vraiment un effet cool. Cependant, j’ai fini par désactiver la fonctionnalité, car elle introduisait des bogues car elle n’était pas une implémentation totalement correcte, qui traitait de toutes les interactions possibles entre utilisateurs.

Autres conseils

J'ai essayé et procédé ainsi. L’application et l’architecture ont été réalisées avant mon arrivée dans l’entreprise, et ce que j’ai fait a été faite "paginée". et asynchrone.

Ils avaient une procédure stockée qui contenait déjà la pagination ... alors ce que j’ai fait est, à la première demande, de renvoyer le "taille". du total des résultats (avec les données de la page1).

Du côté du client, j'ai ajouté des lignes vides à un DataTable ... (vide, sauf pour le champ "RowNumber").

Sur d'autres pages de données (qui ont été reçues en asynchrone), j'obtiendrais les lignes [X], elles sont définies comme suit: "ItemArray". au nouveau tableau, et mettre à jour ma grille. Exemple:

myDataGridView.Rows[rowNumber].SetValues(valuesFromNewPage);

Cela fonctionne beaucoup mieux si vous n’avez qu’un seul thread capable de modifier la collection sous-jacente. J'ai un fichier DGV en lecture seule, de sorte que le seul moyen d'ajouter / de supprimer des lignes est de manipuler le BindingSource sous-jacent. J'ai un fil de synchronisation qui ajoute / supprime des éléments du BindingSource à intervalles réguliers.

Je devais faire un "rusé" chose - si l'élément en cours de mise à jour est l'élément sélectionné, vous ne pouvez pas simplement dire

myBindingSource[n] = newItem;

mais vous devez plutôt copier en profondeur les valeurs du nouvel élément dans l'existant. Sinon, vous déclencherez un " modifié " événement, qui redessinera tout ce qui est lié à votre source de données. J'ai eu un scintillement perceptible lorsque j'ai fait la copie de référence, et le passage en copie profonde (uniquement pour l'élément En cours) l'a corrigé.

Bien sûr, si vous laissez l’utilisateur bricoler avec les données directement à partir du formulaire, plutôt que de l’utiliser comme une vue en lecture seule, vous ouvrez une toute nouvelle (vilaine!) boîte de Pandore.

Si le processus prend 2 secondes ou moins, un message "occupé" apparaît alors. curseur et faire la mise à jour en ligne. Il y a deux raisons à cela:

  • Une personne qui commence une opération qui ne va prendre que quelques secondes se trouvera toujours dans la zone "ciblée". mode de pensée au moment où l'opération est terminée. Inconsciemment, il attend toujours les résultats de son action et n'a pas encore déconnecté son cerveau conscient de ce foyer particulier (tant que l'application affiche le signal "occupé").

  • Compte tenu de ce qui précède, je ne pense pas que la surcharge cognitive du multi-threading, avec tous les dangers qui y sont associés, vaille la peine d'être encourue.

Si le processus prend jusqu'à 5 secondes, je voudrais d'abord me concentrer sur une réduction à 2 secondes ou moins. Encore une fois, il est généralement beaucoup plus facile de se concentrer sur l'amélioration des performances (par exemple, en utilisant la pagination dans le code SQL) que sur l'introduction du multi-threading. Même avec le type BackgroundWorker , les interactions non séquentielles impliquées dans le multi-threading restent difficiles à analyser et à sécuriser.

Si vous constatez qu’il n’ya aucun moyen de réduire le délai à 2 secondes ou moins, vous pouvez utiliser une technique similaire à celle recommandée par confuzatron. Mais même dans ce cas, vous voudrez peut-être montrer un dialogue de progression à l'utilisateur final, car il va choisir un contexte après plus de 2 secondes d'attente. Le dialogue de progression lui fournit des informations faciles à assimiler sur le moment où il peut revenir à se concentrer sur votre contexte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top