1

我需要知道哪些處理程序被子集化爲ObservableCollection類的CollectionChanged事件。我發現的唯一解決方案是在事件的委託上使用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框架事件真的需要公開一個給予訂閱處理程序的屬性。 (順便說一句,我發現一篇文章描述了WinForms委託系統,但我需要這個。) – 2010-04-12 13:40:12