2008-10-23 19 views
2

J'ai une application serveur qui reçoit des informations sur un réseau et les traite. Le serveur est multithread et gère plusieurs sockets à la fois, et les threads sont créés sans mon contrôle via les méthodes de style BeginInvoke et EndInvoke, qui sont chaînées par les fonctions de rappel correspondantes.J'ai besoin d'aide pour obtenir des informations sur un thread d'interface utilisateur et un autre thread dans C#

J'essaie de créer un formulaire, en plus de l'interface graphique principale, qui affiche un élément ListBox rempli d'éléments décrivant les sockets actuellement connectés. Donc, ce que je suis en train d'essayer de faire est d'ajouter un élément à la ListBox en utilisant sa fonction Add(), à partir du thread sur lequel la fonction de rappel appropriée s'exécute. J'accès à mes contrôles de formulaires par la propriété Controls - IE:

(ListBox)c.Controls["listBox1"].Items.Add(); 

Naturellement, je ne pas simplement appeler la fonction, je l'ai essayé plusieurs façons que j'ai trouvé ici et sur le Web pour communiquer entre threads, y compris MethodInvoker, en utilisant un delegate, en combinaison avec Invoke(), BeginInvoke() etc Rien ne semble fonctionner, je reçois toujours la même exception en me disant que mon contrôle a été accédé à partir d'un thread autre que celui sur lequel il a été créé.

Des pensées?

+0

Une subtilité pertinente est que, si vous lisez d'un contrôle, vous voulez généralement utiliser Invoke au lieu de BeginInvoke pour assurer la variable de destination dans le thread courant est peuplé avant de continuer. Je ne pense pas que nous ayons encore des contrats à terme. :) –

Répondre

2

Vous devez appeler Invoke (ou BeginInvoke) sur le contrôle ListBox vous accédez pour que le délégué à appeler sur le fil qui a créé ce contrôle.

ListBox listBox = c.Controls["listBox1"] as ListBox; 
if(listBox != null) 
{ 
    listBox.Invoke(...); 
} 
2

L'utilisation de BeginInvoke ou Invoke devrait fonctionner correctement. Pourriez-vous poster un programme court mais complet qui démontre le problème? Vous devriez être capable d'en faire un qui n'a pas vraiment besoin de choses côté serveur - il suffit d'avoir un tas de threads qui "prétendent" recevoir des connexions entrantes.

5

J'ai toujours utilisé quelque chose le long de ces lignes:

 c = <your control> 
     if (c.InvokeRequired) 
     { 
      c.BeginInvoke((MethodInvoker)delegate 
      { 
       //do something with c 
      }); 
     } 
     else 
     { 
      //do something with c 
     } 

J'ai aussi écrit un tas de méthodes d'extension d'assistance pour ... l'aide.

using System; 
using System.ComponentModel; 
public static class CrossThreadHelper 
{ 
    public static bool CrossThread<T,R>(this ISynchronizeInvoke value, Action<T, R> action, T sender, R e) 
    { 
     if (value.InvokeRequired) 
     { 
      value.BeginInvoke(action, new object[] { sender, e }); 
     } 

     return value.InvokeRequired; 
    } 
} 

utilisé comme ceci:

 private void OnServerMessageReceived(object sender, ClientStateArgs e) 
    { 
     if (this.CrossThread((se, ev) => OnServerMessageReceived(se, ev), sender, e)) return; 
     this.statusTextBox.Text += string.Format("Message Received From: {0}\r\n", e.ClientState); 
    } 
+0

Pourquoi ne pas simplement une méthode d'extension qui accepte une action ou MethodInvoker? Beaucoup plus propre, et l'appelant peut toujours remplir le reste dans le délégué –

+0

@ Marc - bon point que je vais le changer. – Hath