Problème de thread. Fenêtre et thread externe. [Résolu]

Signaler
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005
-
Messages postés
1
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
8 mai 2006
-
Bonjour tout le monde !

J'aimerais vous relater un problème qui m'arrive dans mon projet en ce moment.

J'ai une classe externe (Socket_Serveur) et j'ai ma fenêtre principale.
Dans cette fenêtre, j'ai une ListBox où j'aimerais afficher des infos concernant le serveur, genre : conecté, envoie du message, etc ...
En respectant le principe d'une faible couplage, j'aimerais que ma classe puisse afficher ces méthodes pour n'importe quelle ListBox. Vous me suivez jusque là ?
Donc dans ma classe (Socket_Serveur), j'ai une méthode qui écoute en continu si un client demande une connexion et donc veut envoyer un message au serveur. Pour ne pas surcharger le processeur, je l'ai mise dans un thread.
Donc nous voyons bien qu'il y a deux threads, un pour afficher la fenêtre et son ensemble (écoute d'événements) et mon thread d'ecoute du port désigné. Suis-je compréhensible ?
Enfin, pour utiliser l'afficher sur n'importe quelle listbox, je déclare un nouveau membre qui est une listbox. A l'instanciation, je met la listbox de ma fenêtre. (L'instanciation se fait bien sur dans le code de la fenêtre),
Genre : Socket_Serveur serv = new Socket_Serveur(port, this.ListeBoxe);
Et bien dès que je veux afficher, j'ai une exception : du genre crossthreading interdit. Il me dit exactement : Le thread où la listbox a été instanciée n'est pas le même que celui où vous l'utilisez.

Est-ce assez clair, je l'espère ...

Voilà, sur cela, je vous laisse.
Malgré la longueur du message, j'espère avoir été clair et attends une réponse rapide de votre part (c'est assez crucial pour mon projet).
Merci d'avance. Ivanoff.

11 réponses

Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
87
exemple :


Thread m_thread;

private void ThreadProc()
{
MessageDelegate message = new MessageDelegate(OnMessage);
object[] objs = new object[1];

for ( int i=0; i <10; i++ )
{
// ajout du message au listbox
objs[0] = i.ToString();
listBox.Invoke(message, objs);

// légère attente
Thread.Sleep(500);
}
}

// delegate qui sera utilisé pour l'"envoi" du message au controle
private delegate void MessageDelegate ( string message );

// la méthode qui fera l'insertion du message
private void OnMessage ( string message )
{
listBox.Items.Add("Message recu : " + message );
}

private void button1_Click(object sender, System.EventArgs e)
{
m_thread.Start();
}

sans oublier dans le constructeur du Form :

m_thread = new Thread(new ThreadStart(ThreadProc));

Cocoricoooooooo !!!!
coq
MVP Visual C#
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
87
Invoke permet d'effectuer l'action (dans notre cas l'ajout d'item) dans le contexte du thread auquel "appartient" le controle, et non dans notre thread.

Cocoricoooooooo !!!!
coq
MVP Visual C#
Messages postés
1182
Date d'inscription
mercredi 21 janvier 2004
Statut
Membre
Dernière intervention
6 septembre 2011
13
ben l'exception a l'air clair...
tu genere une listbox a partir de ton thread d'ecoute qui doit etre gerer par le thread d'affichage et il aime pas ca....

donc le mieux serait de t'arranger pour que ton thread d'ecoute passe le message a ton thread d'affichage du type "ca y est genere ton listbox..."

en gros...


Arthenius

"Il n'y a pas de mauvais développeurs,...
mais uniquement de mauvais utilisateurs..."
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
87
ce sujet parle du même problème :
http://www.csharpfr.com/forum.v2.aspx?ID=356593
tu n'as plus qu'a adapter :-)

Cocoricoooooooo !!!!
coq
MVP Visual C#
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005

Merci d'avoir répond aussitôt !

Le problème c'est que ça ne repond pas exactement a mon problème. Certes, cela y ressemble, mais le problème est que tout se gère dans le fenêtre.
Or je veux que ce soit ma deuxième classe (Socket_Serveur) qui envoie une message à la listbox pour afficher à chaque fois que le serveur reçoit une demande de connexion un message dans la listbox.
Pour être plus clair, je vais vous donner une partie de mon code :

Pour la classe socket_serveur :

/// <summary>



/// <c>Permet de traiter chaque client en attente</c>



/// </summary>



protected
void Sockets_Connectes()


{



while (
true)


{



this.Liste_De_Lecture.Clear();



for (
int i = 0; i <
this.Ensemble_Des_Clients.Count; i++)


{



this.Liste_De_Lecture.Add((
Socket)
this.Ensemble_Des_Clients[i]);


}



if (
this.Liste_De_Lecture.Count > 0)


{


/* Détermine le statut des sockets dans la liste *



Socket.Select(
this.Liste_De_Lecture,
null,
null, 1000);


/* Pour chacun d'entre eux */



for (
int i = 0; i <
this.Liste_De_Lecture.Count; i++)


{



string Message =
"";


/* Tant que l'on reçoit des données, on les traite



while (((
Socket)
this.Liste_De_Lecture[i]).Available > 0)


{



byte[] donnees =
new
byte[
this.Taille_Tampon];


((
Socket)
this.Liste_De_Lecture[i]).Receive(donnees);


Message +=
Encoding.Default.GetString(donnees);


}


/* C EST ICI QUE JE VEUX FAIRE :
* this.malistbox.items.add("Message recu : " + Message); */
}


}


/* On ne surcharge pas trop le processeur */



Thread.Sleep(10);


}


}

Et dans la fenêtre Fserveur, lors du chargement de la fenêtre, on a :


public
Fserveur()


{

Socket_Serveur serv = new (numPort, tailleDonnees, this.listBoxe);
}

Puis lors de l'ouverture, on a juste :


private
void Form1_Load(
object sender,
EventArgs e)


{


serv.CommencerEcoute();




}



Et dans commencer ecoute, on a la méthode citée plus haut, celle qui pose problème.

Je suis désolé mais je en vois pas comment adapter la source ...

En effet la méthode que je vous ai présentée est placée dans une boule infinie, donc c'est à chaque "tour", donc dès qu'un client demande une connexion, qu'on affiche un message dans la listbox.

Merci d'avance, pour vos réponses, et en espérant une nouvelle réponse de votre part.

Ivanoff
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005

Merci le coq !!

Vraiment merci beaucoup !!
Je te serai eternellement reconnaissant de mavoir aider !

Commen savai tu cela ?

Ivanoff, heureux
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005

Le bouton d'acceptation de la réponse ne marche pas !
Pourquoi ?
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005

Non c'est bon sa fonctionne, désolé.
Messages postés
6351
Date d'inscription
samedi 1 juin 2002
Statut
Modérateur
Dernière intervention
2 août 2014
87
euh ba au fur et à mesure on apprend pas mal de choses lol

pour le bouton accepter si il fonctionne : regle ton anti-popup pour qu'il les laisse passer sur ce site ^^

Cocoricoooooooo !!!!
coq
MVP Visual C#
Messages postés
99
Date d'inscription
lundi 14 octobre 2002
Statut
Membre
Dernière intervention
28 décembre 2005

Je suis désolé de revenir à la charge mais j'ai un nouveau problème pour les threads.

Vu que je devais le répéter dans bon nombre de classes,j'ai décidé de faire une classe spécifique pour ce lien vers la listbox.

J'ai créé une classe mère qui est générale pour tout objet. Et j'ai créé une classe fille héritant de cette sur-classe fonctionnant pour une listbox (et j'ai l'intention de le faire pour la combo, ...)

