IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

Chargement d'une ListView à l'aide d'un BackgroundWorker - SQL.


Sujet :

Windows Forms

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de mathisdu42
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2013
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2013
    Messages : 168
    Par défaut Chargement d'une ListView à l'aide d'un BackgroundWorker - SQL.
    Bonjour, bonsoir à tous.

    Depuis peu de temps j'essaye d'intégrer des BackgroundWorker à mon programme pour éviter les freeze intempestifs de l'application. Actuellement j'ai une ListView qui récupère quelques 9000 lignes de ma base de données pour que le BgW soit utile et pour des tests. J'ai donc mis en place le BgW et fait fonctionné ce dernier correctement. Seulement, j'aimerais rajouter une ProgressBar pour afficher la progression du chargement de la liste, seulement, j'ai un peu de mal à la faire fonctionner.

    Voici le code :

    Lancement du formulaire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     private void userList_Load(object sender, EventArgs e)
            {
                if (!backgroundWorker1.IsBusy)
                {
     
                    metroListView1.Visible = false;
                    progressBar1.Visible = true;
                    metroLabel2.Visible = true;
                    backgroundWorker1.RunWorkerAsync();
     
                }
            }
    Le DoWork du BackgroundWorker AVEC le code de la ProgressBar que j'ai tenté d'essayer, sans succès :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    private void bgw1_DoWork(object sender, DoWorkEventArgs e)
            {
     
                try
                {
     
                    using (var cnx = new MySqlConnection("ConnectionString"))
                    {
     
                        cnx.Open();
                        var cmd = new MySqlCommand("SELECT * FROM Account", cnx);
                        using (var dr = cmd.ExecuteReader())
                        {
     
                            while (dr.Read())
                            {
                                metroListView1.Invoke((MethodInvoker)delegate
                                {
     
     
                                    ListViewItem listitem = new ListViewItem(dr["Username"].ToString());
                                    listitem.SubItems.Add(dr["Rang"].ToString());
                                    listitem.SubItems.Add(dr["Mail"].ToString());
                                    metroListView1.Items.Add(listitem);
                                });
     
     
     
                                progressBar1.Invoke((MethodInvoker)delegate
                                {
     
                                    progressBar1.Maximum = metroListView1.Items.Count;//Dt is your DataTable
                                    for (int i = 0; i < metroListView1.Items.Count; i++)
                                    {
                                        //Do Work
                                        progressBar1.Value = i + 1;
                                    }
     
                                });
     
                            }
                        }
     
                    }
                }
     
                catch (Exception ex)
                {
                    var eb = new ErreurBdd();
                    eb.ShowDialog();
                    LogException("errorLog", "Error", ex.Message + " - | " + DateTime.Now + " | Build: " + Application.ProductVersion + Environment.NewLine);
     
     
                }
            }
    Le ProgressChanged du BackgroundWorker :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    private void bgw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                progressBar1.Value = e.ProgressPercentage;
                metroLabel2.Text = string.Format("Chargement en cours, veuillez patienter...{0}%", e.ProgressPercentage);
            }

    Donc voilà, en ce qui me concerne je pense qu'il est logique que le code suivant ne fonctionne pas étant donné qu'il se situe dans la boucle "While" mais alors où le placer ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     progressBar1.Invoke((MethodInvoker)delegate
                                {
     
                                    progressBar1.Maximum = metroListView1.Items.Count;//Dt is your DataTable
                                    for (int i = 0; i < metroListView1.Items.Count; i++)
                                    {
                                        //Do Work
                                        progressBar1.Value = i + 1;
                                    }
     
                                });
    Merci,
    Cordialement.

  2. #2
    Membre chevronné
    Avatar de nouanda
    Homme Profil pro
    Hobbyist
    Inscrit en
    Mai 2002
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Hobbyist

    Informations forums :
    Inscription : Mai 2002
    Messages : 246
    Par défaut
    En effet, il y a quelques erreurs de logique ici.

    Tout d'abord, la façon dont tu fais avancer la progress bar: tu le fais une fois que ta listview est remplie, donc cela n'a pas d’intérêt. Visuellement, je ne suis même pas sur que Windows ait le temps de rafraîchir l'affichage le temsp de finir la boucle while, donc tu ne vois rien du tout.
    [Edit] Je ne m’étais pas rendu compte que tu faisais cela a chaque itération du dr.Read(). Sans vouloir être méchant, c'est encore plus un non-sens. Mais je ne vais rien dire, je suis sur que mes projets en contiennent plein aussi...

    Ensuite, tu n'appelles jamais la méthode ReportProgress(Int32), qui lance l’événement ProgressChanged, et c'est cela qu'il te manque.

    Ce que je ferais:
    • enlever la partie progressbar/boucle while dans la méthode DoWork.
    • dans le DoWork, effectuer une première étape qui consiste a récupérer le compte d'items et définir cela comme le maximum de ta progressbar
      Par exemple:
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
       using (var cnx = new MySqlConnection("ConnectionString"))
                      { 
                          cnx.Open();
                          var cmd = new MySqlCommand("SELECT COUNT(*) FROM Account", cnx);
                          int itemscount = cmd.ExecuteScalar(); // il faut que modifie cela pour verifier que le ExecuteScalar ne provoque pas d'InvalidCastException.
                          cmd.CommandText = "SELECT * FROM Account";
                          using (var dr = cmd.ExecuteReader())
                          { 
                              while (dr.Read())
                               etc...
    • Ajouter un compteur dans la méthode DoWork que tu incrémentes dans la boucle while dr.read()
    • Appeler backgroundWorker1.ReportProgress(Math.Floor(compteur / itemscount)) a la fin de la boucle while dr.read()
    • Et dans le ProgressChanged, simplement faire progressBar1.Value = e.ProgressPercentage;

  3. #3
    Membre confirmé Avatar de mathisdu42
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2013
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2013
    Messages : 168
    Par défaut
    Bonsoir à toi

    Merci pour ta réponse,

    Tout d'abord ne t'en fait pas je ne prends pas mal ce que tu me dis, bien au contraire, ça me permettra de m'améliorer et d'apprendre de mes erreurs Donc en effet, avec du recul, je me rends bien compte que ce que je faisais n'avait aucun sens. J'ai donc étudié et mis en pratique les explications que tu m'as fournies mais je ne comprends pas tout.. Je vais peut être passer pour je-ne-sais-quoi mais bon, faut bien passer par là un jour ou l'autre.
    Ce que je comprends pas trop c'est les deux points suivants :
    • Ajouter un compteur dans la méthode DoWork que tu incrémentes dans la boucle while dr.read()
    • Et ce code : backgroundWorker1.ReportProgress(Math.Floor(Compteur / itemscount))


    Je ne comprends pas pourquoi il faut incrémenter un compteur ? Pour la progressBar ? Et ce compteur, il compte quoi ? les Items de la listView ?
    Et pourquoi diviser le résultat du compteur par le nombre d'Items récupérés dans la base de données ?

    Désolé si je te bombarde de questions qui peuvent paraitre bête mais c'est simplement pour y voir plus clair

    Merci !

  4. #4
    Membre chevronné
    Avatar de nouanda
    Homme Profil pro
    Hobbyist
    Inscrit en
    Mai 2002
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Hobbyist

    Informations forums :
    Inscription : Mai 2002
    Messages : 246
    Par défaut
    Il faut un compteur, car la méthode ReportProgress demande un le pourcentage de complétion en paramètre. Et comme le dit si gentiment la documentation:
    Citation Envoyé par MSDN
    It is up to you to implement a meaningful way of measuring your background operation's progress as a percentage of the total task completed.
    Il faut donc un moyen de calculer ce pourcentage de complétion. Et en l’occurrence, il faut connaitre le nombre de lignes a traiter (récupérée avec le select count(*)), et où tu en es de la lecture. D’où l’idée d'avoir un compteur.
    Dans mon idée, tu l'initialises a zéro avant d'ouvrir la connexion, et tu l'incrémentes juste avant la fin de la boucle while. Comme ça, tu sais exactement combien de lignes du reader ont été lues.
    Tu pourrais également l'initialiser en dehors du try/catch, ce qui te permets, en cas d'exception a la lecture, de savoir combien de lignes ont été lues avant de planter.
    Il est possible en effet utiliser comme compteur metroListView1.Items.Count (et donc écrire backgroundWorker1.ReportProgress(Math.Floor(metroListView1.Items.Count/ itemscount))), juste après avoir fait metroListView1.Items.Add(listitem); mais si jamais un jour, tu reprends ton code, et décide que certaines entrée ne doivent pas être affichées dans la ListView, tu perds l'information.

    Au passage, il faut vérifier que ton backgroundworker a sa propriété WorkerReportsProgress = true, sinon ReportProgress va générer une InvalidOperationException

  5. #5
    Membre confirmé Avatar de mathisdu42
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Mars 2013
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Mars 2013
    Messages : 168
    Par défaut
    Je pense avoir saisi la chose. J'ai fait ce que tu as dit, une requête SELECT Count(*) avec un ExecuteScalar que j'ai converti en int itemscount = (Convert.ToInt32(cmd.ExecuteScalar())); ensuite j'ai créé une variable int compteur = 0; que j'ai placé avant l'ouverture de la connexion. Ensuite dans la boucle While (dr.Read()) j'ai dans un premier temps incrémenté le compteur par compteur++ (je doute fort que ce soit ce qu'il faut faire.. J'ai pensé à une éventuelle boucle for que j'aurai incrémenté puis ajouté un calcul de pourcentage ?). Dans un second temps j'ai mis le code pour ajouter les Items de la BDD dans la listView (à l'intérieur de la boucle While) puis en dernier inscrit backgroundWorker1.ReportProgress(Math.Floor(compteur / itemscount));Voilà ce que j'ai fait. Évidemment je pense fort que ce code est faux puisque premièrement, la listView duplique tous les Items (par 6), ensuite j'ai dû faire une erreur de conversion étant donné que VS m'indique du Floor de Math.Floor que
    L'appel est ambigu entre les méthodes ou les propriétés : 'Math.Floor(decimal)' et 'Math.Floor(double)'
    Et pour finir je pensais ajouter dans la boucle While un if (listView1.Items.Count == itemscount) break; ?

    Merci.

  6. #6
    Membre chevronné
    Avatar de nouanda
    Homme Profil pro
    Hobbyist
    Inscrit en
    Mai 2002
    Messages
    246
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Australie

    Informations professionnelles :
    Activité : Hobbyist

    Informations forums :
    Inscription : Mai 2002
    Messages : 246
    Par défaut
    Tu peux envoyer ton code? Il n'y a pas de raison d'avoir des items en double...
    Pour l'ambiguite, c'est de ma faute... Essaye de faire directement backgroundWorker1.ReportProgress((compteur *100 / itemscount)); Apparemment pas besoin de passer par Math.Floor avec les integers (je l'ignorais totalement...).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 07/10/2015, 17h23
  2. Filtrer une listview à l'aide d'un edittext
    Par redmonster dans le forum Composants graphiques
    Réponses: 7
    Dernier message: 03/06/2012, 21h24
  3. Problème de chargement d'une listView dans un thread
    Par Jérémy Lefevre dans le forum Composants graphiques
    Réponses: 3
    Dernier message: 12/10/2011, 17h27
  4. Aide au chargement d'une DLL.
    Par Flow_75 dans le forum C++
    Réponses: 4
    Dernier message: 24/06/2007, 21h24
  5. chargement dans une listview
    Par k_boy dans le forum VC++ .NET
    Réponses: 3
    Dernier message: 04/12/2006, 13h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo