Croos-thread s - utilisation des delegates pour modifier des paramettre des cont
cs_megamario
Messages postés146Date d'inscriptionlundi 15 juin 2009StatutMembreDernière intervention14 février 2013
-
9 mars 2010 à 21:39
cs_Robert33
Messages postés834Date d'inscriptionsamedi 15 novembre 2008StatutMembreDernière intervention14 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:
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.
leprov
Messages postés1160Date d'inscriptionvendredi 23 juillet 2004StatutMembreDernière intervention21 octobre 201017 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.
Perecastorr
Messages postés39Date d'inscriptionlundi 10 novembre 2008StatutMembreDernière intervention 7 septembre 20101 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
cs_Robert33
Messages postés834Date d'inscriptionsamedi 15 novembre 2008StatutMembreDernière intervention14 janvier 201733 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";
}
cs_megamario
Messages postés146Date d'inscriptionlundi 15 juin 2009StatutMembreDernière intervention14 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.
Vous n’avez pas trouvé la réponse que vous recherchez ?
cs_Robert33
Messages postés834Date d'inscriptionsamedi 15 novembre 2008StatutMembreDernière intervention14 janvier 201733 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 .