DataGridView CellFormatting sorgt für Performance-Probleme

  • VB.NET
  • .NET 4.0

Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    DataGridView CellFormatting sorgt für Performance-Probleme

    Hallo zusammen.

    Ich lass mir in einem DataGridView Daten aus einem DataSet anzeigen, Zellen mit 0 sollen "leer" erscheinen,
    Rows mit Inhalt "Samstag" oder "Sonntag" sollen grau markiert werden. Das klappt auch mit unten stehendem Code, allerdings
    gibt's dadurch massive Performanceprobleme beim Scrollen etc.

    Kann man das eleganter lösen? Wenn ich u.g. Code auskommentiere verhält sich das DGV den Umständen entsprechend "normal"

    VB.NET-Quellcode

    1. Private Sub dgv_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles dgv.CellFormatting
    2. If Object.Equals(e.Value, 0) Then e.Value = "" : e.FormattingApplied = True
    3. If Object.Equals(e.Value, 0D) Then e.Value = "" : e.FormattingApplied = True
    4. If Object.Equals(e.Value, 0#) Then e.Value = "" : e.FormattingApplied = True
    5. If Object.Equals(e.Value, "Samstag") OrElse Object.Equals(e.Value, "Sonntag") Then dgv.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.LightGray
    6. End Sub
    Originaler (noch) Nichtskönner :D
    probiermal ob das schneller ist

    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
    2. For Each row As DataGridViewRow In DataGridView1.Rows
    3. For Each cell As DataGridViewCell In row.Cells
    4. 'color cells null
    5. If String.IsNullOrEmpty(CStr(cell.Value)) Then
    6. cell.Style.BackColor = Color.Silver
    7. 'color cells Samstag + Sonntag
    8. ElseIf cell.Value.ToString.Contains("Sa") Or _
    9. cell.Value.ToString.Contains("So") Then
    10. cell.Style.BackColor = Color.LightBlue
    11. cell.Style.ForeColor = Color.Blue
    12. End If
    13. Next
    14. Next
    15. End Sub


    aber kannst du nicht Samstag und Sonntag beim Laden schon färben?

    VB.NET-Quellcode

    1. 'code......
    2. If d.DayOfWeek = DayOfWeek.Saturday Or d.DayOfWeek = DayOfWeek.Sunday Then
    3. .Rows(j - 1).Cells(col).Style.BackColor = Color.LightBlue
    4. 'code.....



    ErfinderDesRades schrieb:

    Lässt sich das Problem auf genau zeile #5 eingrenzen?

    ja, scheint die Zeile zu sein.

    Kasi schrieb:

    probiermal ob das schneller ist

    leider eine "Vollkatastrophe", er braucht nun fast 2 Minuten, um das DGV überhaupt zu füllen ;)

    Kasi schrieb:

    aber kannst du nicht Samstag und Sonntag beim Laden schon färben?

    macht er ja über's CellFormatting
    Originaler (noch) Nichtskönner :D
    Jo, das .CellFormatting scheint ein ungeeignetes Event zu sein, um einen Row-DefaultCellStyle zu setzen.
    .CellFormatting wird wie der Name sagt für jede Zelle aufgerufen - und zwar findet das im Zusammenhang mit dem Paint-Vorgang statt.
    Folglich ergibt sich eine EreignisKette, nämlich die Modifikation des DefaultStyles der Row löst ja logisch wiederum einen Paint-Vorgang für alle Zellen dieser Row aus.

    Probiermal stattdessen das .RowPrePaint - Event.

    (und wenn das auch nicht hilft, muss man wohl richtig Optimierung auffahren, einen Cache bauen oder sowas...)

    Aber spasseshalber kannste ja auch mal Debug-Ausgaben machen, um die Abfolge der Events nachzuvollziehen.
    Ja, Deine Vermutung ist richtig*. Nur wird CellFormatting für jede Zelle aufgerufen. Und da Du dabei u.U. das komplette DGV umfärbst, ergibt sich ein entsprechend erhöhter Aufwand. Jede Zelle sollte sich um die eigene Darstellung kümmern, nicht um die anderen.

    btw: Post#3, Codeblock#1, Zeile#10 und CB#2, Z#2: Der Unterschied zwischen And und AndAlso/Or und OrElse

    ##########

    * zumindest, wenn die Daten bei Programmstart geladen werden. Wenn zur Laufzeit, dann wird ggf. mit jeder neuen Datenzeile das Event gefeuert. Und zwar sooft, wie es (anzeigbare?) Spalten gibt.
    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 2 mal editiert, zuletzt von „VaporiZed“ ()

    ErfinderDesRades schrieb:

    Probiermal stattdessen das .RowPrePaint - Event.


    würd' ich gerne ma testen, ich weiß aber akut nicht wie ich da einen Zellinhalt abfragen kann (der Zellinhalt von "Tag" muss ja Samstag oder Sonntag sein, zum Einfärben)...
    Originaler (noch) Nichtskönner :D
    Öhm … wieso eigentlich Post#1: dgv.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.LightGray? Warum nicht dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Style.BackColor = Color.LightGray? Wie gesagt: Jede Zelle sollte sich immer nur um sich selbst kümmern. Oder Ist das Sinn der Sache, dass die komplette Zeile gegraut wird? Weil: Wenn nur in einer Zelle der Zeile Samstag/Sonntag steht, dann sollte, wenn die Zelle einer anderen Spalte gemalt wird, ja gar nix passieren. Zeig mal bitte ne Beispielzeile.
    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.

    VaporiZed schrieb:

    Oder Ist das Sinn der Sache, dass die komplette Zeile gegraut wird?

    jop, ist sinnig für die Ansicht:


    Ich hab's nun mittels "DoubleBuffering" wie hier beschrieben eindämmen können, das DGV läuft nun ohne großartige Probleme ;)
    Originaler (noch) Nichtskönner :D

    tragl schrieb:

    würd' ich gerne ma testen, ich weiß aber akut nicht wie ich da einen Zellinhalt abfragen
    ZellInhalt abfragen ist ja eh nicht wirklich schön.
    Besser ist, du fragst den Datensatz - dgv.Row(e.RowIndex).DataboundItem ab, DoppelCast auf die typisierte Row, und dann die Daten-Property abfragen, die interessiert

    VB.NET-Quellcode

    1. dim rw = DirectCast(DirectCast(dgv.Rows(e.RowIndex).DataBoundItem,DataRowView).Row, DatenabfrageHCRow)
    2. if rw.Datum.Weekday.IsInRange(Samstag, Sonntag) then dgv.Row(e.RowIndex)->blau ' so sinngemäss

    Aber das mittm DoubleBuffer sieht ja auch interessant aus - aber das ist ein Hack, weisste, ne?

    CodeProject schrieb:

    ...it also significantly reduces the amount of functions being called internally in the DataGridView.
    Zu hoffen, dass das keine Nebenwirkungen zeitigt.
    ich habe mal den Vorschlag von @ErfinderDesRades probiert,
    ich nutze allerdings immer eine Zahl für die Tage

    VB.NET-Quellcode

    1. Private Sub DataGridView1_RowPostPaint(sender As Object, e As System.Windows.Forms.DataGridViewRowPostPaintEventArgs) Handles DataGridView1.RowPostPaint
    2. If e.RowIndex < 0 OrElse DataGridView1.Rows(e.RowIndex).IsNewRow Then Return
    3. Select Case CInt(DataGridView1.Rows(e.RowIndex).Cells(3).Value)
    4. Case Is = 0, 6 ' Samstage, Sonntag
    5. DataGridView1.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.Lavender
    6. Case Is = 1, 2, 3, 4, 5 'restliche Tage
    7. DataGridView1.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.Moccasin
    8. Case Else
    9. End Select
    10. End Sub

    ErfinderDesRades schrieb:

    Besser ist, du fragst den Datensatz

    Hab ich folgendermaßen gelöst:

    VB.NET-Quellcode

    1. Private Sub dgv_RowPrePaint(sender As Object, e As DataGridViewRowPrePaintEventArgs) Handles dgv.RowPrePaint
    2. Dim rw = DirectCast(DirectCast(dgv.Rows(e.RowIndex).DataBoundItem, DataRowView).Row, DatenabfrageHcRow)
    3. If rw.Tag = "Samstag" OrElse rw.Tag = "Sonntag" Then dgv.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.LightGray
    4. End Sub


    macht aber ohne DoubleBuffer die gleichen Probleme :rolleyes:

    ErfinderDesRades schrieb:

    Zu hoffen, dass das keine Nebenwirkungen zeitigt.

    bisher nicht... ich behalt' das mal im Auge ;)
    Originaler (noch) Nichtskönner :D
    bei mir leider schon, hab aber im Gesamten das Gefühl, dass die komplette Anwendung eher "langsam" läuft (was scrollen etc. anbelangt)
    vom Gefühl her fehlt hier eine Hardwarebeschleunigung, das verhält sich so als würde die Anwendung auf einem Remoteserver mit Windows Server 2012 laufen (da ruckelt auch immer alles beim Scrollen)...

    Hab' ich ne grundlegende Setting übersehen?
    EDIT: ich bin schon am Überlegen irgendwie alles auf WPF umzubasteln (nur aus Performancegründen) weil unsere Rechner bald alle Win10 haben... hab' aber die Hoffnung, dass das auch anders geht
    Originaler (noch) Nichtskönner :D

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