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 :

Thread pour une méthode


Sujet :

Windows Forms

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 2
    Par défaut Thread pour une méthode
    Bonjour,

    Je me suis mis au C# il y a quelque mois pour développer une application à base de WinForms.
    Jusqu'ici, tout va bien, l'ensemble marche pas trop mal, et j'ai appris pas mal de trucs intéressants, mais je suis maintenant face à un problème que je n'arrive pas résoudre... Faire en sorte que les fenêtres ne soient pas figées pendant le traitement d'une action de longue durée.

    Je me suis donc documenté sur les différents manières de faire, j'ai retenu notamment le composant BackgroundWorker et la classe Thread. Je suis arrivé à mettre en œuvre les exemples trouvés sur MSDN ou ici, ainsi que ceux d'un bouquin que j'ai emprunté (mais qui date un peu : ".NET et C# version 2").
    Mais transposé à mes besoins, ça ne marche pas.

    J'utilise une API (propriétaire) avec laquelle on peut faire un tas de truc mais une des méthodes est assez longue à traiter, j'ai donc essayer de la faire traiter dans un thread ou un BackgroundWorker :
    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
    namespace MyPlugin {
     
        partial class Form1 : Form {
     
            private Thread reco;
     
            // ...
     
            protected override void OnLoad(EventArgs e) {
                Application.Idle += new EventHandler(OnLoaded);
                base.OnLoad(e);
            }
     
            private void OnLoaded(object sender, EventArgs e) {
                Application.Idle -= new EventHandler(OnLoaded);
                //this.myAPI.Reconnect(usr, pwd); // Appel dans le thread Form mais long à traiter... Donc essai avec Thread :
                reco = new Thread(new ThreadStart(DoReconnect));
                reco.Start();
                reco.Join();
                FillListView(myAPI.GetList());
            }
     
            private void DoReconnect() {
                // Le thread accède à myAPI, usr, pwd mais ce sont pas des contrôles...
                this.myAPI.Reconnect(usr, pwd);
            }
     
        }
     
    }
    J'obtiens exactement le même résultat avec ce système qu'en appelant directement Reconnect dans OnLoaded : fenêtre figée (ie impossible de la redimensionner, de manipuler ses combobox, etc...).

    Tous les exemples que j'ai mis en œuvre sont assez simples dans la mesure où les tâches confiées au deuxième thread ne sont pas une action sur un objet qui est utilisé tout au long de l'appli... Si vous pouvez me conseiller, merci. En espérant avoir été clair.

  2. #2
    Candidat au Club
    Profil pro
    Inscrit en
    Février 2011
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 2
    Par défaut
    Écrire mon problème ici m'a au moins permis de me vider la tête.
    J'ai essayé une nouvelle piste. Thread.Join() ne doit pas vraiment faire ce que je croyais qu'il ferait...

    J'ai donc fait ceci :
    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
            private void OnLoaded(object sender, EventArgs e) {
                Application.Idle -= new EventHandler(OnLoaded);
                //this.myAPI.Reconnect(usr, pwd); // Appel dans le thread Form mais long à traiter... Donc essai avec Thread :
                reco = new Thread(new ThreadStart(DoReconnect));
                reco.IsBackground = true;
                reco.Start();
            }
     
            private void DoReconnect() {
                // Le thread accède à myAPI, usr, pwd mais ce sont pas des contrôles...
                this.myAPI.Reconnect(usr, pwd);
                this.Invoke(new MethodInvoker(DoThings));
            }
     
            private void DoThings() {
                FillListView(myAPI.GetList());
                // et les trucs suivants
            }
    Et ça donne bien le rendu IHM escompté !
    Bon, il faut que je réordonne mieux toutes mes méthodes trucs, mais ça devrait le faire ? Si vous avez de meilleurs avis ou des idées pour arranger le code afin que ça soit plus propre, je vous écoute. Autrement, je passerai le problème a résolu incessamment sous peu.

  3. #3
    Membre extrêmement actif
    Inscrit en
    Avril 2008
    Messages
    2 573
    Détails du profil
    Informations personnelles :
    Âge : 65

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 573
    Par défaut classe thread,classe delegue
    bonjour nbcsharp
    pour ne pas faire des "trucs" et aussi parce que tu parles de reordonner un peu les choses.

    1/Inconvenient d'utiliser une classe Thread
    -ne permet pas de passer des parametres.
    -il faut utiliser des parametres globaux.
    2/ "Aspect" peu connu des Delegues
    -un delegue s'execute toujours dans un thread different ,eh oui.
    -Au lieu d'utiliser un "thread" pour faire du "threading" on peut utiliser simplement la "bete" delegue "explicitement avec sa methode BeginInvoke" qui fait tres bien du threading
    -on peut passer des parametres.
    -quand on utilise un delegue on fait du threading sans le savoir (Mr Jourdain fait de la prose sans le savoir)

    2/Mise à jour de l'UI
    - utiliser egalement un delegue "auxiliaire" charge de la maj des controles.
    - utiliser la methode InvokeRequired des controles,peu connue.
    Pour illustrer ce qui precede voici le code repris (les appels à ton api sont en "comments" puisque je ne les ai pas)
    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
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
     
     
     
    //Remarque1: Definition d'un Delegue
    //l'appel "par defaut" à un delegue equivaut 
    //à utiliser NomDelegue.BeginInvoke avec parametres
    //BeginInvoke "asynchrone" s'execute toujours dans un thread separe 
    //----------------------------------------------------
    //Class monDelegueDelegate
    //  Inherits MulticaseDelegate
     
    //  Sub Invoke(digits As Integer)
    //  Sub BeginInvoke(param1  As type1,param2 as type2,etc..., _
    //      callback As AsyncCallback, asyncState As Object)
    //  Sub EndInvoke(result As IAsyncResult)
    //End Class
    //--------------------------------------------------------------------------
    //Remarque2: sur les Methodes des Controles
    // Invoke,BeginInvoke,EndInvoke,InvokeRequired
    //qui utilise un Delegue comme parametre
    //--------------------------------------------------------------------------
    //Class System.Windows.Forms.Control
    //  Overloads Function Invoke(method As Delegate) As Object
    //  NotOverridable Overloads Function Invoke(method As Delegate, _
    //      args() As Object) As Object
    //  Overloads Function BeginInvoke(method As Delegate) As IAsyncResult
    //  NotOverridable Overloads Function BeginInvoke(method As Delegate, _
    //      args() As Object) As IAsyncResult
    //  NotOverridable Function EndInvoke(asyncResult As IAsyncResult) As Object
    //End Class
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
     
    namespace MyPlugin {
     
     
        public partial class Form1 : Form
        {
            //Delegue permet de passer des parametres 
            //Appel à classe thread ne le permet pas(il faut parametres globaux)
            //Passage de parametres en utilisant "explicitement" BeginInvoke
            //
            public delegate void dlgGReconnect(string usr, string pwd);
            //
            //Delegue auxiliaire charge de la maj de l'UI  
            //appele  "asynchroniquement
            //
            public delegate void dlgMiseAjourUI(int counter);
     
            public Form1()
            {
                InitializeComponent();
            }
     
            private void OnLoaded(object sender, EventArgs e)
            {
     
                //Application.Idle -= new EventHandler(OnLoaded);
                //this.myAPI.Reconnect(usr, pwd); // Appel dans le thread Form mais long à traiter... Donc essai avec Thread :
                //Thread reco = new Thread(new ThreadStart(DoReconnect));
                //reco.IsBackground = true;
                //reco.Start();
     
     
            }
     
            private void DoReconnect()
            {
                // Le thread accède à myAPI, usr, pwd mais ce sont pas des contrôles...
                //this.myAPI.Reconnect(usr, pwd);
                //this.Invoke(new MethodInvoker(DoThings));
            }
            private void DoReconnectBIS(string usr, string pwd)
            {
                //Le thread accède   usr, pwd sont des parametres internes...
                //this.myAPI.Reconnect(usr, pwd);
                //this.Invoke(new MethodInvoker(DoThingsBis));
                 DoThingsBis();
            }
     
            private void DoThings()
            {
                //FillListView(myAPI.GetList());
                // et les trucs suivants
            }
            //Version Revise de DoThings avec Maj de l'UI
            private void DoThingsBis()
            {
                //
                //Simple Compteur mais ca peut etre des variables de FillListView 
                //
                int counter=0;
                //Appel maj de UI
                MiseAjourUI(counter);
                //FillListView(myAPI.GetList());
     
                for (int j=0;j<1000000000;j++)
                 {
                    counter = j;
                 }
                //Appel maj de UI
                MiseAjourUI(counter);
     
            }
            //
            //Sub de Maj des controles de l'interface UI
            //
            private void MiseAjourUI(int counter)
            { 
                //L'appel vient de UI directement(normal)
                if  (!this.InvokeRequired)
                {
                this.textBox1.Text= counter.ToString();
                this.label1.Text =  counter.ToString();
                this.progressBar1.Value = counter;
                }  
                //Non l'appel vient d'un autre thread
                // s'invoke elle-meme  mais "asynchroniquement"
                // par le biais du Delegue auxiliaire maj UI
                else
                {
                    dlgMiseAjourUI objMiseAjourUI = MiseAjourUI;
                    this.BeginInvoke(objMiseAjourUI,new object[]{counter});
                }
     
             }
            //On demarre la tache "worker" ici
            private void button1_Click(object sender, EventArgs e)
            {
                //ceci est une autre facon de faire 
                //Utilise Appel par defaut "explicite asynchrone" BeginInvoke
                this.textBox1.Text = "";
                this.label1.Text = "";
                this.progressBar1.Minimum = 0;
                this.progressBar1.Maximum = 100;
                string usr = "ALI";
                string pwd = "MOMO";
                dlgGReconnect recoBis = DoReconnectBIS;
                recoBis.BeginInvoke(usr, pwd, null, null);
            }
     
        }
    }
    A propos des parametres null,null.Grace à eux on peut definir des methodes de rappel(callback) du genre avertissement "tache terminee....".

    Il ne faut pas faire des "trucs" mais faire un code propre.....
    bon code

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

Discussions similaires

  1. Thread pour une animation dans un JPanel
    Par womannosky dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 05/05/2009, 11h37
  2. exécuter un thread pour une durée donnée
    Par selmani300 dans le forum C
    Réponses: 6
    Dernier message: 28/04/2009, 14h44
  3. Thread pour une barre de progression
    Par BATCHOS CON TEQUILA dans le forum Windows Communication Foundation
    Réponses: 3
    Dernier message: 15/01/2009, 03h05
  4. Réponses: 3
    Dernier message: 19/03/2008, 10h38
  5. Exécution d'un Thread dans une méthode statique
    Par barbiche dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 03/05/2007, 15h25

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