C# trier une colonne d'un DataGridView à l'aide d'une listBox

Signaler
-
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
-
Bonjour,
je souhaiterai trier une colonne d'une datagridview en fonction de son contenu, ce qu'il me faudrait en particulier c'est le fait que la listbox détecte les différentes possibilités et me les affiches puis laisse apparaître le contenu du datagridview en fonction de la listbox



Configuration: Windows / Chrome 84.0.4147.89

16 réponses

Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Bonjour

Comment est alimenté le datagridview?
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Bonjour whismeril, j'ai déja eu affaire à ton aide (je reviens à peine sur mon projet), tu m'avais fournis un exemple qui me permettais de filtrer une colonne grâce à la listbox en question.

Mon datagridview est remplis à l'aide d'une list remplis au préalable par une classe qui parse mes logs

voici l'exemple
j'aimerai filtrer comme ça sur d'autre colonne pour limiter l'affichage je mettais tourner vers l'advancedDatagridview qui fournis un systèmes de filtres cependant il ne fonctionne pas
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
J’ai reparcouru rapidement la discussion précédente.
As tu choisi de filtrer avant de charger les fichiers ou après ?
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

J'ai choisi de filtrer après je sais si je peux filtrer avant étant donner que je ne sais pas ce que je vais récupérer
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
En fait tu pourrais faire un pré traitement à partir du quel générer tes filtres.
Ça pourrait même ne pas être plus beaucoup long à l’exécution.
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

C'est à dire ; (genre récupérer les éventuels filtres puis faire le traitement une fois les filtres choisis ?)
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Finalement j'ai réussi a faire le tri avec plusieurs listbox, je réduis drastiquement l'affichage dans mon datagridview, j'aimerai savoir si une pagination en plus de ces filtres était possible (limiter à 100 lignes)et si les filtres pouvais ce combiner ?

Exemple:


