仅当此事件没有处理程序时才添加AddHandler?

时间:2010-01-25 07:08:15

标签: vb.net delegates event-handling

我想设置一个事件处理程序,如果没有设置:

If GetHandlers(MyWindow.Closed, AddressOf MyWindow_Closed).Length = 0 Then
    AddHandler MyWindow.Closed, AddressOf MyWindow_Closed
EndIf

1 个答案:

答案 0 :(得分:2)

除了定义事件的代码之外,您无法真正查询事件委托的当前值。你的意图是什么?通常你不应该过于担心(必然)与其他订阅者?有一些方法可以通过封装来找到当前值,但是它们推荐(这不是一个好主意)。

如果您关心的是您是否已经使用那个处理程序处理该事件(即您不想双重订阅,那么您始终可以:修复代码,以便它不会这样做,或b:作弊(C#示例):

// remove handler **if subscribed**, then re-subscribe
myWindow.Closed -= MyWindow_Closed;
myWindow.Closed += MyWindow_Closed;

要获得调用列表是......脆弱但可行。在简单的情况下,您可以使用反射来获取字段,并获取值。但是对于表单等,它使用稀疏技术(最小化没有订户的事件的空间)。如果是FormClosed,则会通过EVENT_FORMCLOSED键入。

使用示例(C#,抱歉)可能更有意义:

    Form form = new Form();
    form.FormClosed += delegate { Console.WriteLine("a");}; // just something, anything
    form.FormClosed += delegate { Console.WriteLine("b");}; // just something, anything
    object key = typeof(Form).GetField("EVENT_FORMCLOSED",
        BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
    EventHandlerList events = (EventHandlerList )
        typeof(Component).GetProperty("Events",
        BindingFlags.NonPublic | BindingFlags.Instance).GetValue(form, null);
    FormClosedEventHandler handler = (FormClosedEventHandler)events[key];
    foreach (FormClosedEventHandler subhandler in handler.GetInvocationList())
    {
        subhandler(form, null); // access the two events separately
    }

对于ObservableCollection<T>,委托直接在字段上,因此需要更少的间接:

ObservableCollection<SomeType> list = ...
NotifyCollectionChangedEventHandler handler = (NotifyCollectionChangedEventHandler)
    list.GetType()
    .GetField("CollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic)
    .GetValue(list);