清除对像所有事件的代码示例
‘下面的方法是清除了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