AddHandler only if no handlers for this event?

时光总嘲笑我的痴心妄想 提交于 2019-12-11 08:47:29

问题


I want to set an event handler only if this is not set:

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

回答1:


You can't really query the current value of the event's delegate, except in the code that defines the event. What is your intent here? Normally you shouldn't be too concerned (necessarily) with other subscribers? There are ways of hacking past the encapsulation to find the current value, but they are not recommended (it just isn't a good idea).

If your concern is whether you are already handling that event with that handler (i.e. you don't want to double-subscribe, then you can always either a: fix the code so it doesn't do this, or b: cheat (C# example):

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

To get the invocation list is... brittle but doable. In simple cases you can just use reflection to get the field, and snag the value. But with forms etc it uses sparse techniques (to minimise the space for events without subscribers). In the case of FormClosed, this is keyed via EVENT_FORMCLOSED.

It might make more sense with an example (C#, sorry):

    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
    }

In the case of an ObservableCollection<T>, the delegate is directly on a field, so less indirection is required:

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


来源:https://stackoverflow.com/questions/2130752/addhandler-only-if-no-handlers-for-this-event

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!