How to access control's event?

2019-04-16 04:55发布

问题:

I am trying to get the name of the events that is assigned to control For eg: I have two forms A and B .Form B contains GridControl and gridcontrol has some events like gridControl1_Validating.

my goal is just to know what are the events assigned to the control

My Code is as follows FOrm A

 public Control[] FilterControls(Control start, Func<Control, bool> isMatch)
    {
        var matches = new List<Control>();
        Action<Control> filter = null;
        (filter = new Action<Control>(c =>
        {
            if (isMatch(c))
                matches.Add(c);
            foreach (Control c2 in c.Controls)
                filter(c2);
        }))(start);

        return matches.ToArray();


    }


     static void main[]
     {


        Control[] FoundControls = null;
        FoundControls = FilterControls(TF, c => c.Name != null && c.Name.StartsWith("grid"));

        var eventinfo = FoundControls[0].GetType().GetEvent("gridControl1.Validating", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

     }

ON compiling I get my control but I am getting null at eventinfo Although gridcontrol event has this event in form B

Please help

回答1:

Try "Validating" instead of "gridControl1.Validating""

var eventinfo = FoundControls[0].GetType().GetEvent(
    "Validating",
    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

Although this have nothing to do with the fact that you have attached an event handler to the event. You are getting the event itself, not the attached handlers. You can do nothing useful with the eventInfo variable (other that adding and removing other event handlers).

To access attached handlers (underlying delegates) you need to look at the code for the event implementations (using a decompiler like Reflector or dotPeek, or using Microsoft Reference Source):

public event CancelEventHandler Validating
{
    add
    {
        base.Events.AddHandler(EventValidating, value);
    }
    remove
    {
        base.Events.RemoveHandler(EventValidating, value);
    }
}

It turns out that the Control class uses a property named Events of type EventHandlerList to store all the delegates based on a key (EventValidating field in this case).

To retrieve delegates for an event, we should read them from the Events property:

public static Delegate[] RetrieveControlEventHandlers(Control c, string eventName)
{
    Type type = c.GetType();
    FieldInfo eventKeyField = GetStaticNonPublicFieldInfo(type, "Event" + eventName);
    if (eventKeyField == null)
    {
        eventKeyField = GetStaticNonPublicFieldInfo(type, "EVENT_" + eventName.ToUpper());
        if (eventKeyField == null)
        {
            // Not all events in the WinForms controls use this pattern.
            // Other methods can be used to search for the event handlers if required.
            return null;
        }
    }
    object eventKey = eventKeyField.GetValue(c);
    PropertyInfo pi = type.GetProperty("Events",
       BindingFlags.NonPublic | BindingFlags.Instance);
    EventHandlerList list = (EventHandlerList)pi.GetValue(c, null);
    Delegate del = list[eventKey];
    if (del == null)
        return null;
    return del.GetInvocationList();
}

// Also searches up the inheritance hierarchy
private static FieldInfo GetStaticNonPublicFieldInfo(Type type, string name)
{
    FieldInfo fi;
    do
    {
        fi = type.GetField(name, BindingFlags.Static | BindingFlags.NonPublic);
        type = type.BaseType;
    } while (fi == null && type != null);
    return fi;
}

and

public static List<Delegate> RetrieveAllAttachedEventHandlers(Control c)
{
    List<Delegate> result = new List<Delegate>();
    foreach (EventInfo ei in c.GetType().GetEvents())
    {
        var handlers = RetrieveControlEventHandlers(c, ei.Name);
        if (handlers != null) // Does it have any attached handler?
            result.AddRange(handlers);
    }
    return result;
}

The last method will extract all the event handlers attached to the control events. This includes handlers from all the classes (even internally attached by winforms). You can also filter the list by the target object of the handler:

public static List<Delegate> RetrieveAllAttachedEventHandlersInObject(Control c, object handlerContainerObject)
{
    return RetrieveAllAttachedEventHandlers(c).Where(d => d.Target == handlerContainerObject).ToList();
}

Now you can get all the event handlers of gridControl1 defined in formB:

RetrieveAllAttachedEventHandlersInObject(gridControl1, formB);