C#中删除任意控件任意事件的事件列表的实现!

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

 

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

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
    } 

 

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
实现C#窗体的任意位置拖动效果,可以通过以下步骤进行: 1. 在窗体上添加一个Panel件,并将其Dock属性设置为Top。这个Panel件将作为窗体的标题栏。 2. 在Panel件上添加一个Label或者其他件,用来显示窗体的标题。 3. 在Panel件的MouseDown事件,获取鼠标当前的位置,并将窗体的Location属性设置为这个位置。同时设置一个变量记录鼠标按下时的位置。 4. 在Panel件的MouseMove事件,如果鼠标左键被按下,计算鼠标当前位置和按下时位置的偏移量,然后将窗体的Location属性加上这个偏移量。 下面是示例代码: ``` public partial class Form1 : Form { private Point mouseOffset; public Form1() { InitializeComponent(); } private void panelTitle_MouseDown(object sender, MouseEventArgs e) { mouseOffset = new Point(-e.X, -e.Y); this.Cursor = Cursors.SizeAll; } private void panelTitle_MouseMove(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { Point mousePos = Control.MousePosition; mousePos.Offset(mouseOffset.X, mouseOffset.Y); this.Location = mousePos; } } private void panelTitle_MouseUp(object sender, MouseEventArgs e) { this.Cursor = Cursors.Default; } } ``` 在上述代码,panelTitle是我们添加的Panel件,用来作为窗体的标题栏。在MouseDown事件,我们记录鼠标按下时的位置,并将鼠标的光标设置为SizeAll,以便用户知道窗体可以被拖动。在MouseMove事件,如果鼠标左键被按下,我们计算鼠标当前位置和按下时位置的偏移量,并将窗体的Location属性设置为鼠标当前位置加上偏移量。在MouseUp事件,我们将光标设置回默认状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值