2009-07-01 5 views
8

Je vous écris une petite application de chat, et j'ai ce gestionnaire d'événements:C#, Event Handlers et Threading

void o_Typing(object sender, EventArgs e) 
{ 
    MessageBox.Show("Fired!"); 
    this.Text = "Fired!"; 
} 

o_Typing est une méthode dans une classe dérivée de TabPage. Fondamentalement, je veux que chaque conversation ait son propre onglet.

Les gestionnaires d'événements sont déclenchés par mon objet Chat, qui s'exécute dans un autre thread. J'ai 1 thread pour l'interface utilisateur, et un autre thread pour chaque conversation Chat (pour continuer à interroger le serveur pour les nouvelles données)

Lorsque l'événement est déclenché, le MessageBox apparaît, mais la légende onglet ne change pas. Une fois que l'événement a été déclenché une fois, il ne se déclenche plus, ce qui me porte à croire que l'événement est appelé dans le thread de travail, bien qu'il soit défini dans le thread de l'interface utilisateur.

Comment puis-je appeler mes événements à partir du thread de travail et utiliser Invoke() pour les exécuter sur le thread de l'interface utilisateur?

Répondre

11

Il y a deux options:

1) Marque thread-safe les gestionnaires d'événements: utilisez Control.Invoke/BeginInvoke dans un gestionnaire d'événements qui a besoin de parler au fil de l'interface utilisateur. 2) Remettre le maréchal de travail dans le thread d'interface utilisateur avant de déclencher l'événement - en d'autres termes, utiliser Control.Invoke dans le cadre du processus de lancement de l'événement, de sorte que les gestionnaires d'événements soient tous appelés dans le thread de l'interface utilisateur . En fonction de la structure de votre application, vous ne souhaiterez peut-être pas que votre composant événementiel en connaisse explicitement l'interface utilisateur. Cependant, lors de sa construction, vous pouvez passer un ISynchronizeInvoke (que Control implémente) et votre composant peut l'utiliser pour augmenter ses événements sur le bon fil. Bien sûr, cela ne fonctionne que (tout simplement, de toute façon) si chaque gestionnaire d'événements est heureux de fonctionner sur le même thread - mais ce sera souvent le cas. Vous écririez quelque chose comme:

protected void OnFoo(EventArgs args) 
{ 
    if (sync != null && sync.InvokeRequired) 
    { 
     sync.Invoke((Action) delegate { OnFoo(args) }, null); 
     return; 
    } 
    EventHandler handler = Foo; // Where Foo is the event name 
    if (handler != null) 
    { 
     handler (this, args); 
    } 
} 
+0

Merci, j'ai utilisé Invoke() sur le gestionnaire d'événements et cela a fonctionné comme un charme. –

6

Si vous déclenchez votre événement dans du code exécuté par votre thread de travail, toutes les méthodes souscrites à cet événement seront exécutées sous ce thread de travail.

Pour les éléments GUI, vous devez consulter les méthodes Invoke.

Cordialement

+0

Merci pour la réponse, voir mon édition. –

+0

Ce n'est pas le cas. Vous appelez l'événement sur votre thread de travail, et chaque abonné doit vérifier s'il se trouve sur le bon thread et s'appeler lui-même s'il le faut. –

+0

Ou, apparemment, vous pouvez faire ce que Jon suggère. –