博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#中删除任意控件任意事件的事件列表的实现!
阅读量:4119 次
发布时间:2019-05-25

本文共 4127 字,大约阅读时间需要 13 分钟。

有时候遇到动态挂接事件的时候,可能想删除以前挂接的事件。因为如果不删除,事件是会重复挂接的。

 

这里给出两种实现方法,各有优缺点。

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

    } 

 

 

转载地址:http://mdcpi.baihongyu.com/

你可能感兴趣的文章
自己的网站与UCenter整合(大致流程)
查看>>
laravel 制作通用的curd 后台操作
查看>>
【小红书2017年笔试】求一个数组中平均数最大的子数组
查看>>
Linux基础系列-定时器与时间管理
查看>>
Linux基础系列-可执行程序的产生过程
查看>>
Linux基础系列-Kernel 初始化宏
查看>>
Linux子系统系列-I2C
查看>>
<iOS>关于自定义description的一点用法
查看>>
Unix 命令,常用到的
查看>>
DLL中建立进程共享数据段需要注意的语法问题
查看>>
服务器端技术----Http请求的处理过程
查看>>
C语言-预处理指令2-条件编译
查看>>
C语言-预处理指令3-文件包含
查看>>
C语言-变量类型
查看>>
C语言-static和extern关键字1-对函数的作用
查看>>
C 语言-static和extern关键字2-对变量的作用
查看>>
【JavaScript 教程】浏览器—History 对象
查看>>
还不会正则表达式?看这篇!
查看>>
100道+ JavaScript 面试题,助你查漏补缺
查看>>
JavaScript深入理解之闭包
查看>>