tags:

views:

228

answers:

7

Hi,

In my .NET application I am subscribing to events from another class. The subscription is conditional. I am subscribing to events when the control is visible and de-subscribing it when it become invisible. However in some conditions I do not want to de-subscribe the event even if the control is not visible as I want the result of an operation which is happening on background thread .

Is there any way through which I can determine if a that class has already subscribed to that event.

I know we can do it in the class which will raise that event by checking event with null but I don not know how to do it in a class which will subscribe to that event.

A: 

You might be able to use Delegate.GetInvocationList?

ho1
That's not available for an event.
Gorpik
@Gorpik: It is, but only from within the class the event is declared in. You would have to write some kind of method on the class to do the processing for you.
Simon P Stevens
@Simon P Stevens: Of course, if you have access to the class that defines the event, you can do whatever you want. But I am assuming that you don't.
Gorpik
A: 

Can't you just remember whether you already subscribed? That approach worked fine for me so far. Even if you have a lot of events or objects, you may still want to just remember that (in a dictionary, for example).

On the other hand, visibility change was, at least for me, not a good point to subscribe/unsubscribe. I typically rather go with construction / Disposed, which are more clear than each time visibility changes.

OregonGhost
+1  A: 

Assuming that you have no access to the innards of the class declaring the event, you have no way to do it directly. Events only expose operators += and -=, nothing else. You will need a flag or some other mechanism in your subscribing class to know whether you are already subscribed or not.

Gorpik
+1  A: 

Can you put the decision making logic into the method that fires the event? Assuming you're using Winforms it'd look something like this:

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

Where isCriteriaFulfilled is determined by your visible/invisible logic.

// UPDATES /////

Further to your 1st comment would it not make sense to alter the behaviour inside your event handler depending on the value of this.Visible?

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

Or if you really have to go with subscribing and unsubscribing:

 private Delegate _method1 = null;
...
if(this.visible) 
{
    if (_method1 == null)
        _method1 = new Delegate(method1);
    a.Delegate += _method1;
}
else if (_method1 != null)
{
    a.Delegate -= _method1;
} 
Phil
I wonder if `areCriteriaFulfilled` is better grammatically speaking?
Phil
I am doing as followsif(this.visible){ a.Delegate += new Delegate(method1);}else{ a.Delegate -= new Delegate(method1);}
Ram
@Ram: Updated answer.
Phil
I don't want to do as suggested by you as the events are triggered at regular interval and I want to use them only when my control is invisible. if I do what you are saying, it will be a performance hit.
Ram
@Ram: Updated again. But I'm still curious as to why you think it will impact performance? Subscribing to an event also has an overhead of allocating and (eventually) deallocating memory.
Phil
@Phil : Yes, I do agree that it will increase overhead. thanks. :)
Ram
+1  A: 

How about simply checking whether the control is visible or not whenever the event handler is triggered?

Amry
I don't want to do that as the events are triggered at regular interval and I want to use them only when my control is invisible. if I do what you are saying, it will be a performance hit.
Ram
@Ram: Why do you think it will be a performance hit? Have you measured the change in performance?
Phil
@Phil: Hi Phil, It is a performance hit as I am doing this with multiple forms and multiple events. Each form process the data diff way. So to avoid processing of data I am subscribing the events only is form is visible.I believe using boolean would be a good option.
Ram
+9  A: 

The event keyword was explicitly invented to prevent you from doing what you want to do. It makes the delegate object for the event inaccessible so nobody can mess with the events handlers. Windows Forms puts an extra layer of security in place so it becomes difficult even if you use Reflection. It stores delegate instances in an EventHandlerList with a secret "cookie", you'd have to know the cookie to dig the object out of the list.

Well, don't go there. It is trivial to solve your problem with a bit of code on your end:

private bool mSubscribed;

private void Subscribe(bool enabled) {
  if (!enabled) textBox1.VisibleChanged -= textBox1_VisibleChanged;
  else if (!mSubscribed) textBox1.VisibleChanged += textBox1_VisibleChanged;
  mSubscribed = enabled;
}
Hans Passant
A: 
  /// <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);
  }
SwDevMan81