有时候遇到动态挂接事件的时候,可能想删除以前挂接的事件。因为如果不删除,事件是会重复挂接的。
这里给出两种实现方法,各有优缺点。
1。利用反射机制实现
void ClearEvent(Control control, string eventname)
{
if (control == null) return;
if (string.IsNullOrEmpty(eventname)) return;
BindingFlags mPropertyFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
BindingFlags mFieldFlags = BindingFlags.Static | BindingFlags.NonPublic;
Type controlType = typeof(System.Windows.Forms.Control);
PropertyInfo propertyInfo = controlType.GetProperty("Events", mPropertyFlags);
EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(control, null);
FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + eventname, mFieldFlags);
Delegate d = eventHandlerList[fieldInfo.GetValue(control)];
if (d == null) return;
EventInfo eventInfo=controlType.GetEvent(eventname);
foreach (Delegate dx in d.GetInvocationList())
eventInfo.RemoveEventHandler(control, dx);
}
调用案例:
ClearEvent(button1,"Click");//就会清除button1对象的Click事件的所有挂接事件。
这种方法可以一劳永逸,简单方便。但是引入了反射机制。除非必要,不建议在程序中采用反射,毕竟反射涉及到的数据类型,编译器是无法检查的,容易给程序运行时带来不稳定因素。当然,如果你足够自信,那也没什么不可以。
2。模仿.net维护事件表的机制,自己维护自己的事件表。这样不用引入反射,采用普通方法也可以很方便实现,代码显得还更加简单易懂。
本人比较推荐这种方式。
这种方式的缺点是需要自己定义一个EventHandlerList。不过这点添加,本人觉得是完全值得的。
首先要定义一个存放事件的列表,这个.net已经提供了类EventHandlerList,这个类存放机制类似hashmap。
EventHandlerList myEventHandlerList = new EventHandlerList();
然后我们写一个添加事件的方法:
void AddEvent(Control control,EventHandler eventhandler)
{
control.Click+=eventhandler;
myEventHandlerList.AddHandler(control,eventhandler);
}
很简单,就两行代码,但是以后自己添加事件就用这个方法,以便于以后删除。如果不采用这个方法添加的事件,是不会被删除的。
还要写一个删除事件的方法:
void ClearEvent(Control control)
{
Delegate d=myEventHandlerList[control];
foreach(Delegate dd in d.GetInvocationList())
control.Click-=(EventHandler)dd;
myEventHandlerList.RemoveHandler(control,d);
}
以后要清除事件的时候,就用这个方法即可。
当然这个方法有个问题就是如何不用反射机制实现任意方法的事件的添加和删除。
其实也没什么困难的,写几个CASE语句就能解决问题,虽然事件很多,但是COPY一下即可,也不算费事。
而且你也可以只写你关心的那几个事件。所以这个对工程不会造成什么影响。
最后总结:
综合上述两种方法,设计一个类,来负责处理此类事情,以便以后需要调用。
class MyEventManager:IDisposable
{
EventHandlerList eventList = new EventHandlerList();
Hashtable eventObjectList = new Hashtable();
public void AddEvent(Control control, string eventname, EventHandler eventhandler)
{
string keystr = control.Name + eventname;
if (!eventObjectList.Contains(keystr)) eventObjectList.Add(keystr, new object());
object eventObject = eventObjectList[keystr];
switch (eventname)
{
case "Click":
control.Click += eventhandler;
break;
case "Enter":
control.Enter += eventhandler;
break;
//...
//这里可以添加更多的事件支持,这都是因为C# 不支持宏替换而采用的无奈之举
//当然用反射也可以,不过用反射就没必要用这种方法了。
}
eventList.AddHandler(eventObject, eventhandler);
}
public void DelEvent(Control control, string eventname)
{
string keystr = control.Name + eventname;
object eventObject = eventObjectList[keystr];
Delegate d = eventList[eventObject];
if (d == null) return;
foreach (Delegate dd in d.GetInvocationList())
{
switch (eventname)
{
case "Click":
control.Click -= (EventHandler)dd;
break;
case "Enter":
control.Enter -= (EventHandler)dd;
break;
//...
//这里可以添加更多的事件支持,这都是因为C# 不支持宏替换而采用的无奈之举
//当然用反射也可以,不过用反射就没必要用这种方法了。
}
}
eventList.RemoveHandler(eventObject, d);
eventObjectList.Remove(eventObject);
}
public static void ClearEvent(Control control, string eventname)
{
if (control == null) return;
if (string.IsNullOrEmpty(eventname)) return;
BindingFlags mPropertyFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
BindingFlags mFieldFlags = BindingFlags.Static | BindingFlags.NonPublic;
Type controlType = typeof(System.Windows.Forms.Control);
PropertyInfo propertyInfo = controlType.GetProperty("Events", mPropertyFlags);
EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(control, null);
FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + eventname, mFieldFlags);
Delegate d = eventHandlerList[fieldInfo.GetValue(control)];
if (d == null) return;
EventInfo eventInfo = controlType.GetEvent(eventname);
foreach (Delegate dx in d.GetInvocationList())
eventInfo.RemoveEventHandler(control, dx);
}
#region IDisposable Members
public void Dispose()
{
eventList.Dispose();
}
#endregion
}