2012-06-14 98 views
3

我有一臺連接到一個按鈕,單擊Windows窗體像這樣兩個事件處理程序:防止下一個事件處理程序被調用

this.BtnCreate.Click += new System.EventHandler(new RdlcCreator().FirstHandler); 
this.BtnCreate.Click += new System.EventHandler(this.BtnCreate_Click); 

都被正確調用。

但是,在FirstHandler()內可以防止BtnCreate_Click()被執行嗎?就像:

void FirstHandler(object sender, EventArgs e) 
{ 
    if (ConditionSatisfied) 
    //Prevent next handler in sequence being executed 

} 

我知道我可以只取消訂閱事件,但可以通過編程方式(從方法內)完成?

+0

爲什麼不只是使用布爾標誌? –

+0

ConditionSatisfied模仿一個 –

+0

通過ChainEventArgs替換EventArgs並添加一些變量來支持處理程序鏈邏輯 – gabba

回答

5

據我所知,沒有解決方案。這是因爲當事件發生時,不能保證事件處理程序的調用順序。

因此,你不應該以任何方式依賴他們的訂單。

+0

處理程序按照它們所連接的順序被調用,除非添加/刪除訪問器以奇怪的方式實現。他們爲什麼不叫他們?它們存儲在一個普通的列表中。 – Groo

+0

@Groo儘管所有處理程序都按照它們所附的順序被調用,但這是您不應該依賴的實現細節。 – sloth

+0

我同意,訂購不能依賴,我會找到一種不同的方法。 –

0

添加在this.BtnCreate_Click以下條件這是第二個事件

BtnCreate_Click(object sender, EventArgs e) 
{  
    if (!ConditionSatisfied)  //Prevent next handler in sequence being executed 
    { 
    // your implementation goes here 
    } 
} 
+0

這是我alraedy有 –

+0

你沒有得到我的觀點好友。您在CreateFrom EventHandler中使用此條件,但我已將它放入BtnCreate_Click事件處理程序中。區別在於您無需取消訂閱該活動。這是唯一正統的做法。 –

2

爲什麼你不只是一個事件處理程序替換它們?事情是這樣的:

var rdlc = new RdlcCreator(); 
this.BtnCreate.Click += (sender, e) => { 
    rdlc.FirstHandler(sender, e); 
    if (!rdlc.HasHandledStuff) { // <-- You would need some kind of flag 
     this.BtnCreate_Click(sender, e); 
    } 
}; 

這樣,你也能保證處理的順序。或者,使用上面的實現,但改變FirstHandler的簽名返回一個布爾值指示條件(在這種情況下,並不真的需要有事件的簽名了):

if (!rdlc.FirstHandler(sender, e)) { 
     this.BtnCreate_Click(sender, e); 
    } 

編輯:或者,您只需將第二個處理程序傳遞給FirstHandler。
FirstHandler的簽名改成這樣:

void FirstHandler(object sender, EventArgs e, EventHandler nextHandler) { 
    if (ConditionSatisfied) { 
     // do stuff 
    } 
    else if (nextHandler != null) { 
     nextHandler(sender, e); 
    } 
} 

然後:

this.BtnCreate.Click += 
    (s, e) => new RdlcCreator().Firsthandler(s, e, this.BtnCreate_Click); 
0

我建議你創建一個某種類包裝的。所以,你可以在那裏存儲一些事件標誌組(例如16位整數)和一些方法來設置或取消設置單個位(其中每個方法調用或不調用EventHandler)。您可以輕鬆地在課程中存儲Eventhandlers甚至Actions的任何計數,並以您想要的任何順序調用。

2

System.ComponentModel命名空間包含用於此目的的CancelEventHandler委託。它提供的參數之一是一個CancelEventArgs實例,其中包含一個布爾型Cancel屬性,該屬性可以設置爲任何處理程序,以指示應停止調用列表的執行。

然而,將其連接到一個普通的EventHandler代表,您將需要創建自己的包裝,一樣的東西:

public static class CancellableEventChain 
{ 
    public static EventHandler CreateFrom(params CancelEventHandler[] chain) 
    { 
     return (sender, dummy) => 
     { 
      var args = new CancelEventArgs(false); 
      foreach (var handler in chain) 
      { 
       handler(sender, args); 
       if (args.Cancel) 
        break; 
      } 
     }; 
    } 
} 

對於你的榜樣,你會使用這樣的:

this.BtnCreate.Click += CancellableEventChain.CreateFrom(
    new RdlcCreator().FirstHandler, 
    this.BtnCreate_Click 
    /* ... */ 
); 

當然,如果您以後需要取消訂閱(分離),您需要在字段中捕獲已創建的鏈處理程序。

0

找到解決同一個問題的方法,但沒有運氣。所以不得不解決我自己。 爲可取消的事件參數

甲基類
public class CancelableEventArgs 
{ 
    public bool Cancelled { get; set; } 
    public void CancelFutherProcessing() 
    { 
     Cancelled = true; 
    } 
} 

接着定義了擴展方法的事件處理程序,請注意在向後的順序調用(在我的情況下UI元素調用列表的訂戶,因爲它們加入到組分所有本的情況下,所以這後來元素呈現了最公開程度,更優先)

public static class CommonExtensions 
{ 
    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static void SafeInvokeWithCancel<T>(this EventHandler<T> handler, object sender, T args) where T : CancelableEventArgs 
    { 
     if (handler != null) 
     { 
      foreach (var d in handler.GetInvocationList().Reverse()) 
      { 
       d.DynamicInvoke(sender, args); 
       if (args.Cancelled) 
       { 
        break; 
       } 
      } 
     } 
    } 

這裏是使用

public class ChessboardEventArgs : CancelableEventArgs 
{ 
    public Vector2 Position { get; set; } 
} 

因此,如果一個UI元素對事件有一些行爲,它可以處理更多的細胞

 game.OnMouseLeftButtonDown += (sender, a) => 
     { 
      var xy = GetChessboardPositionByScreenPosition(a.XY); 
      if (IsInside(xy)) 
      { 
       var args = new ChessboardEventArgs { Position = xy }; 
       OnMouseDown.SafeInvokeWithCancel(this, args); 
       a.CancelFutherProcessing(); 
      } 
     }; 
相關問題