DataGridView / ColumnHeaderMouseClick / Welches Event folgt danach?

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von VaporiZed.

    DataGridView / ColumnHeaderMouseClick / Welches Event folgt danach?

    Hallo!

    Ich habe ein "ColumnHeaderMouseClick"-Event in dem ich ein Mouse-Rechtsklick abfrage um ein FontDialog anzeigen zu lassen um das Font des DGV zu ändern.
    Das klappt auch.
    Nun hab ich eine Funktion welche mir "GetPreferredHeight" und "GetPreferredWidth" liefert und aufs DGV anwenden soll.
    Diese Funktion funktioniert auch in anderen Bereichen des Programms.

    Nur leider wenn ich das Font ändere wird das DGV kurzzeitig mit der minimalen Zeilenhöhe angezeigt, also die gewünschte Höhe, dann werden aber alle Reihen auf maximal Height gesetzt, sodass jeglicher Inhalt komplett in den Zellen angezeigt wird.

    Ich hab im "ColumnHeaderMouseClick"-Event ein dgv.Refresh() eingebaut um das verhalten zu beobachten..nach dem .Refresh ist das DGV auf minimaler Spaltenhöhe, aber wenn er das "ColumnHeaderMouseClick"-Event verlässt wird noch irgend ein Event ausgelöst was die DGV auf maximale Reihenhöhe setzt!

    Welches Event wird denn nach einem "ColumnHeaderMouseClick"-Event noch ausgelöst? Kann man das iwie CodeMappen?

    Morrison schrieb:

    Kann man das iwie CodeMappen?
    Du kannst alle betreffenden Events abbonieren und ein Debug.WriteLine(EVENT_NAME) da reinschreiben, da bekommst Du die Reihenfolge im Ausgabefenser angezeigt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ähm, ja..
    Welche sind denn "alle betreffenden"?

    Hab jetzt sowas im Event stehen:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub dgvMainTable_ColumnHeaderMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles dgvMainTable.ColumnHeaderMouseClick
    2. 'Debug.WriteLine("ColumnHeaderMouseClick")
    3. 'Sortieren
    4. If e.Button = MouseButtons.Left Then
    5. dgvMainTable.ClearSelection()
    6. If dgvMainTable.SortOrder.ToString() = "Descending" Then
    7. dt_MainTable.DefaultView.Sort = dgvMainTable.SortedColumn.Name & " DESC"
    8. Else
    9. dt_MainTable.DefaultView.Sort = dgvMainTable.SortedColumn.Name & " ASC"
    10. End If
    11. dt_MainTable = dt_MainTable.DefaultView.ToTable()
    12. End If
    13. 'DGV-Schriftgröße
    14. If e.Button = MouseButtons.Right Then
    15. 'dgvMainTable.DefaultCellStyle.Font = New Font("Tahoma", 15)
    16. 'dgvMainTable.ColumnHeadersDefaultCellStyle.Font = New Font("Tahoma", 15)
    17. Using fDialog As FontDialog = New FontDialog
    18. If fDialog.ShowDialog <> Windows.Forms.DialogResult.Cancel Then
    19. dgvMainTable.DefaultCellStyle.Font = fDialog.Font
    20. dgvMainTable.ColumnHeadersDefaultCellStyle.Font = fDialog.Font
    21. Using _gr As Graphics = Me.CreateGraphics
    22. MainTable_StandardMin_RowsHeight = CInt(_gr.MeasureString("?ßGgjJiI", fDialog.Font).Height + 4)
    23. End Using
    24. 'dgvMainTable.Update()
    25. Debug.WriteLine(MainTable_StandardMin_RowsHeight)
    26. 'Resize Rows&Columns because of new Font
    27. DGV_MainTable_Setup_Widths_AutoSizeModes()
    28. For Each _row As DataGridViewRow In dgvMainTable.Rows
    29. _row.Height = MainTable_StandardMin_RowsHeight
    30. Next
    31. dgvMainTable.Refresh()
    32. End If
    33. End Using
    34. 'MainTable_FontChanged = True
    35. End If
    36. End Sub



    Welches Event wird denn NACH "ColumnHeaderMouseClick" ausgelöst?

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

    Morrison schrieb:

    Welche sind denn "alle betreffenden"?
    Keine Ahnung, im Ernstfall alle, in denen "Mouse" vorkommt, die kannst Du ja per Doppelklick im Designer abbonieren und die nicht-relevanten dann einfach löschen.
    Jou, das ist eine Fleißarbeit.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Morrison schrieb:

    Welches Event wird denn nach einem "ColumnHeaderMouseClick"-Event noch ausgelöst? Kann man das iwie CodeMappen?
    Für sowas habe ich mir einen speziellen Code geschrieben, weil ich auch immer mal wieder vor der Frage stehe:

    VB.NET-Quellcode

    1. Private Sub WriteCodeFor(CE 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 = False")
    5. Code.AppendLine()
    6. For Each ControlEvent In CE.GetType.GetEvents
    7. Code.AppendLine($"Private Sub {CE.Name}_{ControlEvent.Name}(sender As Object, e As {ControlEvent.EventHandlerType.ToString.Replace("Handler", "Args")}) Handles {CE.Name}.{ControlEvent.Name}")
    8. Code.AppendLine(" If IgnoreEvents Then Return")
    9. Code.AppendLine($" EventHistory.Add(""{CE.Name}.{ControlEvent.Name}"")")
    10. Code.AppendLine("End Sub")
    11. Code.AppendLine()
    12. Next
    13. IO.File.WriteAllText($"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\EventHandlerCode for {CE.Name}.txt", Code.ToString)
    14. End Sub

    Man übergibt an diese Sub ein Control, z.B. das DGV und führt den Code aus. Daraus entsteht eine Datei mit Code. Man kopiert sich den Code ins Projekt rein. Dieser Code erfasst alle Events und schreibt die Reihenfolge in EventHistory, eine List(Of String), solange IgnoreEvents auf False gestellt ist. Man macht die gewünschte Aktion, also z.B. Mausklick. Danach schaut man sich die EventHistory an und weiß, was in welcher Reihenfolge passiert.
    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“ ()

    @VaporiZed Feines Snippet.
    Wenn man da noch einen oder zwei Filter einbaut, einen zum Durchlassen und einen zum Nicht-Durchlassen, bekommt man eine feine Datei.
    Desweiteren könnte man da auch eine "Partial Class" draus machen mit etwas kryptischeren Prozedurnamen, im Sinne von:

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. WriteCodeFor(Button1)
    3. End Sub
    4. Private Sub Button1_Click_2(sender As Object, e As EventArgs) Handles Button1.Click
    5. MessageBox.Show("feddich")
    6. End Sub
    da muss der bestehende Code nicht geändert und der Testcode kann einfach gelöscht werden.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Man könnte es glaub auch dynamisch machen, also dass kein Code generiert werden muss.
    Da hätte man eine Klasse, die man mit eim Objekt initialisiert, und die Klasse findet mit Reflection alle Events, abboniert sie und logt ins Debug-Fenster.
    Hmm - man müsste auch einen Space-Separierten String übergeben, mit Event-Namen, die man nicht geloggt haben will.
    zB MouseMove oder Paint treten häufig in sehr schneller Folge auf, sodass die anderen Events im Debug-Fenster dann untergehen würden.
    Am Ende wird eine Extension daraus:

    VB.NET-Quellcode

    1. dgvMeinTollesDGV.LoggEvents(exclude:="MouseMove *Paint")
    gesehen? der Exclude-Filter kann auch Wildcards verarbeiten ;)

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

    ErfinderDesRades schrieb:

    der Exclude-Filter kann auch Wildcards verarbeiten
    Einer Methode, die noch nicht existiert, kann man vieles hinterhersagen :D
    Ich hatte das früher vor meinem Code probiert, bin aber damals wie heute daran gescheitert, die passenden EventHandler zu kreieren, da ich schon bei der Methode AddEventHandler am Delegaten scheitere, da der immer genau den passenden EventArgs-Typen für ein Ereignis will.
    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.
    Glaub doch. Man kann Events, die sich an den Event-Pattern halten, alle auf denselben Basic-EventHandler schicken:

    VB.NET-Quellcode

    1. Public Sub New()
    2. InitializeComponent()
    3. AddHandler dgvDstvdb.MouseMove, AddressOf AllHandler
    4. End Sub
    5. Private Sub AllHandler(sender As Object, e As EventArgs) Handles btTest.Click
    6. Debug.WriteLine(e.GetType.Name)
    7. End Sub
    Glaub ich. Aber bei Reflection geht das nicht mehr.
    Bilder
    • Reflection zickt.png

      35,56 kB, 784×422, 60 mal angesehen
    • Reflection zickt immer noch.png

      34,22 kB, 756×397, 65 mal angesehen
    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.
    Bin zwar nen Schritt weiter, aber leider bin ich wohl in eine Sackgasse abgebogen. Da ich hier der Zielsub nix anderes als sender und EventArgs mitgeben kann, scheitert das Loggen. :( Und Test muss auch Shared in VB sein, sonst meckert der Compiler wegen Inkompatibilität der Signatur.

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Log(Button1)
    3. End Sub
    4. Private Sub Log(Control As Control)
    5. For Each ControlEvent In Control.GetType.GetEvents
    6. Dim GenericDelegate = [Delegate].CreateDelegate(ControlEvent.EventHandlerType, New EventHandler(AddressOf Test).Method)
    7. ControlEvent.AddEventHandler(Control, GenericDelegate)
    8. Next
    9. End Sub
    10. Private Shared Sub Test(sender As Object, e As EventArgs)
    11. Console.WriteLine($"{DirectCast(sender, Control).Name} raised an event. But which one?")
    12. End Sub
    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.
    Wieder etwas weiter gekommen. Ziemlich tricky und immer noch nicht fertig. Vielleicht kann/will es jemand zuende bringen?

    VB.NET-Quellcode

    1. Imports System.Reflection
    2. Public Class Form1
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Log(Button1)
    5. End Sub
    6. Private Sub Log(Control As Control)
    7. EventHandlerCreator.CreateEventHandlersFor(Control)
    8. End Sub
    9. End Class
    10. Public NotInheritable Class EventHandlerCreator
    11. Public Shared Sub CreateEventHandlersFor(Control As Control)
    12. For Each ControlEvent In Control.GetType.GetEvents
    13. Dim Action As Action = Sub() Console.WriteLine($"{Control.Name} hat das Event {ControlEvent.Name} ausgelöst.")
    14. Dim EventArgType = ControlEvent.EventHandlerType.GetMethod("Invoke").GetParameters(1).ParameterType
    15. Dim GenericHandler = GetType(GenericEventHandler(Of)).MakeGenericType(EventArgType)
    16. Dim Handler = Activator.CreateInstance(GenericHandler, Control, ControlEvent, Action)
    17. Next
    18. End Sub
    19. End Class
    20. Public Class GenericEventHandler(Of T As EventArgs)
    21. Private ReadOnly Action As Action = Nothing
    22. Public Sub New(Control As Control, EventInfo As EventInfo, Action As Action)
    23. Me.Action = Action
    24. EventInfo.AddEventHandler(Control, New EventHandler(Of T)(AddressOf Handle))
    25. End Sub
    26. Private Sub Handle(sender As Object, e As T)
    27. Action()
    28. End Sub
    29. End Class


    Problem in Z#21/#33: Das Objekt mit dem Typ "System.EventHandler`1[System.EventArgs]" kann nicht in den Typ "System.EventHandler" konvertiert werden.

    Laut diesem stackoverflow-Thread mit dem von mir ungetesteten Code aus Antwort#1 soll es in C# klappen.

    ##########

    Ich hab mir jetzt das MSDN-Beispiel zum Thema AddEventHandler hergenommen und umgebaut. Es ist m.E. zwar ziemlich Pfeil-Rücken-Brust-Auge (Stichworte: Delegaterzeugung über AssemblyBuilder, ILGenerator). Aber: Es funktioniert!

    VB.NET-Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Log(Button2)
    3. End Sub
    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

    Bilder
    • Logging Events.png

      4,47 kB, 321×273, 50 mal angesehen
    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 3 mal editiert, zuletzt von „VaporiZed“ ()