2010-10-30 6 views
4

Je comprends qu'un gestionnaire d'événements s'exécute sur n'importe quel thread qui a appelé l'événement. Je comprends également le besoin de mettre à jour les contrôles de formulaire uniquement à partir du thread qui a créé les contrôles. Je suppose que le fil de l'interface utilisateur est celui qui a créé le formulaire dans le but de cette question.Evénements, threads et messages .NET

Si l'événement est le résultat d'un message publié, tel qu'un message de peinture, le gestionnaire n'est-il pas découplé du thread d'origine? Si cela est vrai, n'importe quel thread pourrait invoquer des opérations d'invalidation et la peinture résultante se produirait toujours sur le thread de l'interface utilisateur puisque c'est le seul qui gère les messages du formulaire.

Voici comment cela se passe dans ma tête vers 2h00 du matin avec un bol de collation vide à côté de moi. S'il vous plaît clarifier et corriger afin que je puisse avoir une bonne compréhension des mécanismes au travail.

Répondre

5

MSDN:

appel de la méthode Invalidate ne force pas une peinture synchrone; Pour forcer une peinture synchrone, appelez la méthode Update après avoir appelé la méthode Invalidate. Par conséquent, Invalidate peut être appelée à partir de n'importe quel thread et mise à jour uniquement à partir du thread d'interface utilisateur. Dans tous les cas, pour être sûr à 100% que vous n'utilisez pas d'appels de thread croisés non valides, définissez la propriété Control :: CheckForIllegalCrossThreadCalls sur true au début du programme. Cela provoque tout échec d'appel immédiatement, vous n'avez pas besoin de deviner.

+0

L'appel de 'Update' après' Invalidate' revient à appeler 'Refresh', ce qui aurait dû être appelé depuis le thread de l'interface utilisateur. –

1

Tout d'abord, voir la réponse d'Alex. En second lieu, notez que le simple fait de faire quelque chose qui aboutit à un pompage de message provoquant un événement sur le thread d'interface utilisateur ne signifie absolument pas que l'action initiatrice doit avoir lieu sur ce même thread.

Je parle très largement ici; mais notez que n'importe quel code pourrait en interne rassembler des choses sur le thread UI en appelant Control.Invoke() ou un équivalent.

Dans votre propre code d'application, vous devez être sûr de le faire, bien sûr. Mais je suggère simplement que si vous trouvez un code quelque part qui semble violer le principe ici, c'est probablement Invoke() quelque part pour vous.

0

Même s'il est techniquement possible de le faire, vous aurez des problèmes. Le code pour Invalidate est le suivant:

public void Invalidate(bool invalidateChildren) { 
    if (IsHandleCreated) { 
     if (invalidateChildren) { 
      SafeNativeMethods.RedrawWindow(new HandleRef(window, Handle), 
              null, NativeMethods.NullHandleRef, 
              NativeMethods.RDW_INVALIDATE | 
              NativeMethods.RDW_ERASE | 
              NativeMethods.RDW_ALLCHILDREN); 
     } 
     else { 
      // It's safe to invoke InvalidateRect from a separate thread. 
      using (new MultithreadSafeCallScope()) 
      { 
       SafeNativeMethods.InvalidateRect(new HandleRef(window, Handle), 
               null, 
               (controlStyle & ControlStyles.Opaque) != ControlStyles.Opaque); 
      } 
     } 

     NotifyInvalidate(this.ClientRectangle); 
    } 
} 

Il y a quelques problèmes ici:

  1. Si le Form est disposé après la IsHandleCreated vérification est effectuée, la poignée sera parti;

  2. Le NotifyInvalidate qui appelle OnInvalidated qui déclenche l'événement Invalidated sera appelé sur le thread appelant. Les gestionnaires enregistrés à cet événement ne peuvent pas s'attendre à ce qu'il ait été appelé à partir d'un thread différent;

  3. Même si cela indique que InvalidateRect peut être appelé à partir d'un thread séparé, il n'indique pas si RedrawWindow peut. La question devient donc si vous appelez Invalidate(false) (ou Invalidate(), cela correspond à false) ou vous appelez Invalidate(true).

Longue histoire courte. Vous ne devriez pas appeler cela depuis un thread différent. Vous devez appeler toutes les méthodes qui interagissent avec un Control (ainsi également Form) via Invoke ou BeginInvoke.

Questions connexes