简体   繁体   中英

How to get handler methods of a control to handle the same events of another control

I want to find out which methods have been assigned to handle events of a control (from outside) and then assign the same methods to handle the same events of another control. I tried the following method with no success:

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);
            }
        }
    }
}

Your solution is good as long as the controls you are using are implemented by you. This happens because the compiler creates a field for each event that you can access like in the code you posted. But this is not the only way you can do it. It's something like for properties: you usually have a field for each property, but it's not the only way to do it.

In the case of Control, to get the delegates associated to the event you have to get the EventHandlerList through the property Events, and then get the right EventHandler accessing it using the value of the field with the name composed by the string "Event" followed by the actual name of the event (eg for Click you have to look for the field "EventClick").

Here you can find a modified version of your code that should work for WinForm controls. Be aware that it won't work for your own designed controls. You should combine the two approaches for managing all the situations.

    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);
                }
            }
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM