Laden...

Namen & Methoden aller an einem Control registrierten EventHandler

Erstellt von Joetempes vor 14 Jahren Letzter Beitrag vor 13 Jahren 9.039 Views
Joetempes Themenstarter:in
888 Beiträge seit 2007
vor 14 Jahren
Namen & Methoden aller an einem Control registrierten EventHandler

Beschreibung:

Diese Methode liefert alle Event-Namen & Methoden-Namen an einem Control registrierten EventHandler.

Rückgabewert is ein Dictionary: KEY: Event-Name | VALUE: List<Method-Name>


       /// <summary>
        /// Search for all event Methods to a given control 
        /// </summary>
        /// <param name="i_control">given control</param>
        /// <returns>Dictionary with all events they have a callback method</returns>
        public Dictionary<string, List<string>> GetEventMethods(Control i_control)
        {
            //KEY: Event-Name | VALUE: List<Method-Name>
            Dictionary<string, List<string>> eventMethodDic = new Dictionary<string, List<string>>();

            EventInfo[] eventInfos = i_control.GetType().GetEvents();
            for (int i = 0; i < eventInfos.GetLength(0); i++)
            {
                string eventName = eventInfos[i].Name;

                PropertyInfo propertyInfo = i_control.GetType().GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic);
                object eventHandlerList = propertyInfo.GetValue(i_control, null);
                MethodInfo methodInfo = eventHandlerList.GetType().GetMethod("Find", BindingFlags.Instance | BindingFlags.NonPublic);
                FieldInfo fieldInfo = typeof(Control).GetField("Event" + eventName, BindingFlags.Static | BindingFlags.NonPublic);

                if (fieldInfo != null)
                {
                    object value = fieldInfo.GetValue(i_control);
                    object result = methodInfo.Invoke(eventHandlerList, new object[] { value });

                    if (result != null)
                    {
                        object handler = result.GetType().InvokeMember("handler", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic, null, result, null);
                        MulticastDelegate md = handler as MulticastDelegate;
                        Delegate [] delegates  = md.GetInvocationList();

                        List<string> methods = new List<string>();
                        for (int i2 = 0; i2 < delegates.Length; i2++)
                        {
                            if (delegates[i2].Method.Name != null)
                                methods.Add(delegates[i2].Method.Name);
                                
                        }

                        eventMethodDic.Add(eventName, methods);

                    }
                }
            }
 
            return eventMethodDic;
        }

Aufruf:


Dictionary<string, string> eventDic = this.GetEventMethods(myControl);

Edit:
UPDATE

Schlagwörter: EventHandler, MethodInfo, EventInfo

6.862 Beiträge seit 2003
vor 14 Jahren

Hallo,

der Code wird wahrscheinlich nicht in allen Fällen funktionieren. Wenn man nämlich selber ein Control mit eigenen Events definiert, hat man ja die Möglichkeit auch die Eventfelder selbst anzulegen und dann muss die Annahme

FieldInfo fieldInfo = typeof(Control).GetField("Event" + eventName, BindingFlags.Static | BindingFlags.NonPublic);

,dass das Feld mit Event... beginnt, nicht mehr stimmen.

Abgefangen hast du den Fall ja, da du auf null abfragst in nächsten Schritt, aber erwähnen kann mans ja trotzdem 😃

Baka wa shinanakya naoranai.

Mein XING Profil.

L
29 Beiträge seit 2009
vor 14 Jahren

Hm, ich hatte da auch mal ne Lösung.


        public Dictionary<string, string> GetEventMethods(Control control)
        {
            Dictionary<string, string> eventMethodDic = new Dictionary<string, string>();

            Type controlType = typeof(control);

            PropertyInfo events = controlType.GetProperty("Events", BindingFlags.NonPublic | BindingFlags.Instance);

            EventHandlerList value = (EventHandlerList)events.GetValue(control, null);

            FieldInfo[] fields = controlType.GetFields(BindingFlags.NonPublic |  BindingFlags.Static);

            foreach (FieldInfo info in fields)
            {
                object o = info.GetValue(control);

                if (o != null)
                {
                    Delegate eventHandler = value[o];

                    if (eventHandler != null)
                    {
                        eventMethodDic.Add(info.Name, eventHandler.Method.Name);
                    }
                }
            }
            return eventMethodDic;
       }

