alle Events für ein Control loggen

    • VB.NET
    • .NET (FX) 4.5–4.8

      alle Events für ein Control loggen

      Wie findet man heraus, in welcher Reihenfolge welches Event für ein Control gefeuert wird?

      Nachdem das Thema im Thread DataGridView / ColumnHeaderMouseClick / Welches Event folgt danach? war und eine Lösung vielleicht etwas untergegangen ist, hier die bisher genannten Möglichkeiten:
      1. EventHandler-Codeerstellung
      2. dynamische EventHandler-Erstellung



      EventHandler-Codeerstellung

      Man kopiert sich den folgenden Code ins Projekt und führt ihn aus. Nach dem Ausführen des Codes kann man ihn aus dem Projekt löschen.
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Private Sub WriteCodeFor(Control As Control)
      2. Dim Code As New Text.StringBuilder
      3. Code.AppendLine("Private Property EventHistory As New List(Of String)")
      4. Code.AppendLine("Private IgnoreEvents As Boolean = True")
      5. Code.AppendLine()
      6. For Each ControlEvent In Control.GetType.GetEvents.OrderBy(Function(x) x.Name)
      7. Code.AppendLine($"Private Sub {Control.Name}_{ControlEvent.Name}_LoggingCode(sender As Object, e As {ControlEvent.EventHandlerType.GetMethod("Invoke").GetParameters(1).ParameterType.Name}) Handles {Control.Name}.{ControlEvent.Name}")
      8. Code.AppendLine(" If IgnoreEvents Then Return")
      9. Code.AppendLine($" EventHistory.Add(""{Control.Name}.{ControlEvent.Name}"")")
      10. Code.AppendLine("End Sub")
      11. Code.AppendLine()
      12. Next
      13. IO.File.WriteAllText($"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\EventHandlerCode for {Control.Name}.txt", Code.ToString)
      14. End Sub


      Man erhält eine Datei auf dem Desktop, die alle EventHandler des übergebenden Controls enthält. Den Dateiinhalt kopiert man sich ins Projekt und macht die gewünschten Aktionen mit dem Ziel-Control. Will man wissen, was nach dem MouseClick auf einen Button passiert, schaltet man im dortigen EventHandler IgnoreEvents auf False und erhält alle Folgeevents in der Liste EventHistory., die man sich zu einem späteren Zeitpunkt ansehen kann.

      Wie @RodFromGermany im o.g. Thread erwähnte, haben die EventHandler-Prozedurnamen einen kleinen Zusatz, um nicht in Konflikt mit bestehenden zu geraten.




      dynamische EventHandler-Erstellung

      Ein bisschen anspruchsvoller (v.a. vom Verständnis) ist die dynamische EventHandler-Erstellung. Leider muss man wohl kompliziert einen passenden Delegaten erstellen, der zum jeweiligen Event passt (Ursprungsquellcode). An der Verwendung von Generika bin ich gescheitert, s. o. erwähnter Thread.
      Man führt einmalig die Methode Log für das gewünschte Zielcontrol aus und das Ergebnis zeigt sich dann in der Konsole/im Ausgabe-Fenster, in der dann die EventHandler Rückmeldung geben.

      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports System.Reflection
      2. Imports System.Reflection.Emit
      3. '[…]
      4. Private Sub Log(Control As Control)
      5. For Each ControlEvent In Control.GetType().GetEvents
      6. Dim HandlerType = ControlEvent.EventHandlerType
      7. Dim InvokeMethod = HandlerType.GetMethod("Invoke")
      8. Dim Parameters = InvokeMethod.GetParameters()
      9. Dim ParameterTypes = Parameters.Select(Function(x) x.ParameterType).ToArray
      10. Dim aName As New AssemblyName() With {.Name = "DynamicTypes"}
      11. Dim AssemblyBuilder = Emit.AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run)
      12. Dim ModuleBuilder = AssemblyBuilder.DefineDynamicModule(aName.Name)
      13. Dim TypeBuilder = ModuleBuilder.DefineType("Handler", TypeAttributes.Class Or TypeAttributes.Public)
      14. Dim MethodBuilder = TypeBuilder.DefineMethod("DynamicHandler", MethodAttributes.Public Or MethodAttributes.Static, InvokeMethod.ReturnType, ParameterTypes)
      15. Dim ILGenerator = MethodBuilder.GetILGenerator()
      16. ILGenerator.EmitWriteLine($"{Control.Name} löste das Event »{ControlEvent.Name}« aus.")
      17. ILGenerator.Emit(OpCodes.Ret)
      18. Dim FinalType = TypeBuilder.CreateType()
      19. Dim EventHandler = FinalType.GetMethod("DynamicHandler")
      20. Dim FinalDelegate = [Delegate].CreateDelegate(HandlerType, EventHandler)
      21. ControlEvent.AddEventHandler(Control, FinalDelegate)
      22. Next
      23. End Sub



      Wie @ErfinderDesRades im o.g. Thread erwähnte, könnte man zu Beginn der For-Schleife auch die Events rausfiltern, die nicht relevant sein dürften, indem man den Event-Namen auswertet.




      Man könnte sicherlich auch was über das Erfassen der WndProc-Parameter rausbekommen. Da dort allerdings extrem viele Nachrichten hin- und herwandern, wird das Rausfiltern der relevanten Daten schwierig - falls überhaupt dort alles erfasst wird.
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()