Croos-thread s - utilisation des delegates pour modifier des paramettre des cont

Messages postés
146
Date d'inscription
lundi 15 juin 2009
Statut
Membre
Dernière intervention
14 février 2013
- - Dernière réponse : cs_Robert33
Messages postés
834
Date d'inscription
samedi 15 novembre 2008
Statut
Membre
Dernière intervention
14 janvier 2017
- 14 mars 2010 à 09:01
Bonsoir à tous.

J'ai un petit souci avec mon programme quand à l'utilisation des threads et du passage de paramètres.

J'ai trouvé un tuto qui explique très bien le problème et j'arrive sans souci à modifier le Text d'un label.

Mais impossible de modifier le paramètre Visible d'un groupbox, il m'éjecte comme si je passais en direct d'un thread a l'autre, alors que je passe par un delegate et invoke.

je précise, on travaille plusieurs sur se projet.
La classe GestionReleve est une form qui a tout les code de gestion du programme et une Form qui nous sert de splashScreen.
La classe IHMReleve (Moi) qui s'occupe de l'IHM

GestionReleve me démarre dans un thread. Et GestionReleve viens chercher en boucle les infos pour savoir ce que j'attends de lui. Un tableau de booléen qui répertorie ce que j'attends.
Pour ce qui est de venir chercher les info, j'ai fait de simple méthode " truc Get...() " qui renvoie la donnée rechercher bien sur protéger par sémaphore au cas ou. Apparemment ce n'est pas tellement comme sa qu'il faut faire mais cela marche bien. Si vous avez une solution plus propre pour la recherche de données entre thread a me proposé se serait sympa.

Bon mon problème lui se situe pour transmettre des données de GestionReleve avec l'IHM.

Je vous présente mes 1er test pour modifier un label qui marche bien et pour modifier le visible du groupbox qui plante:

