2010-09-24 4 views
7

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

AddHandler Button.Click, AddressOf myButton_Click 

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

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

ответ

5

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

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

  1. Создайте упорядоченную коллекцию делегатов типа обработчика событий, называемого MyHandlers. Это будет суррогатом для реализации события MulticastDelegate.
  2. Создайте метод обработчика «master», который фактически будет прикреплен к встроенному событию и будет проходить через 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 (с любыми вставками, выполненными сначала, в обратном порядке чтобы они были вставлены). Если вы разместили этот код в пользовательском элементе управления с помощью кнопки, вы можете даже назвать настраиваемое событие на своем элементе управления. Нажмите, и элемент управления будет выглядеть и работать так же, как и содержащаяся в нем кнопка, за исключением того, что она будет иметь дополнительный контроль над вставкой обработчики. Красота всего этого заключается в том, что ничто об этом коде не заставляет потребителей работать с ним, как что-то другое, кроме простого ванильного события.

11

Не легко.

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

+0

+1 для хорошего совета. –

4

Это более подробная информация о реализации VB.NET, она имеет альтернативный способ общения с событиями с использованием ключевых слов WithEvents and 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

У меня была аналогичная проблема.

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

Здесь его мое решение (в 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()"

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

Смежные вопросы