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

/// <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, null) as 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) > -)
                            {
                                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) == )
                {
                    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;
}

调用方式:(确定事件定义的类,如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;
}

利用反射C#获取事件列表的更多相关文章

  1. android 利用反射机制获取drawable中所有的图片资源

    public List<Map<String,Object>> getGridData() { list=new ArrayList<Map<String,Obje ...

  2. java 中利用反射机制获取和设置实体类的属性值

    摘要: 在java编程中,我们经常不知道传入自己方法中的实体类中到底有哪些方法,或者,我们需要根据用户传入的不同的属性来给对象设置不同的属性值,那么,java自带的反射机制可以很方便的达到这种目的,同 ...

  3. java 利用反射机制,获取实体所有属性和方法,并对属性赋值

    一个普通的实体Person: private int id; private String name; private Date createdTime;...//其它字段// get set方法 . ...

  4. java利用反射机制获取list中的某个字段并以list形式返回

    public static<T> List<Object> listToList(Collection<T> list,String fieldName) thro ...

  5. java利用反射动态获取实体类的属性值

    直接贴代码吧,有需要的话,可以根据自己的需要修改部分代码: public BigDecimal getByAttributeName(ThmdGwqriR thmdGwqriR, String att ...

  6. 利用反射来实现获取成员的指定特性(Attribute)信息

    在开发过程中,我们经常需要自定义一些特性,来辅助我们完成对对象或者枚举进行管理.我们需要知道如何获取对象使用的特性信息. 以下举个学习用的例子. 我们自定义一个特性类,这个特性设置在一个数据段内是否执 ...

  7. C# winform利用反射和自定义特性加载功能模块(插件式开发)

    由于在实际的工作中, 碰见这样的一个问题: 一个软件, 销售给A客户 他需要所有功能, 但是销售给B客户, 他只需要其中的一部分, 1.如果我们在实际的开发过程中, 没有把一些功能模块区分开来的话, ...

  8. 利用反射,更改string对象的value数组以达到改变string值。

    package test; import java.lang.reflect.Field; import lombok.Value; public class Test1{ public static ...

  9. java 反射和泛型-反射来获取泛型信息

    通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public.获得Field对象后都可以使用getType()来获取其类型. Class&l ...

随机推荐

  1. Android开发 ---如何操作资源目录中的资源文件5 ---Raw资源管理与国际化

    效果图: 1.activity_main.xml 描述: 定义两个按钮,一个是Raw资源管理,一个是处理国际化语言,其中i18n表示简体中文 <?xml version="1.0&qu ...

  2. IEDA中彻底删除项目

    删除项目一向比较奇葩,因为当你点击到 该项目名称-->右键 时,并没有 delete 选项,导致我们不知道怎么删除,查找多方文档,得到以下解决: (1)将鼠标移到要删除的 项目名称 上,单击并按 ...

  3. hdu 5228 OO’s Sequence(单独取数算贡献)

    Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the number o ...

  4. 玩转 React 【第03期】:邂逅 React 组件

    上期回顾 前文我们讲解了 React 模板 JSX,接着我们继续来看看 React 组件又是如何工作的呢? 组件化开发到了今天已经是大家的共识,在 React 中,组件同样也是组成我们整个项目的基本单 ...

  5. kbmMWLog同时输出日志到多个日志管理器

    kbmMWLog日志框架,针对不同的业务情况,提供了多种日志管理器: TkbmMWStreamLogManager TkbmMWLocalFileLogManager TkbmMWSystemLogM ...

  6. 如何HACK无线家用警报器?

    30年前,报警器都是硬连线的,具有分立元件,并由钥匙开关操作.20年前,他们已经演变为使用微控制器,LCD和键盘,但仍然是硬连线.10年前,无线报警器开始变得普及,并增加了许多之前没有的功能. 而如今 ...

  7. 【Python】多线程-3

    #练习:线程等待 Event e.set() e.wait()   from threading import Thread, Lock import threading import time   ...

  8. 微软Power BI 每月功能更新系列——7月Power BI 新功能学习

    Power BI Desktop 7月产品功能摘要 7月是Power BI Desktop团队的重要发布!但由于官方延迟更新,我们的讲述也就更晚了一点,也许大家觉得没有必要了,都8月了,谁还看7月的? ...

  9. [转] [Elasticsearch] 数据建模 - 处理关联关系(1)

    [Elasticsearch] 数据建模 - 处理关联关系(1) 标签: 建模elasticsearch搜索搜索引擎 2015-08-16 23:55 6958人阅读 评论(0) 收藏 举报 分类: ...

  10. Java中的容器 I————浅谈List

    一.List接口的继承关系 List接口是Collection接口的子接口,而ArrayList和LinkedList以及Vector是其实现类. List的特点是可以将元素维护在特定的序列中,可以再 ...