在其他事件处理程序前添加自己的事件处理程序

Mer*_*ros 9 c# vb.net event-handling winforms

当我在VB中使用AddHandler将我自己的方法添加到Click事件时:

  AddHandler Button.Click, AddressOf myButton_Click
Run Code Online (Sandbox Code Playgroud)

我看到我的代码最后执行 - 在Button_Click事件的其他事件处理程序之后.有没有办法其他事件插入我的事件处理程序,以便它首先执行?

我将此问题标记为C#以及VB,如果您有任何建议,请随意使用任何一种语言.
谢谢!

Ree*_*sey 13

不容易.

话虽这么说,不要这样做.您的代码不应该关心它的调用顺序 - 它应该只关心有问题的按钮被点击了.所有处理程序(包括您的处理程序)都将执行.如果订单很重要,您应该重新考虑您的设计,并使用其他一些机制来控制它.


Kei*_*thS 7

单个事件的处理程序的执行顺序不能通过内置事件本身的基本行为来控制.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;
Run Code Online (Sandbox Code Playgroud)

请注意,您不再将MasterClickHandler以外的处理程序附加到实际事件中; 你不能拥有自己的蛋糕,也不能吃它,无论是重写还是保持基本的事件行为.事件"属性"中也没有内置"插入"行为; 你必须定义一个允许这个的方法.最后,你永远不应该直接引发事件MyControlButtonClick(尽管你的控件是唯一可以控制的,这可以通过代码检查来强制执行).

现在,当您单击按钮时,按钮的内置Click事件将触发MasterEventHandler,它将按照它们附加到MyControlButtonClick的相同顺序执行MyHandlers中的委托(首先执行插入的任何委托,按照它们插入的相反顺序执行) ).如果您将此代码放在带有Button的自定义用户控件中,您甚至可以在控件Click上命名自定义事件,并且控件的外观和工作方式与它包含的Button非常相似,不同之处在于它可以对插入进行额外控制处理程序.整个事情的美妙之处在于,这个代码没有任何东西可以强迫消费者使用它作为一个普通的"香草"事件.