Voici le code dans le thread principal:
public partial class GestionReleve : Form
    {
        
        private delegate void PresenceSGBD(bool SGBD);
        private static IHMreleve.IMHReleve IHMForm;
        
        
        public GestionReleve()
        {
            InitializeComponent();
            IHMForm = new IHMreleve.IMHReleve();
            Thread IHM = new Thread(new ThreadStart(IHMStart));
            //Obligatoire pour utilisé les boites de dialogue tel que OpenFile dans un autre thread
            IHM.SetApartmentState(ApartmentState.STA);
            //Demarrage du thread IHM
            IHM.Start();
            
       // Pour les test cross-thread
            Thread.Sleep(5000);
            this.Invoke(new PresenceSGBD(IHMForm.SetPresenceSGBD), true); 
        }
 
       private static void IHMStart()
        {
            IHMForm.ShowDialog();
        }
 


Et la méthode qui se trouve dans la classe IHMReleve:

 public void SetPresenceSGBD(bool SGBD)
        {
  
                if (SGBD)
                {
                    lB_InfoVersSGBD.Text = "SGBD OK";
                    //gB_FichierSGBD.Visible = true;
                }
                else
                   lB_InfoVersSGBD.Text = 'SGBD NOK";
        }


En le laissant comme sa cela marche donc impeccable, mais suffit que je mette gB_FichierSGBD.Visible = true; Actif et la cela plante avec un beau message d'erreur de modification de variable entre thread. Le message d'ailleurs se situe sur IHMForm.ShowDialog(); mais en debug pas à pas je vois bien qu'il plante à l'accès de la fonction "Visible". le message d'erreur le nome bien aussi.

Je vais avoir pas mal de composant graphique à modifier comme sa et notamment les composant de Zedgraph pour mettre à jour les courbes en temps réel.

Pour le moment pour palier à sa au lieu de modifier le l'objet, je modifie une variable qui est scanner en permanence pas un timer et provoque le changement de l'objet en fonction, bien sur protégé par des sémaphores.

Si vous avez une solution à m'apporté, surtout pour se SET... mais aussi pour la GET, j'ai commencé à regarder InvokeRequiered mais je comprend pas l'utilisation

Merci de votre aide

Technicien en électricité Industriel (39 ans), en cours de reconversion BTS IRIS 2eme Année.
Au lycée pendant l'année scolaire, et en stage pendant les vacances scolaire.
Afficher la suite 

5 réponses

Messages postés
1160
Date d'inscription
vendredi 23 juillet 2004
Statut
Membre
Dernière intervention
21 octobre 2010
13
0
Merci
Théoriquement toute l'UI devrait se trouver sur le meme thread. Les threads secondaires doivent servir a computer des données, non pas a contenir d'autres formulaires.
Deuxiement, un ShowDialog dans un autre thread me semble abhérant...

A mon avis tu devrais commencer par revoir l'architecture et par mettre tous tes formulaires dans le meme thread.
Commenter la réponse de leprov
Messages postés
39
Date d'inscription
lundi 10 novembre 2008
Statut
Membre
Dernière intervention
7 septembre 2010
1
0
Merci
C'est vrai que les threads avec un interface graphique, c'est pas vraiment le pied, mais si tu pose la question, c'est que tu doit en avoir besoin. Les controles que tu créer sur un treads ne sont accessible que par celui ci. Donc tu dois rebasculer sur ton thread principal pour pouvoir modifié les controles.

Donc je pense que tu devrais aussi utiliser la propriété InvokeRequired pour regarder sur quel thread tu es, et si tu n'es pas sur le bon, un petit invoke pour permettre de rebasculer sur le bon thread et réappeler t'a méthode
Commenter la réponse de Perecastorr
Messages postés
834
Date d'inscription
samedi 15 novembre 2008
Statut
Membre
Dernière intervention
14 janvier 2017
26
0
Merci
Bonsoir,

En effet, Perecastorr à raison, il faut passer par un invoke pour déléguer l'execution.
un peu trop long à expliquer ici, mais il y a de bon tutoriaux en ligne.
cela dit, leprov à encore plus raison, il vaut mieux ne pas melanger les choses, mais parfois on ne peut faire autrement.

pour faire simple,
dans ta forme IMHReleve, déclare un delegate pour deleguer l'execution de ta methode SetPresenceSGBD à un autre thread.
Déplace le code dans une méhode prevée, et invoke si nécéssaire.

// un delegate pour déléguer l'execution.
private delegate void SetPresenceSGBDDelegate(bool sgbd);
// ici on vérifie si on doir passer par un invoke
public void SetPresenceSGBD(bool SGBD)
{
    if (this.InvokeRequired) // on invoke pour déléguer l'execution
        Invoke(new SetPresenceSGBDDelegate(_SetPresenceSGBD), SGBD);
    else // on peut y aller en direct
        _SetPresenceSGBD(SGBD);  
}
private void _SetPresenceSGBD(bool SGBD)
{
        if (SGBD)
        {
            lB_InfoVersSGBD.Text = "SGBD OK";
            gB_FichierSGBD.Visible = true;
        }
        else
           lB_InfoVersSGBD.Text = "SGBD NOK";

}



bon code...

C# is amazing, enjoy it!
Commenter la réponse de cs_Robert33
Messages postés
146
Date d'inscription
lundi 15 juin 2009
Statut
Membre
Dernière intervention
14 février 2013
0
Merci
Merci à vous,

En ce qui concerne le thread principal (la gestion ce n'est pas moi qui l'a gère), on est a plusieurs sur le projet.
Moi je m'occupe de l'IHM et donc je regarde actuellement comment le thread gestion va pouvoir me passer les infos.
C'est pas moi qui est repartie les taches :(

Par contre j'ai crée le thread Gestion (le principal), comme c'est lui qui me crée, cela se permet de voir comme cela se passe.

Voila ce que j'ai fait et cela marche merci :

public void SetPresenceSGBD(bool SGBD)
        {
            //Nessessaire pour 
            if (lB_InfoVersSGBD.InvokeRequired) 
            {
                lB_InfoVersSGBD.Invoke(new MethodInvoker(delegate { SetPresenceSGBD(SGBD); })); 
            } 
            else 
            { 
                if (SGBD)
                {
                    lB_InfoVersSGBD.Text = "SGBD OK";
                    if (gB_ListeCSV .Visible) gB_FichierSGBD.Visible = true;
                    _PresenceSGBD = true;
                }
                 else
                   lB_InfoVersSGBD.Text = "SGBD NOK";
                }
        }



Technicien en électricité Industriel (39 ans), en cours de reconversion BTS IRIS 2eme Année.
Au lycée pendant l'année scolaire, et en stage pendant les vacances scolaire.
Commenter la réponse de cs_megamario
Messages postés
834
Date d'inscription
samedi 15 novembre 2008
Statut
Membre
Dernière intervention
14 janvier 2017
26
0
Merci
Bonjour,

ta solution est correcte, c'est en fait la même chose que ce que je t'avais donné, mais avec le framework 3.5, la methode MethodInvoker(...) permet de le faire en une seule ligne .


C# is amazing, enjoy it!
Commenter la réponse de cs_Robert33