1

Мне нужно знать, какие обработчики связаны с событием CollectionChanged класса ObservableCollection. Единственным решением, которое я нашел, было бы использование Delegate.GetInvocationList() для делегата события. Проблема в том, что я не могу заставить Reflection найти компилятор, сгенерированный делегатом. AFAIK делегат имеет то же название, что и событие. Я использовал следующий кусок кода:Получить компилятор сгенерированный делегат для события

PropertyInfo notifyCollectionChangedDelegate = collection.GetType().GetProperty("CollectionChanged", BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); 

ответ

4

не является свойством, это поле. Это работает:

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); 
    } 
    } 
} 

Не используйте его.

1

Весь смысл событий является то, что они инкапсулировать публикации/подписки природы без обнажая в настоящее время подписался обработчики. Вам не нужно знать подписанных обработчиков - если вы это сделаете, вы должны использовать свой собственный тип вместо ObservableCollection. Что ты пытаешься сделать?

Нет ничего, чтобы гарантировать, что является полем делегатов, созданных компилятором. Возможно, это не было объявлено с помощью поля-подобного события - действительно, даже не может быть отдельного поля для делегата поддержки. (Вероятно, это связано с тем, что на ObservableCollection не так много событий, но элементы управления WinForms используют лениво распределенную карту, чтобы избежать необходимости иметь одно поле на событие, когда большинство событий не имеют подписанных обработчиков.)

+0

Моя цель - управлять подпиской на событие NotifyCollectionChanged, но мне нужно подписаться только один раз. Я не хочу управлять логическим полем для каждого ObservableCollection для хранения этой информации. (Подписка происходит в местах, которые вызывается несколько раз.) Итак, проще всего проверить, подписан ли я уже с обработчиком. Либо мне не хватает чего-то очень простого здесь, либо событие .net framework действительно нужно будет выставить свойство, которое возвращает подписанных обработчиков. (Кстати, ранее я нашел статью, описывающую систему делегатов WinForms, но мне это было нужно.) –