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 :

UI & Threading


Sujet :

Windows Forms

  1. #1
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut UI & Threading
    Bonjour,

    J'aimerais afficher sur mon UI le nombre de fichiers pdf se trouvant dans certains dossiers spécifiques du pc host. Sachant que ce nombre peut varier d'un moment à l'autre, j'aimerais le calculer toutes les 15 secondes.
    Pour ce faire, je démarrer un thread qui se charge de compter le nombre de fichiers, et de mettre à jour l'UI.

    Cependant, j'ai l'impression que ce thread ne rend pas la main au thread UI, ce qui fait que mon UI n'est pas rafraichie (le calcul s'effectue bien, lui).

    Mon code :

    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
     
    while (true)
                {              
                    if (this.listviewHotfolders.InvokeRequired)
                    {
                        this.Invoke(new countJobsCallBack(countJobs));
                    }
                    else
                    {
                        for (int i = 0; i < this.listviewHotfolders.Items.Count; i++)
                        {
                            String[] files = Directory.GetFiles(this.listviewHotfolders.Items[i].SubItems[4].Text);
                            int count = 0;
                            foreach (String file in files)
                            {
                                if (Path.GetExtension(file) == ".pdf")
                                    count++;
                            }
                            this.listviewHotfolders.Items[i].SubItems[6].Text = count.ToString();
                        }
                    }
                }
     
    // Les 15 secondes ne sont pas prises en compte ici, mais le problème reste le même

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Février 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 114
    Points : 140
    Points
    140
    Par défaut
    Bonjour,

    Pourrait-on avoir plus de code ?

    La le code que tu nous montre vérifie si il se trouve sur le thread UI (via le InvokeRequired) et si il s'y trouve, il invoke la méthode CountJobs sur le thread ui et sinon il compte le nombre de fichier pdf (si j'ai bien tout compris).

    Je vois plusieurs points d'erreur :
    - ta boucle pour le compte du nombre de fichier pdf devrait être exécuté en dehors du thread UI (ce que tu souhaite) via un thread de la pool (http://msdn.microsoft.com/fr-fr/libr...(v=vs.90).aspx).
    - tu ne devrait pas (ce n'est que mon avis) lire tes données depuis l'UI dans ta boucle de travail (ce que tu fais en faisant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.listviewHotfolders.Items[i].SubItems[4].Text
    )
    - une fois avoir fait tout tes calculs, tu devrait utiliser this.Invoke pour mettre à jour ton UI (ou bien mettre chacun de tes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.listviewHotfolders.Items[i].SubItems[6].Text = count.ToString();
    dans this.Invoke).

    Enfin, pour demander à un thread d'attendre, tu as http://msdn.microsoft.com/fr-fr/libr...(v=vs.90).aspx.

  3. #3
    Membre expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Points : 3 568
    Points
    3 568
    Par défaut
    Pas de rapport avec l'UI, mais tu peux utiliser la classe FileSystemWatcher, qui envoie un événement si un fichier est ajouté, effacé, modifié : http://msdn.microsoft.com/en-us/libr...emwatcher.aspx
    Microsoft MVP : Windows Platform

    MCPD - Windows Phone Developer
    MCPD - Windows Developer 4

    http://www.guruumeditation.net

    “If debugging is the process of removing bugs, then programming must be the process of putting them in.”
    (Edsger W. Dijkstra)

  4. #4
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Merci pour ta réponse ketan. La méthode que je montre ci-haut est la méthode "CountJobs" et est dans un autre thread que le thread UI (thread lancé dans le constructeur de ma form, je ne sais d'ailleurs pas si c'est le bon endroit pour le faire, bien que je n'en vois pas de meilleur).

    Ce que je veux faire, donc, c'est compter le nombre de fichiers dans chaque dossier repris dans ma listview (et j'ai donc besoin de lire des données dans celle-ci depuis un thread autre que l'UI, puis de la màj).

    Pour y voir plus clair :

    Constructeur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
            public MainWindow()
            {
                InitializeComponent();
                // ...
                Thread inputJobs = new Thread(new ThreadStart(countJobs));            
                inputJobs.Start();
            }
    CountJobs
    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
     
            public void countJobs()
            {
                while (true)
                {              
                    if (this.listviewHotfolders.InvokeRequired)
                    {
                        this.Invoke(new countJobsCallBack(countJobs));
                    }
                    else
                    {
                        for (int i = 0; i < this.listviewHotfolders.Items.Count; i++)
                        {
                            String[] files = Directory.GetFiles(this.listviewHotfolders.Items[i].SubItems[4].Text);
                            int count = 0;
                            foreach (String file in files)
                            {
                                if (Path.GetExtension(file) == ".pdf")
                                    count++;
                            }
                            this.listviewHotfolders.Items[i].SubItems[6].Text = count.ToString();
                        }
                    }
                    Thread.Sleep(5);
                }
            }

  5. #5
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Citation Envoyé par GuruuMeditation Voir le message
    Pas de rapport avec l'UI, mais tu peux utiliser la classe FileSystemWatcher, qui envoie un événement si un fichier est ajouté, effacé, modifié : http://msdn.microsoft.com/en-us/libr...emwatcher.aspx
    Salut Guruu, et merci pour ta réponse.
    Le système est basé en grande partie sur les FileSystemWatchers, mais ceux-ci dépendent d'un service qui n'est pas fortement lié à l'UI, ce qui rend la communication assez difficile. De plus, le nombre de fichiers traités étant assez importants, je ne veux pas un refresh trop régulier de l'UI, et gérer cela serait, je pense, plus compliqué que ce que je propose ici.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 31
    Points : 35
    Points
    35
    Par défaut
    Je pense que ton thread prends trop de ressources.
    Tu dois l'endormir lorsque ton traitement est terminé.
    Sleep(5) n'est probablement pas efficace car le système est incapable de faire une attente de 5ms.
    J'utilise plutôt :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public ManualResetEvent m_SleepEvent = new ManualResetEvent(false);
    dans la boucle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
                m_SleepEvent.Reset(); // Initialisation
                while (true)
                {
                      // Ton traitement
                      m_SleepEvent.WaitOne();   // On reste bloqué
                      m_SleepEvent.Reset();       // On réarme
                }
    Dans la routine qui gère les 15 s, tu fait un Set pour le réveiller.
    Tu peux aussi utiliser un système équivalent pour quitter le thread "proprement".
    Je ne suis pas rentré dans les détails, mais le principe est là.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    m_SleepEvent.Set();

  7. #7
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Bonjour alro,

    Merci pour ta réponse. J'avais essayé via des AutoResetEvent, l'affichage ne se faisait qu'une fois, mais le soucis restait le même par la suite. Pareil ici, avec les ManualResetEvent...

    J'ai réussi à faire ce que je voulais via un timer (et non un thread travail), mais je ne suis pas sur que ce soit la meilleure solution dans ce cas-ci...

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 31
    Points : 35
    Points
    35
    Par défaut
    Le problème du timer, c'est que ça bloque tout le reste pendant son exécution.
    Par contre, le timer peut très bien lancer le thread (ton thread sans la boucle while(true)).

  9. #9
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Je vais essayer comme ça, ça m'a l'air d'une solution plus facile.

    Merci ! Je vous tiendrai au courant.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Février 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 114
    Points : 140
    Points
    140
    Par défaut
    Le freeze de ton UI vient du fait que tout ton code relatif à ton calcul est exécuté dans ton thread UI et aussi que tu ne fait jamais de pause entre deux calcul.

    La ligne en cause est ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if (this.listviewHotfolders.InvokeRequired)
    {
        this.Invoke(new countJobsCallBack(countJobs));
    }
    Une solution qui devrait fonctionner en modifiant un peu ton code :
    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
     
           public void countJobs()
            {
                while (true)
                {              
     
                        for (int i = 0; i < this.listviewHotfolders.Items.Count; i++)
                        {
                            String[] files = Directory.GetFiles(this.listviewHotfolders.Items[i].SubItems[4].Text);
                            int count = 0;
                            foreach (String file in files)
                            {
                                if (Path.GetExtension(file) == ".pdf")
                                    count++;
                            }
                            if (this.listviewHotfolders.InvokeRequired)
                            {
                                this.Invoke(UpdateCount, i, count.ToString());
                            }
                            else
                            {
                                UpdateCount(i, count.ToString());
                            }
                        }
     
                    Thread.Sleep(15000);
                }
            }
     
    public UpdateCount(int index, string  val)
    {
        this.listviewHotfolders.Items[index].SubItems[6].Text = val;
    }
    Ce code fait quoi comparé au tien ?
    - il n'exécute que la mise à jour de l'UI dans le thread UI si besoin
    - il attend 15 secondes entre chaque lancement de ton calcul (Thread.Sleep attend des millisecondes, donc il faut multiplier ton nombre de seconde par 1000).

  11. #11
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Merci pour ton temps ketan.

    Cependant, ce bout de code ne fonctionne pas étant donné que j'essaie d'accéder aux données de l'UI en dehors du thread UI. C'est là la base de mon soucis

    Je vais essayer la solution de Alro_gr : un timer qui lance le thread toutes les 15 secondes, si faisable.

    Merci à tous en tout cas !

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2012
    Messages
    31
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 31
    Points : 35
    Points
    35
    Par défaut
    Le problème de faire un sleep(15000), c'est que le thread peut mettre 15 secondes pour quitter, si par exemple tu fermes l'application juste après le traitement.
    Pour accéder à tes info. depuis ton thread, tu dois passer par une fonction déléguée, je crois..... je débute en C# et je dois bien avouer que je ne comprends pas encore tout. Dans ma logique de C++ (que je maitrise carrément mieux), le thread devrait envoyer un message à la form pour qu'elle se mette à jour.

  13. #13
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Tu as raison de bout en bout Alro, le soucis est que je n'arrive pas à l'implémenter. Je l'ai théoriquement, reste à le mettre en pratique.

    En passant par les délégués, le travail s'effectue uniquement dans le thread UI et bloque donc l'affichage...

    Je suis perdu ! (Et je vais donc rester sur un timer...)

  14. #14
    Membre habitué
    Profil pro
    Inscrit en
    Février 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 114
    Points : 140
    Points
    140
    Par défaut
    Pour le problème de l'attente à la fermeture, tu peux passer ton thread en fond après sa création comme le runtime détruit le thread lors de la demande de fermeture, sans attendre sa fin (le problème d'un while(true) dans un thread peut complètement bloquer une application et l'empêcher de se fermer).
    http://msdn.microsoft.com/fr-fr/libr...(v=vs.90).aspx

    Personnellement je suis plus découplage de l'interface et des données, ce qui implique que pour le calcul je n'ai pas besoin de demander à la vue mes données vu que je les ais déjà.

    Dans ton cas, le mieux que je vois c'est quelque chose comme ça dans ton thread :
    1 - passage dans le thread UI pour récupérer la liste des dossiers à vérifier (via àun appel à Invoke)
    2 - une fois de retour dans le thread de travail, faire mes calculs
    3 - une fois les calculs finis, passer dans le thread UI pour mettre à jour l'interface avec les nouveaux résultats (via Invoke ou BeginInvoke)
    4 - mettre en attente le thread de travail (sleep, Event, autre ?)
    5 - recommencer à l'étape 1.

    Après, je suis d'accord que la boucle while(true) n'est pas terrible et qu'il faut mieux utiliser des systèmes de contrôles avec les thread plutôt que des sleep, mais si on veut rester simple, c'est quand même le mieux.

  15. #15
    Membre actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    141
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 141
    Points : 201
    Points
    201
    Par défaut
    Un immense merci !

    Ca fonctionne parfaitement, sans bloquer mon UI. C'est exactement ce que je voulais.

    Une nouvelle fois merci pour le temps que tu as passé pour m'aider ketan (et ça vaut pour les autres )!

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

Discussions similaires

  1. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 10h00
  2. récupérer la valeur de sortie d'un thread
    Par jakouz dans le forum Langage
    Réponses: 3
    Dernier message: 31/07/2002, 12h28
  3. Programmer des threads
    Par haypo dans le forum C
    Réponses: 6
    Dernier message: 02/07/2002, 14h53
  4. Réponses: 5
    Dernier message: 12/06/2002, 16h12
  5. [Kylix] Pb de Thread !!
    Par Anonymous dans le forum EDI
    Réponses: 1
    Dernier message: 25/04/2002, 14h53

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