AddHandler только если нет обработчиков для этого события? - PullRequest
1 голос
/ 25 января 2010

Я хочу установить обработчик событий, только если он не установлен:

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

1 Ответ

2 голосов
/ 25 января 2010

Вы не можете на самом деле запросить текущее значение делегата события, кроме как в коде, который определяет событие. Каково ваше намерение здесь? Обычно вы не должны быть слишком обеспокоены (обязательно) с другими подписчиками? Есть способы взломать инкапсуляцию, чтобы найти текущее значение, но они не рекомендуются (это просто не очень хорошая идея).

Если вас беспокоит, обрабатываете ли вы это событие с помощью этого обработчика (т.е. вы не хотите выполнять двойную подписку, то вы всегда можете либо: исправить код, чтобы он не сделать это или b: cheat (пример 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);
...