1

I need to know what handlers are subsribed to the CollectionChanged event of the ObservableCollection class. The only solution I found would be to use Delegate.GetInvocationList() on the delegate of the event. The problem is, I can't get Reflection to find the compiler generated delegate. AFAIK the delegate has the same name as the event. I used the following piece of code:

PropertyInfo notifyCollectionChangedDelegate = collection.GetType().GetProperty("CollectionChanged", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
Sandor Davidhazi
  • 888
  • 1
  • 9
  • 20

2 Answers2

4

It is not a property, it is a field. This works:

using System;
using System.Collections.ObjectModel;  // Add reference to WindowsBase
using System.Collections.Specialized;
using System.Reflection;

namespace ConsoleApplication1 {
  class Program {
    static void Main(string[] args) {
      var coll = new ObservableCollection<int>();
      coll.CollectionChanged += coll_CollectionChanged;
      coll.Add(42);
      FieldInfo fi = coll.GetType().GetField("CollectionChanged", BindingFlags.NonPublic | BindingFlags.Instance);
      NotifyCollectionChangedEventHandler handler = fi.GetValue(coll) as NotifyCollectionChangedEventHandler;
      handler.Invoke(coll, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    static void coll_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
      Console.WriteLine("Changed {0}", e.Action);
    }
  }
}

Don't use it.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

The whole point of events is that they encapsulate the publish/subscribe nature without exposing the currently subscribed handlers. You shouldn't need to know the subscribed handlers - if you do, you should use your own type instead of ObservableCollection. What are you trying to do?

There's nothing to guarantee that there is a compiler-generated delegate field. It may not have been declared using a field-like event - indeed, there may not even be a single field for the backing delegate at all. (There probably is, given that there aren't many events on ObservableCollection - but WinForms controls use a lazily allocated map to avoid having to have one field per event, when most events won't have subscribed handlers.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • My aim is to manage subscription to the NotifyCollectionChanged event, but I need to subscribe only once. I don't want to manage a boolean field for every ObservableCollection to hold this information. (Subscription happens in places which get called multiple times.) So the simplest is to check if I'm already subscribed with a handler. Either I'm missing something very simple here, or a .net framework event would really need to expose a property which gives back the subscribed handlers. (BTW I found an article describing the WinForms delegate system earlier, but I needed this.) – Sandor Davidhazi Apr 12 '10 at 13:40