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

C# Discussion :

Form thread mise à jour depuis autre class [Débutant]


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2002
    Messages
    219
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2002
    Messages : 219
    Par défaut Form thread mise à jour depuis autre class
    Bonjour,

    Je souhaite avoir une Form qui lance un une procédure (longue) dans une autre class et que celle ci mette à jour des éléments de la Form au fur et a mesure de l'avancement de la procédure.

    Pour essayer de comprendre, j'ai suivi un tutoriel - la partie avec les Windows Forms

    Quand tous est dans la même class, pas de problème cela fonctionne (but du tutoriel). mais quand j'essaye d'éclater en 2 class je bloque

    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
       public partial class Form1 : Form
        {
            private Random rand = new Random((int)DateTime.Now.Ticks);
     
            private int[] tableau = new int[500000];
     
            //On crée notre delagate.
            public delegate void MontrerProgres(int valeur);
     
            bool termine = true;
     
            public Form1()
            {
                InitializeComponent();
     
                //On génère un tableau d'entiers aléatoires.
                for (int i = 0; i < tableau.Length; i++)
                {
                    tableau[i] = rand.Next(50000);   //...Boucle très simple, avec méthode Random très simple.
                }
            }
     
            public void Selection()
            {
                //On va simplement compter les nombres du tableau inférieurs à 500.
                int total = 0;
     
                for (int i = 0; i < tableau.Length; i++)
                {
                    if (tableau[i] < 500)
                    {
                        total++;
                    }
     
                    //Puis, on incrémente le ProgressBar.
                    int valeur = (int)(i / (double)tableau.Length * 100);
     
                    //On achète la paix, on entoure notre Invoke d'un try...catch !
                    try
                    {
                        //On invoque le delegate pour qu'il effectue la tâche sur le temps
                        //de l'autre thread.
                        Invoke((MontrerProgres)Progres, valeur);
                    }
                    catch (Exception ex) { return; }
                }
     
                termine = true;
            }
     
            public void Progres(int valeur)
            {
                //On met la valeur dans le contrôle Windows Forms.
                // pgbThread.Value = valeur;
                progressBar1.Value = valeur;
            }
     
            private void button2_Click(object sender, EventArgs e)
            {
                traite tr1 = new traite();
                tr1.tableau = tableau;
                tr1.Selection();
                Thread t2 = new Thread(new ThreadStart(tr1.Selection)); 
            }
    et ma class traite
    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
        class traite
        {
            public int[] tableau;
            Boolean termine = false;
            public static void start()
            {
                traite tr1 = new traite();
                tr1.Selection();
            }
            public void Selection()
            {
                //On va simplement compter les nombres du tableau inférieurs à 500.
                int total = 0;
     
                for (int i = 0; i < tableau.Length; i++)
                {
                    if (tableau[i] < 500)
                    {
                        total++;
                    }
     
                    //Puis, on incrémente le ProgressBar.
                    int valeur = (int)(i / (double)tableau.Length * 100);
     
                    //On achète la paix, on entoure notre Invoke d'un try...catch !
                    try
                    {
                        //On invoque le delegate pour qu'il effectue la tâche sur le temps
                        //de l'autre thread.
                        Invoke((Form1.MontrerProgres)Progres, valeur);
                        //Form1.upro(valeur);
                        //Form1.MontrerProgres;
     
                        // MethodInvoker action = () => Form1.upro(valeur);
     
                    }
                    catch (Exception ex) { return; }
                }
     
     
     
                termine = true;
            }
        }
     
    }
    Je bloque sur la mise à jour de la zone via delegate :
    Invoke((Form1.MontrerProgres)Progres, valeur);

    J'ai fait différent essai, mais j'ai toujours des erreurs de compilation.

    J'ai essayer cette méthode : https://www.daniweb.com/programming/...-another-class
    mais elle ne fonctionne pas non plus .. erreur dans le code.
    Merci pour vos conseils éclairer.
    PS: je suis en .NET 3.5 pour des raisons techniques.

  2. #2
    Membre très actif
    Avatar de charouel
    Homme Profil pro
    Freelance
    Inscrit en
    Mars 2009
    Messages
    618
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mars 2009
    Messages : 618
    Billets dans le blog
    9
    Par défaut
    utilise le multiThreading, lorsque tu déclare ta deuxième classe passe l’instanciation dans un thread a part

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                ThreadStart job = new ThreadStart(constructeur_classe2);
                Thread thread = new Thread(job);
                thread.Start();

  3. #3
    Membre actif
    Profil pro
    Inscrit en
    Août 2005
    Messages
    123
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 123
    Par défaut
    On encore plus simple pour ce genre de traitement, utilise un BackgroundWorker.

    https://msdn.microsoft.com/en-us/lib...v=vs.110).aspx

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2002
    Messages
    219
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2002
    Messages : 219
    Par défaut
    J'ai fait des recherches,
    charouel, j'ai pas compris
    mattdef, j'arrive pas mettre à jour depuis l'autre class !

    Mes 2 class modifiées

    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
        public partial class Form1 : Form
        {
            private Random rand = new Random((int)DateTime.Now.Ticks);
     
            private int[] tableau = new int[50];
     
            //On crée notre delagate.
            public delegate void MontrerProgres(int valeur);
     
            bool termine = false;
     
            public Form1()
            {
                InitializeComponent();
     
                //On génère un tableau d'entiers aléatoires.
                for (int i = 0; i < tableau.Length; i++)
                {
                    tableau[i] = rand.Next(50000);   //...Boucle très simple, avec méthode Random très simple.
                }
                backgroundWorker1.WorkerReportsProgress = true;
                backgroundWorker1.WorkerSupportsCancellation = true;
            }
            private void button2_Click(object sender, EventArgs e)
            {
                if (!termine)
                {
                    backgroundWorker1.RunWorkerAsync();
                }
                else
                {
                    backgroundWorker1.CancelAsync();
                }
                termine = !termine;
            }
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                /*int total = 0; 
                for (int i = 0; i < tableau.Length; i++)
                {
                    if (tableau[i] < 500)
                    {
                        total++;
                    }
     
                    //Puis, on incrémente le ProgressBar.
                    int valeur = (int)(i / (double)tableau.Length * 100);
                    Thread.Sleep(100);
                    backgroundWorker1.ReportProgress(i);
                }*/
                traite tr1 = new traite();
                tr1.Selection(this);
                termine = true;
            }
     
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                string toto = "Demo";
                label1.Text = toto + e.ProgressPercentage.ToString();
                progressBar1.Value = e.ProgressPercentage;
            }
     
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                termine = true;
            }
    Et la class traite

    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
            public void Selection(Form demo)
            {
                //On va simplement compter les nombres du tableau inférieurs à 500.
                int total = 0;
     
                for (int i = 0; i < tableau.Length; i++)
                {
                    if (tableau[i] < 500)
                    {
                        total++;
                    }
     
                    //Puis, on incrémente le ProgressBar.
                    int valeur = (int)(i / (double)tableau.Length * 100);
                demo.backgroundWorker1.ReportProgress(i);
                termine = true;
            }
    Je n'arrive pas depuis la class Traite à mettre à jour reportprogress. J'arrive pas a l'appeller, il est absent dans la liste. J'ai fait un copier coller, mais toujour en erreur ne trouve pas une définition.

    Merci pour votre aide.

    J'ai trouvé plein d'exemple sur Google mais souvent avec 1 seule class, pas trouvé de tuto avec 2 class.
    Je galère depuis hier sur ce problème de threads, et tache de fond, sans pour l'instant avoir trouvée la bonne réponse.

  5. #5
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    On t'a donné une "bonne" réponse...

    Ta classe qui fait le boulot doit proposer un Event OnProgress qui sera appelé par ton traitement long.


    et dans la classe qui va créer le bazar, tu pourras être notifier du traitement.

  6. #6
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Par défaut
    On va la faire simple...

    LA classe qui fait le boulot :

    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
    public delegate void OnThreadProgress(int value);
     
        public class MyClassQuiBosse
        {
            public event OnThreadProgress OnProgress = null;
     
            public void Start()
            {
                Thread th = new Thread(new ThreadStart(DoWork));
                th.Start();
            }
     
            private void DoWork()
            {
                for (int i = 0; i < 100; i++)
                {
                    Thread.Sleep(100);
                    if (OnProgress != null)
                    {
                        OnProgress(i);                    
                    }
                }
            }
     
        }
    Et maintenant, la classe qui appelle.. dans un Winform, un bouton et une progressBar (on ne peut pas faire plus simple, si ? )


    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 button1_Click(object sender, EventArgs e)
            {
                MyClassQuiBosse nico = new MyClassQuiBosse();
                nico.OnProgress += nico_OnProgress;
                nico.Start();
            }
     
            void nico_OnProgress(int value)
            {
                if (InvokeRequired)
                {
                    Invoke(new OnThreadProgress(nico_OnProgress), value);
                }
                else
                {
                    progressBar1.Value = value;
                }
            }
    Et la, c'est juste magique, la progressBar, elle avance... pas de problème de compile, pas de bug... la classe qui fait le boulot ne connait pas son père et donc,
    n'a pas à savoir si il faut mettre à jour une progressBar ou une boite de chocolat...

    Et voilà... 3 mn montre en main

  7. #7
    Membre Expert
    Homme Profil pro
    Développeur .Net / Delphi
    Inscrit en
    Juillet 2002
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .Net / Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2002
    Messages : 738
    Par défaut
    Bonjour,
    Citation Envoyé par charouel Voir le message
    utilise le multiThreading, lorsque tu déclare ta deuxième classe passe l’instanciation dans un thread a part

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                ThreadStart job = new ThreadStart(constructeur_classe2);
                Thread thread = new Thread(job);
                thread.Start();
    Je ne comprends pas vraiment ta solution. Il faudrait peut-être développer un peu...


    Je bloque sur la mise à jour de la zone via delegate :
    Invoke((Form1.MontrerProgres)Progres, valeur);

    J'ai fait différent essai, mais j'ai toujours des erreurs de compilation.
    C'est normal, Invoke est une méthode de l'objet Control (la Form par exemple).
    Globalement, il n'est pas terrible que ta classe exécutant le traitement connaisse ta Form. Donc la passer en paramètres d'une façon ou d'une autre n'est pas conseillé. Le mieux serait de créer un évènement dans ta classe et de lever cet évènement durant le traitement. Ta Form s'abonne à l'évènement et peut ainsi gérer l'affichage avec la méthode Invoke :

    Dans ta classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     class traite
    {
      public delegate void OnProgressDelegate(Object sender, int Progress);
      public event OnProgressDelegate OnProgress;
      ...
      public void Selection()
      {
        ...
        if (OnProgress != null)
            OnProgress(this, valeur);
      }
    }
    Dans ta Form
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void tr1_OnProgress(object sender, int Progress)
    {
         Invoke((MontrerProgres)Progres, Progress);
    }
     
    private void button1_Click(object sender, EventArgs e)
    {
        traite tr1 = new traite();
        tr1.tableau = tableau;
        tr1.OnProgress += tr1_OnProgress;
        Thread t2 = new Thread(new ThreadStart(tr1.Selection)); 
    }
    Maintenant cette méthode fonctionne mais n'est pas terrible. En effet, le fait d'appeler une méthode d'objet dans un thread peut être dangereux car elle peut ne pas être ThreadSafe. Bon c'est toi qui la codes donc tu sais ce qu'il y a dedans mais dans le principe, ça ne se fait pas.
    De plus, il faudrait ajouter un évènement OnCompleted afin de prévenir la fin du traitement. Enfin, ce que je n'ai pas fait dans mon exemple, lorsqu'on s'abonne à un évènement, il faut absolument se désabonner afin d'éviter les fuites mémoire (tr1.OnProgress -= tr1_OnProgress; )

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 09/08/2013, 20h52
  2. ProgressBar mise à jour depuis une autre classe
    Par poussinvert dans le forum Android
    Réponses: 23
    Dernier message: 23/05/2012, 19h20
  3. debogage, form pas mise à jour
    Par LauBelette dans le forum Windows Forms
    Réponses: 7
    Dernier message: 25/02/2007, 09h18
  4. [Stratégie][Idée]Mise à jour depuis appli
    Par Baptiste Wicht dans le forum Langage
    Réponses: 21
    Dernier message: 05/05/2006, 01h16
  5. Réponses: 1
    Dernier message: 27/04/2006, 18h22

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