2010-09-24 147 views
7

的前面。當我使用的AddHandler在VB我自己的方法添加到Click事件:添加自己的事件處理程序在其他事件處理程序

AddHandler Button.Click, AddressOf myButton_Click 

我看到我的代碼執行最後一次 - 對於其他事件處理程序後, Button_Click事件。 有沒有辦法將其他事件的前面插入我的事件處理程序,以便它首先執行?

我將這個問題標記爲C#以及VB,如果您有任何建議,請隨時使用這兩種語言。
謝謝!

回答

5

單個事件的處理程序的執行順序無法通過的基本行爲進行控制內置的事件本身。 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,它將按照與MyControlButtonClick相同的順序執行MyHandlers中的委託(與先插入的任何插件相反)他們被插入的順序)。如果您使用Button將此代碼放置在自定義用戶控件中,則甚至可以在您的控件Click上命名自定義事件,並且控件的外觀和工作方式與它包含的Button非常相似,不同之處在於它可以額外控制插入處理程序。整個事情的美妙之處在於,沒有任何關於這個代碼強制消費者使用它作爲普通的「香草事件」以外的任何東西。

11

不容易。

這就是說,不要這樣做。你的代碼不應該關心它被調用的順序 - 它應該只關心被點擊的按鈕。所有的處理程序,包括你的,都將執行。如果順序很重要,你應該重新考慮你的設計,並使用其他一些機制來控制它。

+0

+1爲好建議。 – 2010-09-24 17:22:16

4

它更多的是VB.NET的實現細節,它有一個使用WithEvents和Handles關鍵字處理事件的替代方法。使用Handles的事件處理程序通過窗體構造函數中的自動生成代碼進行訂閱。此代碼將在您的任何代碼之前運行,包括InitializeComponent或您的自定義AddHandler語句。並且將因此總是首先運行。

讓你的代碼保證先運行是可能的。從按鈕派生自己的類並重寫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

我有類似的問題。

我有一個事件:關閉,兩個不同的對象收聽。而且我必須確定第一個對象的事件將在第二個對象的事件之前被調用。

他在這裏的我的解決方法(在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()」

希望我有幫助。