On a bien Agv::Execution et N_DEFAUT (car il n'y a que lui) mais pour ce qui est de PLC_RDK et bien il ce transforme en AGVn°6
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Oui au deux questions.

Tu peux faire un traitement rapide pour récupérer les données uniques de chaque colonne qui peut filtrer et ensuite ne charger que les lignes adéquates.

Pour n’avoir que 100 lignes à chaque d’affichées, tu peux te servir des méthodes skip et take de la list<t> que tu auras par exemple remplies à l’aide d’une scrollbar
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Je ne vois pas trop comment me lancer dans un traitement rapide...

Ton option ne me permettra pas de naviguer comme un livre par exemple ?
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
En repartant de ça

        private void ChargerFichier()
        {
            string[] lignes = File.ReadAllLines("LogisticCore300120.log");//chaaque ligne est chagée dans un emplacement de tableau

            foreach(string l in lignes)//on itère le tableau pour créer la liste de logs
            {
                Log leLog = Log.Parse(l);
                if (leLog != null)
                    lesLogs.Add(leLog);
                else
                    File.AppendAllText("LignesEnErreur.txt", l);//écrit les lignes rejétées dans le fichier LignesEnErreur.txt
            }

            lesLogs = lesLogs.OrderBy(x => x.Datation).ToList();
        }



J'ai fait un test vite fait.
Sur le formulaire, j'ai ajouté 2 listbox et un bouton
J'ai modifié le code au dessus:
        List<Log> lesLogs = new List<Log>();//liste de tous les logs

        string[] lignes;
        List<string> filtreModule = new List<string>();
        List<string> filtreType = new List<string>();

        private void ChargerFiltres()
        {
            lignes = File.ReadAllLines("LogisticCore300120.log");//chaque ligne est chagée dans un emplacement de tableau

            filtreModule.Clear();
            filtreType.Clear();

            foreach (string l in lignes)
            {
                string[] valeurs = l.Split('\t');//pour bien faire il faudrait utiliser la regex
                if (l.Length < 3)
                    continue;

                if (!filtreModule.Contains(valeurs[1]))
                    filtreModule.Add(valeurs[1]);

                if (!filtreType.Contains(valeurs[2]))
                    filtreType.Add(valeurs[2]);
            }
            //on peut peut-être optimiser le temps de chargement des filtres

            lstModule.DataSource = filtreModule;//listbox pour les modules
            lstType.DataSource = filtreType;//listbox pour les Types
        }

        private void ChargerFichier(string[] filtres)
        { 
            foreach (string l in lignes)//on itère le tableau pour créer la liste de logs
            {
                bool ok = true;//si ça reste ok, on garde la ligne
                foreach(string f in filtres)
                {
                    if(!l.Contains(f))
                    {
                        ok = false;
                        break;
                    }
                }

                if (!ok)
                    continue;

                Log leLog = Log.Parse(l);
                if (leLog != null)
                    lesLogs.Add(leLog);
                else
                    File.AppendAllText("LignesEnErreur.txt", l);//écrit les lignes rejétées dans le fichier LignesEnErreur.txt
            }

            lesLogs = lesLogs.OrderBy(x => x.Datation).ToList();
        }



Et pour le bouton
        private void button1_Click(object sender, EventArgs e)
        {
            ChargerFichier(new[] { lstModule.Text, lstType.Text });
            dgwLog.DataSource = null;
            dgwLog.DataSource = lesLogs;

        }


Les filtres sont un peu longs à charger, je dois pouvoir faire mieux, mais pas ce soir
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Je suis un peu perdu étant donné que j'ai pas mal modifier le début pour trier, je ne vois pas trop quand appeler ChargerFiltres, quand je fais chargerfichier il me remontre l'erreur suivante :


en re testant avec tes fonctions je me rends compte que ma regex n'est pas passer alors que sur le même fichier celle-ci fonctionne
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Oui, regarde à la ligne 3, j’ai mis la déclaration de lignes plus global de façon à ne le charger qu’une fois
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Ouais mais je vois pas trop quand on appel ChargerFiltres
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Là oú avant tu appelais chargerfichier
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Par contre, dans cet exemple vite fait on peut tomber sur des cas « impossibles »

C’est à dire que tu peux sélectionner une combinaison de filtres qui ne donnent aucun résultat.
C’est pas forcément cool pour l’utilisateur qui va faire des manips pour rien.

Une autre options serait de tout charger les logs comme avant mais sans les afficher dans le datagridview.
On se contente d’afficher une première liste de filtres (sur le module par exemple), avec le mot clé et le nombre d’occurrences.

L’utilisateur sélectionne un mot clé un bouton apparaît lui proposant de tout afficher et une liste montre les types vraiment présents pour le module sélectionné et le nombre d’occurrences etc...
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

J'avais penser a cette possibilité du coup je m'étais dit, laisser toute les occurrences possibles mais en fonctions des combinaisons mettre 0 occurrences ou bien le nombre disponible en fonction des combinaisons
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Alors,

avec un datagridview et 2 listes
On repart avec la méthode chargerFichier d'origine

        private void ChargerFichier()
        {
            string[] lignes = File.ReadAllLines("LogisticCore300120.log");//chaaque ligne est chagée dans un emplacement de tableau

            foreach(string l in lignes)//on itère le tableau pour créer la liste de logs
            {
                Log leLog = Log.Parse(l);
                if (leLog != null)
                    lesLogs.Add(leLog);
                else
                    File.AppendAllText("LignesEnErreur.txt", l);//écrit les lignes rejétées dans le fichier LignesEnErreur.txt
            }

            lesLogs = lesLogs.OrderBy(x => x.Datation).ToList();
        }


et on reprend la class logGroupe, avec un constructeur supplémentaire et un ToString personnalisé

    /// <summary>
    /// Enregsitre les regroupements de logs correspondant à un filtre
    /// </summary>
    class LogGroupe
    {
        public LogGroupe(string Cle, List<Log> LesLogs)
        {
            Key = Cle;
            Logs = LesLogs;
        }

        public LogGroupe(IGrouping<string,Log> Groupe)
        {
            Key = Groupe.Key;
            Logs = Groupe.ToList();
        }
        public string Key { get; set; }

        public List<Log> Logs { get; set; }

        public int Occurence { get { return Logs.Count; } }

        public string Text { get { return string.Format("{0,-15}\t{1,7}\toccurence(s)", Key, Occurence); } }

        public override string ToString()
        {
            return Text;
        }
    }



Les évènement SelectionChanged des 2 listBox (lstModule et lstErreur) sont abonnés à cette méthode
        private void filtre_SelectedValueChanged(object sender, EventArgs e)
        {
            dgwLog.DataSource = null;

            //On récupère la listbox
            ListBox l = (sender as ListBox);
            if (l == null)//c'est pas une listbox => problème d'abonnement
                return;

            //on récupère la valeur sélectionnée
            LogGroupe filtre = l.SelectedItem as LogGroupe;
            if (filtre == null)
                return; // c'est pas un log ou il n'y a rien de sélectionné 

            if(filtre.Key == "Tous les enregistrements") //on affiche les logs concernés dans le datagridview
            {
                dgwLog.DataSource = filtre.Logs;
                return;
            }

            if(l == lstModule)
            {
                lstErreur.DataSource = null;

                //on va faire un groupeBy, à partir de la collection groupée par module, qui permet d'obtenir les valeurs de filtres par erreur et de connaitre le nombre d'occurences
                groupementErreur = filtre.Logs.GroupBy(g => g.Erreur).Select(g => new LogGroupe(g)).ToList();

                //On insère en début de liste la possibilité d'afficher toutes les occurences
                groupementErreur.Insert(0, new LogGroupe("Tous les enregistrements", filtre.Logs));

                lstErreur.DataSource = groupementErreur;

                return;
            }

            if(l == lstErreur)
            {
                //on affiche les log groupés par erreur dans le datagridview
                dgwLog.DataSource = filtre.Logs;
            }
        }



Là où tu charges le fichier (dans le load pour moi), tu mets ce code
        List<LogGroupe> groupementModule;
        List<LogGroupe> groupementErreur;
        private void Form1_Load(object sender, EventArgs e)
        {
            lstModule.DataSource = null;
            lstErreur.DataSource = null;
            ChargerFichier();

            //on va faire un groupeBy, qui permet d'obtenir les valeurs de filtres par module et de connaitre le nombre d'occurences
            groupementModule = lesLogs.GroupBy(l => l.Module).Select(g => new LogGroupe(g)).ToList();

            //On insère en début de liste la possibilité d'afficher toutes les occurences
            groupementModule.Insert(0, new LogGroupe("Tous les enregistrements", lesLogs));

            //On binde la liste de filtres
            lstModule.DataSource = groupementModule;
        }


Au premier chargement, tous les logs sont affichés, car par défaut c'est le premier filtre qui est sélectionné dans lstModule.


Si tu choisis un filtre, alors tous les enregistrements de ce filtre s'affichent, car cette fois c'est le premier filtre de lstErreur qui est sélectionné


Si tu choisi un filtre Erreur alors seulement les occurrences correspondantes s'affichent

Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Merci beaucoup c'est super intéressant et formateur pour moi, c'est exactement ce que je recherchais, je vois que tu as chargé plus de 300 000 lignes est ce qu'une pagination de 1000 lignes ou 500 par pages permettrais d'alléger encore l'affichage ?
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Peut-être mais il faut quand même charger tout le fichier (ou se limiter à 2M lignes comme on avait vu) car sinon tu auras les occurrences de filtres sur 1000 lignes.

C’est à toi de voir.

Avec 300k lignes une fois premier affichage fait c’est très rapide.
Merci beaucoup ça ma bien aidé, je vais maintenant m'amuser sur un autre projet ;)
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Si ça te convient, pense à marquer le sujet résolu
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Finalement j'ai remarqué un soucis, quand je relance une acquisition un de mes listbox saute et deviens vide ...
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Tu pourrais être plus précis?
Messages postés
20
Date d'inscription
jeudi 9 avril 2020
Statut
Membre
Dernière intervention
20 août 2020

Je ne sais pas réellement expliquer mais je peux être amener à relancer un trie de log, une fois celui ci finis une de mes listbox deviens vide
premiere fois que je lance l'analyse

la seconde fois si c'est le même fichier
Messages postés
15086
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
14 novembre 2020
611
Bonsoir

à ChargerFichier, remplace

        List<Log> lesLogs = new List<Log>();//liste de tous les logs

        private void ChargerFichier()
        {
            string[] lignes = File.ReadAllLines("LogisticCore300120.log");//chaaque ligne est chagée dans un emplacement de tableau


par
        List<Log> lesLogs;

        private void ChargerFichier()
        {
            lesLogs = new List<Log>();//remise à zéro de la liste
            string[] lignes = File.ReadAllLines("LogisticCore300120.log");//chaaque ligne est chagée dans un emplacement de tableau