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

cs_megamario Messages postés 145 Date d'inscription lundi 15 juin 2009 Statut Membre Dernière intervention 14 février 2013 - 9 mars 2010 à 21:39
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.

5 réponses

leprov Messages postés 1160 Date d'inscription vendredi 23 juillet 2004 Statut Membre Dernière intervention 21 octobre 2010 17
10 mars 2010 à 12:42
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.
0
Perecastorr Messages postés 39 Date d'inscription lundi 10 novembre 2008 Statut Membre Dernière intervention 7 septembre 2010 1
12 mars 2010 à 10:19
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
0
cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 33
13 mars 2010 à 21:41
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!
0
cs_megamario Messages postés 145 Date d'inscription lundi 15 juin 2009 Statut Membre Dernière intervention 14 février 2013
13 mars 2010 à 21:55
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.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Robert33 Messages postés 834 Date d'inscription samedi 15 novembre 2008 Statut Membre Dernière intervention 14 janvier 2017 33
14 mars 2010 à 09:01
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!
0
Rejoignez-nous