Voila je la crée, je l'instancie dans ma classe Socket_Serveur, et là : Toujours le même problème d'illegal threads....

Je vous file le code :
Ma classe spécifique à l'affichage :


public
abstract
class
Controleur_Affichage


{


/* Délégué permettant l'affichage



protected
delegate
void
MessageDelegue(
string message);


/* Handle du délégué



protected
Controleur_Affichage.
MessageDelegue MessageD;



private
object Controle;



public
Controleur_Affichage(
object controle)


{



this.Mon_Controle = controle;


}



///



/// Méthode permettant l'affichage dans le controle voulu



///



/// "message">Message à affiche



protected
abstract
void OnMessage(
string message);








/* ****************************************************************************** */


/* ************************** ACCESSEURS **************************************** */


/* ****************************************************************************** */



///



/// Accesseur du controle



///



///



protected
object Mon_Controle


{



get


{



return
this.Controle;


}



set


{



this.Controle =
value;


}


}


}



///



/// Classe permettant de gérer l'affichage dans une listbox entre un thread et une For



///



public
class
ControleurAffichage_ListBox :
Controleur_Affichage


{



///



/// Constructeur de la classe dérivÃ



///



/// "lb">ListBox où l'on va afficher les message



public
ControleurAffichage_ListBox(
ListBox lb) :
base( (
object)lb)


{



base.Mon_Controle = lb;



base.MessageD =
new
MessageDelegue(
this.Ajouter_Message);


}



public
void Ajouter_Message(
string Message)


{



object[] objs =
new
object[1];


objs.SetValue(Message, 0);



this.Ma_ListeBox.Invoke(
base.MessageD, objs);


}



///



/// Méthode permettant l'affichage dans le controle voulu



///



/// "message">Message à affiche



protected
override
void OnMessage(
string message)


{



this.Ma_ListeBox.Items.Add(message);


}








/* ****************************************************************************** */


/* ************************** ACCESSEURS **************************************** */


/* ****************************************************************************** */



///



/// Permet de récupérer la listeb



///



///



private
ListBox Ma_ListeBox


{



get


{



return ((
ListBox)
base.Mon_Controle);


}


}


}


}

Et voici son utilisation dans la classe Socket_Serveur :

while(true)
{
.....
.....



this.Mon_Afficheur.Ajouter_Message(
"Essai" + i.ToString());



}

Mon afficheur est une instance de la classe fille de gestion d'affichage.
Il est instancié dans la classe Socket_Serveur (dans le constructeur).

Merci d'avance de votre aide !
Et encore désolé de n'être qu'un novice dans les threads.

Pourrais-je avoir des explications quant à l'explication de l'utilisation obligatoire de invoke et des délégués.

Merci beaucoup.

Ivanoff, inquiet....
Messages postés
1
Date d'inscription
jeudi 24 avril 2003
Statut
Membre
Dernière intervention
8 mai 2006

Bonjour j'ai un petit problème.

Voilà j'ai un TreeView qui reconstruit l'arborescence de mon FileSystem.
J'ai activé l'option checkboxes du treeView.
lorsque je sélectionne un node, je stocke le chemin de ce node dans une arraylist.

j'ai également un watcher qui écoute et détecte lorsqu'un répertoire est créé, renommé ou supprimé.

Je voudrais donc à chaque fois remettre à jour mon treeview. pour ça j'ai suivi la méthode proposé coq ci-dessus.
Le treeview se met à jour sans problème.
Le problème est que lorsque je parcours le nouveau treeview, je fais un test du style
foreach(string s in listeRepertoireEcoute){
if(node.fullPath() == s){
node.checked = true;
}
}

afin de cocher tous les nodes qui étaient cochés avec de faire la mise à jour du treeview.

Mais cela ne fonctionne pas, aucun node n'est séléctionné. pourtant il passe bien dans la condition et passe également sur le node.checked = true.

Quelqu'un aurait-il une idée

Merci d'avance