清除对像所有事件的代码示例
‘下面的方法是清除了Button按钮关联的所有Click事件,验证有效
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonX2.Click
Dim _PropertyInfo As PropertyInfo = GetType(Button).GetProperty("Events", BindingFlags.Instance Or BindingFlags.NonPublic)
If _PropertyInfo Is Nothing Then Exit Sub
Dim _EventList As EventHandlerList = CType(_PropertyInfo.GetValue(ButtonX1, Nothing), EventHandlerList)
If _EventList Is Nothing Then Exit Sub
Dim _FieldInfo As FieldInfo = (GetType(Control)).GetField("EventClick", BindingFlags.Static Or BindingFlags.NonPublic)
If _FieldInfo Is Nothing Then Exit Sub
Dim _ObjectDelegate As [Delegate] = _EventList(_FieldInfo.GetValue(ButtonX1))
If _ObjectDelegate Is Nothing Then Exit Sub
For Each eh As [Delegate] In _ObjectDelegate.GetInvocationList()
RemoveHandler ButtonX1.Click, CType(eh, EventHandler)
Next
End Sub
_ObjectDelegate.GetInvocationList() ‘返回委托的调用列表
参考Control为事件采用EventHandlerList的代码分析
class MyControl1{ // 即使没有订阅,每个事件作为类成员需要4个字节(的引用,没有订阅时为null)。 // Winform的控件至少有70个事件, 这就要280个字节,且大部分事件都没有被用到。 // 就是说每个UI上的控件,Lable,Button,TextBox,等等,每个都可能浪费约300个字节。 public event EventHandler Initializing; public event EventHandler Initialized; // ... public event EventHandler MouseDown; public event EventHandler MouseUp; public event EventHandler MouseMove; public event EventHandler MouseClick; public event EventHandler MouseDoubleClick; public event EventHandler KeyDown; public event EventHandler KeyUp; // ...}class MyControl2{ // 一个EventHandlerList初始只要4个字节(的引用) private EventHandlerList _events; protected EventHandlerList Events { get { if (_events == null) _events = new EventHandlerList(); return _events; } } public event EventHandler Initializing { add { Events.AddHandler("Initializing", value); } // 按需增加 remove { Events.RemoveHandler("Initializing", value); } } public event EventHandler Initialized { add { Events.AddHandler("Initialized", value); } remove { Events.RemoveHandler("Initialized", value); } } // ...}注,除非像Control那样有大量的事件,一般不需要用到EventHandlerList,往往代码简洁更重要。
以上代码有一个局限,就是控件必须从Control继承,且内部事件变量名称必须以Event+事件方式命名,如果内部事件变量名称被混淆,将失效
下面的代码,在上面的代码基础上,优化后,可以无须从Control继承,但依然不能被混淆,混淆后还是会失效
Public Sub removeAllEvents(pObject As Object, pEventName As String)
Dim pBindingFlags = BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static
Dim pFieldBindingFlags = BindingFlags.NonPublic Or BindingFlags.Static Or BindingFlags.IgnoreCase
Dim pPropertyInfo = pObject.GetType().GetProperty("Events", pBindingFlags)
For Each pType In getBaseTypes(pObject)
Dim pFieldInfo = pType.GetField("Event" + pEventName, pFieldBindingFlags)
If pFieldInfo Is Nothing Then
Continue For
End If
Dim pField As [Delegate] = CType(pFieldInfo.GetValue(pObject), [Delegate])
If pField IsNot Nothing Then
Dim pObjectDelegate = pEventList(pField)
If pObjectDelegate IsNot Nothing Then
For Each pInvocatedDelegate In pObjectDelegate.GetInvocationList()
pType.GetEvent(pEventName).RemoveEventHandler(pObject, pInvocatedDelegate)
' 或者.GetRemoveMethod(True).Invoke(pObject, New Object() {pInvocatedDelegate})
Next
Return
End If
End If
Next
End Sub
Private Function getBaseTypes(pObj As Object) As Type()
If pObj Is Nothing Then
Return New Type() {}
End If
Dim pObjType = pObj.GetType()
pObjType = pObjType.BaseType()
Dim pTypes As New List(Of Type)
Do While pObjType IsNot Nothing
pTypes.Add(pObjType)
pObjType = pObjType.BaseType()
Loop
Return pTypes.ToArray()
End Function
