如何获取控件的处理程序方法以处理另一个控件的相同事件



我想找出分配了哪些方法来处理控件的事件(来自外部),然后分配相同的方法来处理另一个控件的相同事件。我尝试了以下方法,但没有成功:

private void ReflectMethods(Control control, Control baseControl, string[] excludedEventNames = null, string[] includedEventNames = null)
{
    Type baseType = baseControl.GetType();
    Type ownType = control.GetType();
    foreach (EventInfo baseEventInfo in baseType.GetEvents())
    {
        if (excludedEventNames != null && excludedEventNames.Contains(baseEventInfo.Name))
            continue;
        if (includedEventNames != null && !includedEventNames.Contains(baseEventInfo.Name))
            continue;
        //
        // Checking if current control has the same event..
        //
        foreach (EventInfo ownEventInfo in ownType.GetEvents())
        {
            if (ownEventInfo.Name == baseEventInfo.Name)
            {
                FieldInfo eventField = baseType.GetField(baseEventInfo.Name, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
                // The above line always returns null, so I cannot get the handler ???
                EventHandler eventHandler = (EventHandler)eventField.GetValue(baseControl);
                ownEventInfo.AddEventHandler(this, eventHandler);
            }
        }
    }
}

只要您使用的控件由您实现,您的解决方案就很好。发生这种情况是因为编译器为每个事件创建一个字段,您可以像您发布的代码一样访问该字段。但这不是你能做到的唯一方法。这类似于属性:您通常为每个属性都有一个字段,但这不是唯一的方法。

在 Control 的情况下,要获取与事件关联的委托,您必须通过属性 Events 获取 EventHandlerList,然后使用字段的值访问它,该字段的名称由字符串 "Event" 组成,后跟事件的实际名称(例如,对于单击,您必须查找字段"EventClick")。

在这里,您可以找到应适用于 WinForm 控件的代码的修改版本。请注意,它不适用于你自己设计的控件。您应该结合这两种方法来管理所有情况。

    private void ReflectMethods(Control control, Control baseControl, string[] excludedEventNames = null, string[] includedEventNames = null)
    {
        Type baseType = baseControl.GetType();
        Type ownType = control.GetType();
        EventHandlerList events = typeof(Control).GetProperty("Events", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic).GetValue(baseControl, null) as EventHandlerList;
        foreach (EventInfo baseEventInfo in baseType.GetEvents())
        {
            if (excludedEventNames != null && excludedEventNames.Contains(baseEventInfo.Name))
                continue;
            if (includedEventNames != null && !includedEventNames.Contains(baseEventInfo.Name))
                continue;
            //
            // Checking if current control has the same event..
            //
            foreach (EventInfo ownEventInfo in ownType.GetEvents())
            {
                if (ownEventInfo.Name == baseEventInfo.Name)
                {
                    object eventField = typeof(Control).GetField("Event" + baseEventInfo.Name, BindingFlags.NonPublic | BindingFlags.Static).GetValue(baseControl);
                    Delegate aDel = events[eventField];
                    ownEventInfo.AddEventHandler(control, aDel);
                }
            }
        }
    }

最新更新