2009-04-19 4 views
1

J'ai du mal à faire fonctionner un programme d'indexation de pages Web. J'ai un formulaire qui télécharge automatiquement les URL à indexer à partir d'un serveur de base de données et renvoie les réponses contenant les informations de la page indexée, sur UDP. J'ai une classe statique appelée UDP qui garde la trace des messages entrants et sortants. Il y a un événement qui se déclenche chaque fois qu'un message est reçu, que le formulaire qui contient tout le code d'indexation croise pour garder trace des messages envoyés par un programme sur le serveur qui contient la base de données d'URL à indexer.Comment puis-je appeler un gestionnaire d'événements à partir d'un thread distinct de celui sur lequel il a été créé?

Tout fonctionnait correctement, jusqu'à ce que j'ajoute un autre formulaire qui apparaît avant le formulaire d'indexation. Maintenant, le formulaire d'indexation s'ouvre sur un autre thread (via Application.Run() et un second thread). Le problème est que le gestionnaire d'événements n'est plus appelé lorsque l'événement est déclenché. Donc, la question est: que se passe-t-il ici, et que puis-je faire pour le réparer? Je suis certain qu'il s'agit d'un mécanisme de sécurité inter-thread qui n'appelle pas les gestionnaires d'événements sur un autre thread que celui sur lequel l'événement a été déclenché. Est-ce que quelqu'un sait d'une manière différente de faire ceci ou un moyen de contourner ceci? Merci d'avance ...

Répondre

3

Un contrôle d'interface utilisateur doit être manipulé sur le thread sur lequel il a été créé (le thread UI). Pour ce faire, vous devrez «invoquer» le gestionnaire d'événements.

Cela peut se faire en augmentant l'événement comme celui-ci:

EventHandler handler = myEventHandler; 
if(handler != null) 
{ 
    ISynchronizeInvoke target = handler.Target as ISynchronizeInvoke; 

    if(target != null && target.InvokeRequired) 
    { 
     target.Invoke (handler, ...); 
    } 
    else 
    { 
     handler.DynamicInvoke (...); 
    } 
} 

Ou, vous pouvez aussi consulter les AsyncOperation & AsyncOperationManager classes.

Ou, peut-être même plus simple, jetez un oeil à la classe SynchronizationContext. En utilisant la propriété 'Current' de cette classe, vous pouvez simplement publier un délégué SendOrPostCallback qui entoure votre eventhandler.

+0

Il n'est généralement pas nécessaire d'utiliser DynamicInvoke ici - il suffit de l'invoquer.Il est également plus commun pour la * cible * de le faire ... –

0

Je ne pense pas que ce soit un "mécanisme de sécurité". Le mécanisme de sécurité existant dans WinForms (à partir de .NET 2.0) envoie une exception si vous êtes dans le débogueur et que vous essayez d'accéder à l'interface utilisateur à partir d'un thread autre que celui approprié.

Etes-vous sûr que l'événement n'est pas appelé ? Cela semble extrêmement étrange. Si vous placez un point d'arrêt sur le gestionnaire d'événements dans le débogueur, ce point d'arrêt n'est-il pas touché?

Pour répondre différemment à votre question, je ne ferais pas exécuter le gestionnaire d'événement entier sur un thread spécifique. Il peut y avoir plus d'un gestionnaire souscrit, et ces gestionnaires peuvent avoir besoin de s'exécuter sur des threads différents. Au lieu de cela, je rendrais les gestionnaires d'événements eux-mêmes thread-safe - les coder de sorte que s'ils ont besoin d'effectuer une action sur un thread particulier, ils retournent au thread (par exemple avec Control.BeginInvoke etc).

Sur quel fil se déroule la plupart de vos accès réseau? J'espère que ce n'est pas des threads d'interface utilisateur impliqués (sinon, vous pouvez obtenir une interface utilisateur ne répond pas). Cela signifierait que si cela fonctionnait avant, vous faites probablement déjà le marshalling approprié ... très étrange.

Si rien de tout cela ne vous aide, pourriez-vous essayer de trouver un programme court mais complet qui démontre le problème? Il est plus facile de diagnostiquer le code concret :)

Questions connexes