Добавление собственного обработчика событий перед другими обработчиками событий - PullRequest
9 голосов
/ 24 сентября 2010

Когда я использую AddHandler в VB, чтобы добавить свой собственный метод в событие Click:

  AddHandler Button.Click, AddressOf myButton_Click

Я вижу, что мой код выполняется последним - после других обработчиков событий для события Button_Click.Есть ли способ вставить мой обработчик событий перед других событий, чтобы он выполнялся первым?

Я отметил этот вопрос как C #, так и VB, пожалуйста, не стесняйтесь использовать любой язык, если у вас есть какие-либо предложения.
Спасибо!

Ответы [ 4 ]

13 голосов
/ 24 сентября 2010

не легко.

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

7 голосов
/ 24 сентября 2010

Порядок выполнения обработчиков одного события не может контролироваться с помощью основного поведения самого встроенного события. MulticastDelegates - это «мешки» обработчиков, и они просто захватывают их по одному за раз. Помните, что именно так большинство разработчиков ожидают, что это сработает, и может быть опасно разрешать обработчики событий, зависящие от порядка. Обработчики событий обычно не должны знать друг о друге, потому что, если они зависят от выполнения до или после другого обработчика, они сначала должны знать о существовании другого обработчика (нарушая сокрытие информации и некоторые другие принципы проектирования), и, во-вторых, если этот порядок изменится, поведение будет нарушено.

Если вы понимаете все это и по-прежнему хотите контролировать порядок выполнения обработчиков события, вам будет предложено следующее.

  1. Создайте упорядоченную коллекцию делегатов типа обработчика событий с именем MyHandlers. Это будет суррогатом для реализации фактического события MulticastDelegate.
  2. Создайте «основной» метод-обработчик, который на самом деле будет присоединен к встроенному событию, будет перебирать MyHandlers и вызывать каждый из них.
  3. Определите некоторые средства для добавления и удаления обработчиков из списка. Некоторые из них могут быть выполнены с помощью пользовательского события «свойство», но оно будет определять только поведение добавления и удаления, а не вставки.

Код может выглядеть следующим образом:

private List<EventHandler> MyHandlers = new List<EventHandler>();

private void MasterClickHandler(object sender, EventArgs e)
{
   foreach(var handler in MyHandlers)
      handler(sender, e); 
}

public event EventHandler MyControlButtonClick
{
   add { MyHandlers.Add(value); }
   remove { MyHandlers.Remove(value); }
}

public void InsertButtonClickHandler(EventHandler handler)
{
   MyHandlers.Insert(handler,0); //calling this to add a handler puts the handler up front
}

...

myForm.MyControl.Click += MasterClickHandler;

Обратите внимание, что вы больше не присоединяете обработчики, кроме MasterClickHandler, к реальному событию; вы не можете съесть свой пирог и съесть его, переопределяя и сохраняя основное поведение события. Также нет поведения «вставки», встроенного в событие «свойство»; Вы должны определить метод, который позволяет это. Наконец, вы никогда не должны вызывать событие MyControlButtonClick напрямую (хотя, поскольку ваш элемент управления является единственным, который может это сделать, это может быть осуществлено путем проверки кода).

Теперь, когда вы нажимаете кнопку, встроенное в кнопку событие Click запускает MasterEventHandler, который будет выполнять делегаты в MyHandlers в том же порядке, в котором они были присоединены к MyControlButtonClick (все, что было вставлено, выполняются первыми, в обратном порядке. они были вставлены). Если вы поместите этот код в пользовательский элемент управления с помощью кнопки, вы можете даже назвать пользовательское событие в элементе управления Click, и элемент управления будет выглядеть и работать так же, как содержащаяся в нем кнопка, за исключением того, что он будет иметь дополнительный элемент управления для вставки. обработчики. Прелесть всего этого в том, что ничто в этом коде не заставляет потребителей работать с ним как с чем-то иным, кроме простого ванильного события.

4 голосов
/ 24 сентября 2010

Это скорее деталь реализации VB.NET, у нее есть альтернативный способ обработки событий с использованием ключевых слов WithEvents и Handles.Обработчик событий, который использует Handles, подписывается автоматически сгенерированным кодом в конструкторе формы.Этот код будет выполняться перед любым вашим кодом, включая InitializeComponent или пользовательский оператор AddHandler.И поэтому всегда будет запускаться первым.

Возможно, ваш код будет гарантированно выполняться первым.Извлеките свой собственный класс из Button и переопределите метод OnClick:

Public Class MyButton
    Inherits Button

    Protected Overrides Sub OnClick(ByVal e As System.EventArgs)
        '' Do your stuff here
        ''....

        '' Other event handlers will run now:
        MyBase.OnClick(e)
    End Sub
End Class
2 голосов
/ 27 декабря 2013

У меня была похожая проблема.

У меня было событие: Закрыто, что два разных объекта слушают.И я должен был быть уверен, что событие 1-го объекта будет вызвано до 2-го.

Вот его мое решение (в C #):

public class Screen
{
    public event EventHandler Closed;
    public event EventHandler ScreenRemoved;


    protected virtual void OnClosed()
    {
        if (Closed != null)
        {
            Closed.Invoke(this, EventArgs.Empty);
        }

        OnScreenRemoved();
    }

    protected virtual void OnScreenRemoved()
    {
        if (ScreenRemoved != null)
        {
            ScreenRemoved.Invoke(this, EventArgs.Empty);
        }
    }
}

Таким образом, для всех событий, которые яхочу вызвать первым:

m_Screen.Closed += Screen_Closed;

И для всех событий, которые я хочу вызвать последним:

m_Screen.ScreenRemoved += new EventHandler(Screen_Closed);

* оба способа добавления события одинаковы, с и без "новый EventHandler () "

Надеюсь, я был полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...