zoukankan      html  css  js  c++  java
  • 利用反射C#获取事件列表

          在程序设计中有时候需要动态订阅客户自己的事件,调用完成后又要删除以前订阅的事件。因为如果不删除,有时会造成事件是会重复订阅,导致程序运行异常。一个办法是用反射来控件事件列表。清空方法代码如下:

            /// <summary>
            /// 清空控件的事件列表
            /// </summary>
            /// <param name="pControl">要清空事件列表的控件</param>
            /// <param name="pEventName">事件名</param>

            void ClearEvent(Control pControl, string pEventName)

            {

                if (pControl== null) return;

                if (string.IsNullOrEmpty(pEventName)) 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(pControl, null);//事件列表

                FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + pEventName, mFieldFlags);

                Delegate d = eventHandlerList[fieldInfo.GetValue(pControl)];

     

                if (d == null) return;

                EventInfo eventInfo=controlType.GetEvent(pEventName);

     

                foreach (Delegate dx in d.GetInvocationList())

                    eventInfo.RemoveEventHandler(pControl, dx);//移除已订阅的pEventName类型事件

     

            }

           这种方法可以一劳永逸,简单方便。但由于引入了反射,涉及到的数据类型,编译器是无法检查的,容易给程序运行时带来不稳定因素。

     

    以上转载的,我是要用来判断ArcEngine中PageLayoutControl控件的事件是否绑定处理函数的,由于MS事件机制的修改,已经不能通过==null的方式来判断事件是否绑定函数了,需要用到反射,这个例子虽然短,不过刚好能说明情况

     

    Type t = typeof(AxPageLayoutControl);
                System.Reflection.FieldInfo fieldInfo = t.GetField("OnDoubleClick", myBindingFlags);
                Delegate instanceDelegate = fieldInfo.GetValue(axPageLayoutControl1) as Delegate;
                string msg = "";
                if (instanceDelegate != null)
                {
                    foreach (Delegate d in instanceDelegate.GetInvocationList())
                    {
                        //c.OnChange -= d as EventHandler;
                        ////evt.RemoveEventHandler(c, d as EventHandler);
                        msg += d.Method.Name;
                    }

                }

                MessageBox.Show("deligate is:" + msg);

    这样就能把PageLayoutControl的OnDoubleClick绑定的所有函数的名称输出出来

    可以进一步修改

    出处:http://www.cnblogs.com/caodajieup/archive/2011/09/29/2195117.html

    ======================================================================================================

    [C#应用]得到组件事件的委托列表

            public static Delegate[] GetComponentEventDelegate(Component component, string EventName, string EventHandlerTypeName)
            {
                Type componentType = component.GetType();
                PropertyInfo eventsPropertyInfo = componentType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
                EventHandlerList eventHanlderList = eventsPropertyInfo.GetValue(component, nullas EventHandlerList;
                FieldInfo HeadFieldInfo = eventHanlderList.GetType().GetField("head", BindingFlags.Instance | BindingFlags.NonPublic);
                object HeadObject = HeadFieldInfo.GetValue(eventHanlderList);
    
                do
                {
                    FieldInfo[] fieldInfoList = componentType.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);
                    foreach (FieldInfo fieldInfo in fieldInfoList)
                    {
                        object fieldValue = fieldInfo.GetValue(component);
                        if (fieldValue != null)
                        {
                            Type fieldType = fieldValue.GetType();
                            if (fieldType.Name == EventHandlerTypeName && (fieldValue as Delegate) != null)
                            {
                                return (fieldValue as Delegate).GetInvocationList();
                            }
                            else if (fieldType.Name == typeof(Object).Name)
                            {
                                if (fieldInfo.Name.IndexOf(EventName, StringComparison.OrdinalIgnoreCase) > -1)
                                {
                                    if (HeadObject != null)
                                    {
                                        Delegate delegateObject = eventHanlderList[fieldValue];
                                        if (delegateObject != null)
                                            return delegateObject.GetInvocationList();
                                    }
                                }
                            }
                        }
                    }
                    componentType = componentType.BaseType;
                } while (componentType != null);
    
                if (HeadObject != null)
                {
                    object ListEntry = HeadObject;
                    Type ListEntryType = ListEntry.GetType();
                    FieldInfo handlerFieldInfo = ListEntryType.GetField("handler", BindingFlags.Instance | BindingFlags.NonPublic);
                    FieldInfo keyFieldInfo = ListEntryType.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic);
                    FieldInfo nextFieldInfo = ListEntryType.GetField("next", BindingFlags.Instance | BindingFlags.NonPublic);
    
                    while (ListEntry != null)
                    {
                        Delegate handler = handlerFieldInfo.GetValue(ListEntry) as Delegate;
                        object key = keyFieldInfo.GetValue(ListEntry);
                        ListEntry = nextFieldInfo.GetValue(ListEntry);
    
                        if (handler != null && handler.GetType().Name == EventHandlerTypeName)
                            return handler.GetInvocationList();
                    }
                }
                return null;
            }

    简要说明: 
    1)参数说明:
    component: 组件对象实例
    EventName: 事件的名称,如"ItemClick"
    EventHandlerTypeName: 事件委托类型,如"ItemClickEventHander"

    2)代码说明:
    第一段代码遍历组件的所有私有字段,尝试根据EventName和EventHandlerTypeName找出相关的字段.
    如果找到了相关的字段,检查它的值是否是Delegate类型,是的话OK.如果它的值是Object类型,那么说明它是EventHandlerList的key,则需要用EventHandlerList实例[key]来得到委托列表.
    第二段代码在第一段代码没找到对应的字段的情况下,检查EventHandlerList是否为空,不为空的话。遍历该组件的所有事件,尝试使用EventHandlerTypeName来找到相关的委托列表。
    如果还未找到,则返回null。

    3)存在的问题
    可能无法找到某些组件的委托,或者找到不匹配的委托列表。
    能否顺利地找到事件对应的委托列表,取决于组件内部定义的事件字段或在EventHandlerList的key字段是否与事件名称相同以及EventHandler类型是否特殊。
    如果组件内部定义了与事件名称相同的字段或EventHandler类型比较特别,则较容易找到对应的委托列表。
    虽然可以通过EventHandlerList来得到组件的所有事件委托,但根据得到的key却无法确定handler委托列表对应的是哪一个事件。

    4)已检测过的组件和事件
    没来得及仔细测试,只测试了二个XtraBar的BarButtonItem.ItemClick和XtraNavBar的NavBarItem.LinkClicked事件。

    出处:https://blog.csdn.net/zxkid/article/details/1444396

    ======================================================================================================

    C#如何知道控件注册了哪些事件,是通过代码获取这个控件的已注册事件列表

    EventInfo[] memberinfo = (typeof(System.Windows.Forms.Button)).GetEvents();
    foreach (EventInfo info in memberinfo)
    {
    //Console.WriteLine(info.Name);
    PropertyInfo propertyInfo = (typeof(System.Windows.Forms.Button)).GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
    EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(this.button2, null);
    FieldInfo fieldInfo = (typeof(Control).GetField("Event" + info.Name, BindingFlags.Static | BindingFlags.NonPublic));
    if (fieldInfo != null)
    {
    Delegate d = eventHandlerList[fieldInfo.GetValue(null)];
    if (d != null)
    {
    listBox1.Items.Add(d.Method.Name);
    }
    }
    }

    出处:https://ask.csdn.net/questions/264615

    ======================================================================================================

    C#中移除自定义事件的所有方法

            /// <summary>
            /// 移除一个对象指定事件的所有注册的方法
            /// </summary>
            /// <typeparam name="T">泛型</typeparam>
            /// <param name="obj">当前对象</param>
            /// <param name="eventName">事件名</param>
            public static void RemoveEvent<T>(T obj, string eventName)
            {
                BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
                EventInfo[] eventInfo = obj.GetType().GetEvents(bindingFlags);
                if (eventInfo == null)
                {
                    return;
                }
     
     
                foreach (EventInfo info in eventInfo)
                {
                    if (string.Compare(info.Name, eventName, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        FieldInfo fieldInfo = info.DeclaringType.GetField(info.Name, bindingFlags);
                        if (fieldInfo != null)
                        {
                            fieldInfo.SetValue(obj, null);
                        }
                        break;
                    }
                }
            }
    
    
    
    //测试代码
    PubFunction.RemoveEvent<BetchSettingValueForm>(this, "BeforeDictEntry");
     
                    //特殊帮助类型帮助前过滤扩展
                    MethodInfo method = valExtend.GetType().GetMethod(field.Element.LabelID + "_Extend");
                    if (method != null)
                    {
                        valExtend.gspState = GspState;
                        valExtend.dsMXJH = MXJH;
                        //转化method到delegate
                        Delegate methodDel = PubFunction.CreateDelegateFromMethodInfo<BeforeDictEntryEventArgs<SmartHelpInfo>>(valExtend, method);
                        //先移除事件再注册
                        BeforeDictEntry += methodDel as EventHandler<BeforeDictEntryEventArgs<SmartHelpInfo>>;
                    }
                    #endregion
                    
                    //值改变事件注册,完成批量设置
                    PubFunction.RemoveEvent<ButtonEdit>(helpEdit, "ButtonClick");
                    helpEdit.ButtonClick += helpEdit_ButtonClick;

    出处:https://blog.csdn.net/soapcoder92/article/details/51027117

    ======================================================================================================

    Remove all the EventHandlers of the object by reflection

    class Program
        {
            static void Main(string[] args)
            {
                Customer c = new Customer();
                EventInfo evt = c.GetType().GetEvent("OnChange",
                        BindingFlags.NonPublic | BindingFlags.Instance
                        | BindingFlags.Public
                    );
                // 添加一个事件关联
                evt.AddEventHandler(c, new EventHandler(c_OnChange));
                // 添加第二个事件关联
                evt.AddEventHandler(c, new EventHandler(c_OnChange));
    
                // 删除全部事件关联。
                RemoveEvent<Customer>(c, "OnChange");
    
                c.Change();
            }
    
            static void c_OnChange(object sender, EventArgs e)
            {
                Console.WriteLine("事件被触发了");
            }
    
            static void RemoveEvent<T>(T c, string name)
            {
                Delegate[] invokeList = GetObjectEventList(c, name);
                if (invokeList == null)
                    return;
                foreach (Delegate del in invokeList)
                {
                    typeof(T).GetEvent(name).RemoveEventHandler(c, del);
                }
            }
    
            public static Delegate[] GetObjectEventList(object p_Object, string p_EventName)
            {
                // Get event field
                FieldInfo _Field = p_Object.GetType().GetField(p_EventName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
                if (_Field == null)
                {
                    return null;
                }
                // get the value of event field which should be a delegate
                object _FieldValue = _Field.GetValue(p_Object);
    
                // if it is a delegate
                if (_FieldValue != null && _FieldValue is Delegate)
                {
                    // cast the value to a delegate
                    Delegate _ObjectDelegate = (Delegate)_FieldValue;
                    // get the invocation list
                    return _ObjectDelegate.GetInvocationList();
                }
                return null;
            } 
        }
    
        class Customer
        {
            public event EventHandler OnChange;
            public void Change()
            {
                if (OnChange != null)
                    OnChange(this, null);
                else
                    Console.WriteLine("no event attached");
            }
        }

    出处:https://blog.csdn.net/diandian82/article/details/5738299

    参考:https://bbs.csdn.net/topics/370126564

    ======================================================================================================

    根据上面的代码,我自己经过修改如下:

            /// <summary>
            /// 获取窗体控件的注册事件名称。
            /// 例如:按钮的单击事件:
            /// GetObjectEventList<Control>(button1, "Click");
            /// 菜单项的单击事件:
            /// GetObjectEventList<System.Windows.Forms.ToolStripItem>(menuStrip1.Items[0], "Click");
            /// 不同的控件的基类也不相同,在使用的时候应格外注意,否则将返回Null
            /// 另外,我这里方法内部使用了EventClick的事件记录,在使用的时候最好还是调试看看事件名称是否匹配
            /// </summary>
            /// <typeparam name="T">表示事件所定义的类</typeparam>
            /// <param name="pControl">控件实例,或事件的子类</param>
            /// <param name="pEventName">事件名称</param>
            /// <returns></returns>
            private Delegate[] GetObjectEventList<T>(T pControl, string pEventName)
            {
                Delegate[] ret = null;
                Type ctlType = typeof(T);
                PropertyInfo _PropertyInfo = ctlType.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
                if (_PropertyInfo != null)
                {
                    EventHandlerList _EventList = _PropertyInfo.GetValue(pControl, null) as EventHandlerList;
                    FieldInfo _FieldInfo = ctlType.GetField("Event" + pEventName, BindingFlags.Static | BindingFlags.NonPublic);
                    if (_EventList != null && _EventList is EventHandlerList && _FieldInfo != null)
                    {
                        Delegate _ObjectDelegate = _EventList[_FieldInfo.GetValue(pControl)];
                        if (_ObjectDelegate != null)
                            ret = _ObjectDelegate.GetInvocationList();
                    }
                }
                return ret;
            }
    View Code

    调用方式:(确定事件定义的类,如Button在Control中定义的Click事件,不然会找不到事件)

    Delegate[] d1 = EventTest.GetObjectEventList<System.Windows.Forms.Control>(btnTest, "Click");
    Delegate[] d2 = EventTest.GetObjectEventList<System.Windows.Forms.ToolStripItem>(menuStrip1.Items[0], "Click");

    支持自定义类中的自定义事件

            public static Delegate[] GetCustomEventList(object obj, string eventName)
            {
                Delegate[] ret = null;
    
                BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
                EventInfo[] eventInfo = obj.GetType().GetEvents(bindingFlags);//此处获取所有事件
    
                EventInfo ei = obj.GetType().GetEvent(eventName, bindingFlags);
                if (ei != null)
                {
                    FieldInfo _FieldInfo = ei.DeclaringType.GetField(eventName, bindingFlags);
                    Delegate _ObjectDelegate = _FieldInfo.GetValue(obj) as Delegate;
                    ret = _ObjectDelegate?.GetInvocationList();
                }
                
                return ret;
            }
    View Code
  • 相关阅读:
    课后作业-阅读任务-阅读提问-1
    Android:XML简介 & 解析方式对比(DOM、SAX、PULL)
    Android Handler
    Android BroadcastReceiver解析
    Android:(本地、可通信的、前台、远程)Service使用全面介绍
    android 服务解析
    android 解决子线程进行UI操作
    android 基础题
    java中的synchronized(同步代码块和同步方法的区别)
    Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor
  • 原文地址:https://www.cnblogs.com/mq0036/p/10406743.html
Copyright © 2011-2022 走看看