68 votes

Comment déterminer si un événement est déjà souscrit ?

Dans mon application .NET, je m'abonne à des événements provenant d'une autre classe. L'abonnement est conditionnel. Je m'abonne aux événements lorsque le contrôle est visible et je m'en désabonne lorsqu'il devient invisible. Cependant, dans certaines conditions, je ne veux pas me désabonner de l'événement même si le contrôle n'est pas visible, car je veux obtenir le résultat d'une opération qui se déroule sur un fil d'arrière-plan.

Existe-t-il un moyen de déterminer si une classe a déjà souscrit à cet événement ?

Je sais que nous pouvons le faire dans la classe qui va lever cet événement en vérifiant l'événement pour null Mais comment le faire dans une classe qui s'abonne à cet événement ?

2 votes

0 votes

Si c'est seulement pour savoir si quelqu'un est abonné : "bool subscribedTo = theEvent != null".

89voto

Hans Passant Points 475940

El event a été explicitement inventé pour vous empêcher de faire ce que vous voulez faire. Il restreint l'accès à la base de données delegate de sorte que personne ne puisse toucher directement aux abonnements aux gestionnaires d'événements qu'il stocke. Les événements sont accesseurs pour un délégué, tout comme une propriété est un accesseur pour un champ. Une propriété ne permet que le get et le set, un événement ne permet que l'add et le remove.

Cela permet de sécuriser votre code, car un autre code ne peut supprimer un gestionnaire d'événement que s'il connaît la méthode du gestionnaire d'événement et l'objet cible. Le langage C# met en place une couche supplémentaire de sécurité en ne vous permettant pas de nommer l'objet cible.

Et WinForms met en place une couche de sécurité supplémentaire, de sorte que cela devient difficile même si vous utilisez Reflection. Il stocke delegate instances dans un EventHandlerList avec un "cookie" secret comme clé, il faudrait connaître le cookie pour extraire l'objet de la liste.

Eh bien, n'y allez pas. Il est trivial de résoudre votre problème avec un peu de code de votre côté :

private bool mSubscribed;

private void Subscribe(bool enabled)
{
    if (!enabled) textBox1.VisibleChanged -= textBox1_VisibleChanged;
    else if (!mSubscribed) textBox1.VisibleChanged += textBox1_VisibleChanged;

    mSubscribed = enabled;
}

4 votes

Auriez-vous, par hasard, des blogs, des vidéos de Channel 9 ou des articles de MSDN qui parlent de la méthodologie de conception derrière la réalisation de l'ouvrage ? événements si difficile d'interagir avec lui ? Peut-être que si je comprenais le pourquoi et ce que le prévu mécanismes pour accomplir certaines choses (normalement) triviales, je pourrais avoir plus de facilité à trouver des solutions triviales à mes propres problèmes.

3 votes

Il n'est pas difficile d'interagir avec vos événements. Interagir avec de quelqu'un d'autre les événements sont rendus difficiles, c'est jouer avec les parties privées. Posez une question à ce sujet.

3 votes

Ok, pourquoi est-il difficile de jouer avec les événements de quelqu'un d'autre ?

8voto

Gorpik Points 7276

En supposant que vous n'ayez pas accès aux entrailles de la classe déclarant l'événement, vous n'avez aucun moyen de le faire directement. Les événements n'exposent que des opérateurs += y -= et rien d'autre. Vous aurez besoin d'un drapeau ou d'un autre mécanisme dans votre classe d'abonnement pour savoir si vous êtes déjà abonné ou non.

6voto

SwDevMan81 Points 22634
  /// <summary>
  /// Determine if a control has the event visible subscribed to
  /// </summary>
  /// <param name="controlObject">The control to look for the VisibleChanged event</param>
  /// <returns>True if the control is subscribed to a VisibleChanged event, False otherwise</returns>
  private bool IsSubscribed(Control controlObject)
  {
     FieldInfo event_visible_field_info = typeof(Control).GetField("EventVisible",
        BindingFlags.Static | BindingFlags.NonPublic);
     object object_value = event_visible_field_info.GetValue(controlObject);
     PropertyInfo events_property_info = controlObject.GetType().GetProperty("Events",
        BindingFlags.NonPublic | BindingFlags.Instance);
     EventHandlerList event_list = (EventHandlerList)events_property_info.GetValue(controlObject, null);
     return (event_list[object_value] != null);
  }

0 votes

Qu'est-ce que l'objet "Contrôle" ? Quel usage dois-je faire de ce script de "Control" ?

2voto

Amry Points 2113

Il suffit de vérifier si le contrôle est visible ou non lorsque le gestionnaire d'événements est déclenché.

0 votes

Je ne veux pas faire cela car les événements sont déclenchés à intervalles réguliers et je veux les utiliser uniquement lorsque mon contrôle est invisible. Si je fais ce que vous dites, les performances seront affectées.

0 votes

@Ram : Pourquoi pensez-vous que les performances seront affectées ? Avez-vous mesuré le changement de performance ?

0 votes

@Phil : Salut Phil, C'est un problème de performance car je fais cela avec plusieurs formulaires et plusieurs événements. Chaque formulaire traite les données de manière différente. Ainsi, pour éviter le traitement des données, je souscris aux événements uniquement lorsque le formulaire est visible. Je pense que l'utilisation de booléens serait une bonne option.

1voto

Phil Gan Points 1859

Pouvez-vous placer la logique de prise de décision dans la méthode qui déclenche l'événement ? En supposant que vous utilisez Winforms, cela ressemblerait à quelque chose comme ceci :

 if (MyEvent != null && isCriteriaFulfilled)
{
    MyEvent();
}

isCriteriaFulfilled est déterminé par votre logique visible/invisible.

// MISES À JOUR /////

Suite à votre 1er commentaire, ne serait-il pas judicieux de modifier le comportement de votre gestionnaire d'événements en fonction de la valeur de la variable this.Visible ?

 a.Delegate += new Delegate(method1);
...
private void method1()
{
    if (this.Visible)
        // Do Stuff
}

Ou si vous devez vraiment vous abonner et vous désabonner :

 private Delegate _method1 = null;
...
if(this.visible) 
{
    if (_method1 == null)
        _method1 = new Delegate(method1);
    a.Delegate += _method1;
}
else if (_method1 != null)
{
    a.Delegate -= _method1;
}

1 votes

Je me demande si areCriteriaFulfilled est meilleur d'un point de vue grammatical ?

0 votes

Je procède comme suit if(this.visible) { a.Delegate += new Delegate(method1) ; } else { a.Delegate -= new Delegate(method1) ; }

0 votes

Je ne veux pas faire ce que vous suggérez car les événements sont déclenchés à intervalles réguliers et je veux les utiliser uniquement lorsque mon contrôle est invisible. Si je fais ce que vous dites, les performances seront affectées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X