Kommt aufs Selbe raus....

Joetempes Themenstarter:in
888 Beiträge seit 2007
vor 14 Jahren

Hallo,

in Deiner Version steckt in der Zeile:

Type controlType = typeof(control);

ein Fehler.

Es muss heißen:

Type controlType = typeof(Control);

--> GROSSES C --> Typ nicht Object

Edit:
Und desweiteren hängt an Deinen Eventnamen im Dictionary jeweils ein "Event" davor.
Als Beispiel: statt "Click" ein "EventClick". ...aber das nur so erwähnt...

Grüße

Gelöschter Account
vor 14 Jahren

ein event ist ein multicastdelegate. das bedeutet, das sich merere methoden anmelden können, die dann der reihe nach aufgerufen werden. deine version wird aber immer nur eine methode zurückgeben.. so wie ich das sehe immer nur die zuletzt registrierte methode.

eigendlich müsstest du ein stringarray oder eine stringlist als value des dictionarys definieren und auch dann ist der methodenname an sich nur wenig informativ, da man ja nciht weiß, wo die methode ist....

edit:

hier hast du noch code zum testen... 😉

static void Main(string[] args)
        {
            mycontrol b = new mycontrol();
            b.test += new EventHandler(b_Click);
            b.test += new EventHandler(b_Click2);
            Dictionary<string, string> eventDic = GetEventMethods(b); 
        }

        static void b_Click(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }
        static void b_Click2(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        public class mycontrol : Control
        {
            public event EventHandler test;
        }
Joetempes Themenstarter:in
888 Beiträge seit 2007
vor 14 Jahren

Hallo JAck30lena,

japp, hast Recht, habs grad getestet.
Werd ich anpassen...

Gutes Auge, Danke für den Hinweis!

Joetempes Themenstarter:in
888 Beiträge seit 2007
vor 14 Jahren

Snipped angepasst: Stichwort: MulticastDelegate

Gelöschter Account
vor 14 Jahren

aber du hast nciht gegen den von mir geposteten code getestet... das hauptproblem mit den nciht erkannten eigenen events beleibt nachwievor... also erkennt es auch nciht die events, die alle anderen controls nur für sich implementiert haben....

L
29 Beiträge seit 2009
vor 14 Jahren

Mit deinem Code getestet und für gut befunden:


        private static Dictionary<string, List<string>> GetEventMethods(Control control)
        {
            Dictionary<string, List<string>> eventMethodDic = new Dictionary<string, List<string>>();

            Type controlType = control.GetType();

            EventInfo[] infos = controlType.GetEvents();
            
            foreach (EventInfo info in infos)
            {
                FieldInfo fieldInfo = controlType.GetField(info.Name, BindingFlags.Instance | BindingFlags.NonPublic);
                if (fieldInfo != null)
                {
                    object o = fieldInfo.GetValue(control);

                    if (o.GetType() == typeof(EventHandler))
                    {
                        EventHandler eventHandler = o as EventHandler;
                        Delegate[] methods = eventHandler.GetInvocationList();

                        List<string> methodNames = methods.Select(method => method.Method.Name).ToList();
                        eventMethodDic.Add(fieldInfo.Name, methodNames);
                    }
                }
            }

            return eventMethodDic;
        }

btw: das klein geschriebene "control" war schon absicht, aber dann gehts natürlich nicht mit "typeof", stattdessen:

Type controlType = control.GetType();
2.891 Beiträge seit 2004
vor 13 Jahren

Ein paar Unschönheiten gibt es noch im Code. Siehe Registriere Events auflisten funktioniert bei einem bestimmten Event nicht