DataGridView Paint Ereignis

  • VB.NET
  • .NET 4.5

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von mrMo.

    DataGridView Paint Ereignis

    Zur Zeit habe ich gerade Probleme mit einem Form, das nicht vollständig geladen/angezeigt wird und dann nicht reagiert.
    Im Moment habe ich das Paint-Ereignis in Verdacht. Allerdings scheint dies erst nach dem vollständigen Laden und Anzeigen
    des Forms angestoßen zu werden.
    1. Stimmt diese Vermutung, oder kann es vorkommen, dass sich die Events in die Quere kommen (Load, Shown, Paint)
    2. Wie kann ich programmtechnisch feststellen, ob das Form vollständig angezeigt wird? ( mit Shown? )
    3. Was bringt das Paint-Event zum (dauernden) Feuern?
    4. Kann man überhaupt im Paint-Event Änderungen am DGV vornehmen, ohne dass das wieder ein Event auslöst?
    1. Es gibt eine fixe Reihenfolge: Load, Shown, Paint
    2. Was heißt vollständig? Das Form selber oder auch all die CEs, die aber quasi für sich selbst verantwortlich sind?
    3. Ein Stop, ein Invalidate, Refresh, Update, wenn Du mit der Maus über einen Button fährst, ihn anklickst, …
    4. Nein. Es löst DGV-Events aus. Aber diese lösen normalerweise nicht wieder das Paint-Events des Forms aus.

    Alles Spekulatius. Ohne Code keine konkreten Lösungswege von meiner Seite möglich.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    zu 2. Es gibt ein Panel mit Buttons und DGV drin. Diese Buttons haben Icons die nicht dargestellt werden. Die Buttons sind darum weiß.
    Zudem wird die Menüzeile nicht dargestellt, während ein DGV mit gebundenen Datatable-Daten richtig angezeigt wird. Die Buttons und das Menü reagieren
    aber durchaus aufs Klicken. Dann werden sie auch langsam sichtbar.

    zu 3. Ich habe mal hier zuhause eine einfache Form mit DGV gebaut. Ohne Mausbewegung im Form wird das Paint-Ereignis gefeuert.

    Das Programm ist schon viel zu groß und ich dürfte es auch nicht mit aus unserer Firma nehmen.
    Spekulationen sind mir darum auch schon recht. ^^
    @Lightsource Das DGV-Paint-Event ist nicht dafür gedacht, Daten in einem DGV anzuzeigen!
    Jede Zelle ist ein eigenes Control, das sich selbst darstellt.
    Sonderbehandlung gibt es im CellFormatting-Event, da kannst Du im Prinzip für jede Zelle einzeln ihren Inhalt so darstellen, wie Du es möchtest, also Zahlen auf 2 Nachkommastellen begrenzen oder den Hintergrund einfärben und solch.
    Was soll denn wie in Deinem DGV dargestellt werden?
    Hast Du spezielle eigene Spalten da drinne?
    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!
    Was passiert denn, wenn Du das Form aus dem Bildschirm raus- und wieder reinziehst?

    Lightsource schrieb:

    Ohne Mausbewegung im Form wird das Paint-Ereignis gefeuert.
    Ja, sicher. Vor dem und beim Programmstart siehst Du nix. Wenn alles fertig geladen ist, siehst Du das Form. Woran liegt's? Weil das Form gezeichnet wurde. Eben weil es auf dem Bildschirm sichtbar wird. Und damit das Paint-Event gefeuert wurde. Das ist auch, wenn Du was anderes in den Vordergrund holst und danach Dein Form wieder in der Vordergrund bringst. Dann nuss es auch wieder neu auf dem Monitor gezeichnet werden -> Paint-Event.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Sowas kann man doch debuggen.
    ZB verdächtige Events mal temporär abhängen, obs dann immer noch laggt.

    ZB eine Ereigniskette entsteht, wenn innerhalb des Ergeignisses Code ausgeführt wird, der mittelbar das Ereignis erneut auslöst.
    Das Paint-Event ist prädestiniert für sowas. Wenn da etwa an Daten rumgefummelt wird, die - via Databinding - neu dargestellt werden müssen (nämlich gepainted).
    Aber wie gesagt: Spekulatius.
    Es war ein Paint Ereignis, so in der Art, wie es ErfinderDesRades vorgeschlagen hatte.

    Was ich immer noch nicht verstehe:
    Warum wurde Paint bereits aufgerufen, bevor das Form fertig aufgebaut war?
    Warum wird hier zuhause bei meinem Test überhaupt DataGridView1_Paint aufgerufen, obwohl ich "die Maus still halte"?


    Setzt mal unten bei "DataGridView1_Paint" einen Haltepunkt
    (Ich glaube das ist ein Beispiel von Microsoft, nur ein DGV auf einem Form)

    VB.NET-Quellcode

    1. Public Class Form1
    2. Public Sub New()
    3. ' Dieser Aufruf ist für den Designer erforderlich.
    4. InitializeComponent()
    5. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    6. End Sub
    7. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    8. Dim table As New DataTable()
    9. ' Declare DataColumn and DataRow variables.
    10. Dim column As DataColumn
    11. Dim row As DataRow
    12. ' Create new DataColumn, set DataType, ColumnName and add to DataTable.
    13. column = New DataColumn()
    14. column.DataType = System.Type.GetType("System.Int32")
    15. column.ColumnName = "id"
    16. table.Columns.Add(column)
    17. ' Create second column.
    18. column = New DataColumn()
    19. column.DataType = Type.GetType("System.String")
    20. column.ColumnName = "item"
    21. table.Columns.Add(column)
    22. ' Create new DataRow objects and add to DataTable.
    23. Dim i As Integer
    24. For i = 0 To 9
    25. row = table.NewRow()
    26. row("id") = i
    27. row("item") = "item " & i
    28. table.Rows.Add(row)
    29. Next
    30. DataGridView1.DataSource = table
    31. Dim myfont = DataGridView1.DefaultCellStyle.Font
    32. DataGridView1.Columns(1).DefaultCellStyle.Font = New Font(myfont, Font.Style.Bold)
    33. End Sub
    34. Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    35. End Sub
    36. Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint
    37. End Sub
    38. End Class
    @Lightsource Teste dies:

    VB.NET-Quellcode

    1. Private Sub DataGridView1_Paint(sender As Object, e As PaintEventArgs) Handles DataGridView1.Paint
    2. If Me.Visible Then
    3. Console.WriteLine("Me Visible")
    4. Else
    5. Console.WriteLine("Me Not Visible")
    6. End If
    7. If DataGridView1.Visible Then
    8. Console.WriteLine("DGV Visible")
    9. Else
    10. Console.WriteLine("DGV Not Visible")
    11. End If
    12. End Sub
    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!

    Lightsource schrieb:

    Paint scheint mir nicht gerade ein verlässliches Event zu sein.
    Das kann ich absolut nicht unterschreiben.
    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!
    Na ja, wenn ich das Programm einfach auf dem Bildschirm stehen lasse und sonst nichts tue, warum wird Paint dann immer mal wieder ausgelöst.
    ( mit leeren Paintroutinen )

    Wenn ich in das Datagridview klicke bekomme ich zwei Paintereignisse. Gut, es könnten Mousedown und Mouseup sein.
    Aber das Grid da schon neu zeichnen zu wollen, wenn zwischen Klickdown und -up kein Pixel verändert wurde, verstehe ich auch nicht.

    Lightsource schrieb:

    Warum wurde Paint bereits aufgerufen, bevor das Form fertig aufgebaut war?
    (ähm - woher weisst du, dass das so ist?
    und: Definiere "Form fertig aufbauen")

    Wie dem auch sei.
    Beachte auch, dass es beim DGV viele PaintEvents gibt: CellPainting, RowPainting, RowPrePaint,...
    Es ist wichtig, das Painting-Konzept von WinForms als Ganzes zu verstehen.
    Ein Paint-Vorgang wird nicht (unbedingt) von deinem Programm ausgelöst.
    Sondern das Betriebssystem stellt fest: "Da und da auf dem Bildschirm hat sich was verändert - vielleicht ist ein Fenster (irgendeines - nicht unbedingt deine App) geschlossen worden, oder verschoben - jedenfalls an der Stelle müssen wir neu hinmalen, was auf dem Bildschirm zu sehen sein soll."
    Und dann sucht das Betriebsystem das Fenster, was an der Stelle zuoberst ist, und sucht die Anwendung dazu (deine App etwa), und gibt der Bescheid, sie solle mal den und den Bereich neu zeichnen.
    Deine App sucht dann, welches Fenster an der Stelle zuoberst ist, und welches Control auf dem Fenster an der Stelle - und wenn das dein DGV ist - ja, dann purzelt da ein DGV_Paint bei raus, und wenn eine DGV-Zelle auch in dem Bereich liegt, dann auch ein DGV_RowPrepaint, DGV_RowPaint, DGV_CellPrePaint, DGV_CellPainting,... etc..

    Also wo du mit deine Maus hinklickst hat nur indirekt was damit zu tun, welche Paint-Events da ausgelöst werden.
    Nämlich wenn du in eine Zelle klickst, dann soll die wohl das Focus-Rectangle bekommen. Das heist, von einer anderen Zelle muss der Focus weggenommen werden, und an die Zelle gegeben werden, wo du hingeklickst.
    Beide Bereiche werden dem Betriebssystem mitgeteilt, und dann geht obige Kaskade wieder los, und iwann purzeln deine PaintEvents bei raus.

    Kann auch sein, dass so ein Paint-Vorgang überflüssigerweise losgetreten wird - dem Betriebssystem wird ja nur "da und da" mitgeteilt, es kann ja nicht selbst überprüfen, ob was denn da hingemalt wird nicht vielleicht 100% identisch ist mit dem, was schon vorher da war.



    Langer Rede kurzer Sinn:
    Im Paint-Event - wenn du es abonnierst - sollst du painten.
    Du kannst auch andere Sachen da machen - damit versaust du dir evtl. aber die Performance - weil Paint-Events können u.U. in sehr schneller Folge gefeuert werden.
    Vor allem solltest du da nix machen, was neu dargestellt werden müsste - weil damit rufst du ja selber den nächsten Painting-Vorgang hervor.



    Jo, so ist das, und ist sehr zuverlässig, und eröffnet enorm vielfältige Möglichkeiten, die Darstellung selbst zu gestalten.
    Was da nun bei dir schief läuft, und in welchem Paint-Event kann man vermutlich nur in deinem Code nachlesen.
    Die Möglichkeiten, da Mist zu bauen, sind jedenfalls noch vielfältiger.
    Vielleicht hast du ja einen .Invalidate() - Aufruf in deim Paint-Event-Code - das wäre genau so eine Benachrichtigung ans Betriebsystem, den nächsten PaintVorgang vom Stapel zu lassen.
    Sowas passiert zB leicht, wenn man Code von iwoher zusammenkopiert.

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

    ErfinderDesRades schrieb:

    (ähm - woher weisst du, dass das so ist?
    und: Definiere "Form fertig aufbauen")

    Meine Definition ist die: Alle zu zeigenden Controls sind sichtbar und reagieren. Und davon vor allem "sichtbar", denn die Reaktion auf Events könnte ja schon
    von anderen Programmteilen unterdrückt werden.
    Du meinst also, dass eventuell das Betriebssystem zu viele oder falsche Repaint-Anforderungen schickt?
    Also wenn vollständige Sichtbarkeit zum "Form-Aufbau" gehört, dann müssen zwingend zuvor alle dafür nötigen Paint-Events durchlaufen sein - sonst wäre das Form ja nicht oder nur unvollständig sichtbar.



    Das Betriebssystem macht seinen Job sehr gut.
    Allerdings kann dein Code das Betriebssystem veranlassen, unnötige PaintVorgänge auszulösen.
    Probier mal diesen Quatsch:

    VB.NET-Quellcode

    1. Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    2. Debug.Print("Form1_Paint")
    3. Me.Invalidate()
    4. End Sub

    Ein Timer? Ich glaub, ich kapier einfach nicht, was Du mit dem Ganzen bezweckst. Was muss denn da dauernd warum neu gezeichnet werden?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    Ja, aber wozu dann mit Timer oder Paint-EventHandler? Das Ummalen eines DGVs würd ich z.B. im CellEndEdit-EventHandler oder im CellValidated-EventHandler anstoßen. Oder wenn Daten anderweitig gespeichert und dann im DGV angezeigt werden, z.B. man gibt Daten in ner TextBox ein und klickt auf nen Button, um die Daten abzuspeichern, dann würd ich z.B. die Cell(x).Style.BackColor der betroffenen Zellen in ner Sub entsprechend ihrer Werte ändern. Und diese Sub im Button.Click-EventHandler aufrufen. Oder anders ausgedrückt: Wertänderungen oder Grenzwertüberschreitungen tauchen ja nicht aus dem Nichts aus. Von irgendwo werden die Dinger ja angestoßen. Und dort kann man auch das Design des Ziel-CEs ändern lassen.

    ErfinderDesRades schrieb:

    Im Paint-Event - wenn du es abonnierst - sollst du painten.
    Auch wenn EdR manchmal in Rätseln spricht, bin ich mir sicher, dass er meint: Linien malen, Kreise, Bilder, whatever. Das, was Du brauchst, um das CE so aussehen zu lassen, wie es Dir gefällt - aber vom CE nicht anderweitig zur Verfügung gestellt wird! Da aber bei ner DGVCell mit Style.BackColor u.ä. das DGV sehr viel ermöglicht, ist das kein Fall, der mit dem Paint-EventHandler abgearbeitet werden muss/sollte.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

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

    Es ist schon eine Weile her, da hatte ich ein ähnliches Projekt. Ich weiß nicht mehr, ob ich hier
    im Forum damals den Tip bekam, das Paint Ereignis für die Farbwahl zu verwenden.

    Es ist halt schon ziemlich komplex, was ich da programmiere. Ich kann mich z.B. nicht darauf
    verlassen, dass die Leute Zahlen immer richtig eingeben. Zudem soll es auch möglich sein,
    Werte als "n.b." ("nicht bestimmt") einzugeben. Und trotzdem soll gerechnet werden, und all die
    anderen Sachen, die ich erwähnt hatte. Z.B. Daten nach unten ausfüllen .
    Hinzu kommt dann die Möglichkeit, dass Werte aus
    einer Datenbank übernommen werden, aber trotzdem per Hand geändert werden könnten.
    Aktualisieren per Button ist nicht so gut, weil es sehr blöd wäre, wenn durch einen Programmabsturz,
    oder plötzlichem Herunterfahren des PCs (womit wir bei unserer glorreichen IT immer mal rechnen müssen)
    oder Fehlbedienung die Daten eines Arbeitstages weg wären. Darum übertrage ich die Daten immer
    sofort an die Oracle-Datenbank. Das sind alles Vorgehensweisen, die sich im Laufe von ca. 20 Jahren
    an mehreren Projekten entwickelt haben. Es würde aber auch zu weit führen, wenn ich das alles hier erklären müsste.
    Kann ich insofern nicht nachvollziehen, weil ich denke, dass sehr vieles ohne das Abfangen des PaintEvents geht, siehe Anhang als Minimalbeispiel.
    Dateien
    • WindowsApp3.zip

      (13,32 kB, 11 mal heruntergeladen, zuletzt: )
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.