Warum werden dgv Paint Events gefeuert?

  • VB.NET
  • .NET 5–6

Es gibt 9 Antworten in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    Warum werden dgv Paint Events gefeuert?

    Hallo,

    ich kämpfe mich gerade durch ein Problem beim asynchronen Löschen von Daten. Ich verstehe nicht was da genau passiert.

    ich habe ein typisches Konstrukt, DataTable an BindingSource an DGV.

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. DisableGUI()
    3. Await Task.Run(AddressOf DataUpdate)
    4. EnableGUI()
    5. End Sub
    6. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    7. DisableGUI()
    8. DS1.Test.Clear()
    9. EnableGUI()
    10. End Sub

    In DataUpdate wird die Tabelle gefüllt. Button1 läuft an sich ansynchron und auch mehrmals hintereinander ohne Probleme.
    Button2 läuft so erstmal auch.
    Mache ich ihn aber asynchron, dann feuert das RowPrePaint-Event des DGVs, und rennt dabei in einen Fehler, weil beim Clearen ja Daten gelöscht werden. ListChangedEvents der BindingSource werden deaktiviert.

    VB.NET-Quellcode

    1. Private Async Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    2. DisableGUI()
    3. Await Task.Run(Sub() DS1.Test.Clear())
    4. EnableGUI()
    5. End Sub

    Bevor ich nun RemoveHandler auf den Eventhandler des RowPrePaint-Events haue, würde ich gerne verstehen was da passiert.

    Eigentlich liegt genau dasselbe Problem bei Button1 vor, da feuert auch das RowPrePaint-Event, nur muss man sich ziemlich verrenken um dabei Fehler zu provozieren.
    Im synchronen Fall kann der Eventhandler ja nicht laufen bevor die Aktualisierung abgeschlossen ist, weshalb es dann auch keine Problem gibt. Aber der Auslöser dieses Events ist mir nicht klar.

    Ich hab es auf SuspendBinding in der DisableGUI zurückgeführt. Aber das ist ja eigentlich genau warum ich SuspendBinding aufrufe, damit solche Sachen nicht passieren.

    Viele Grüße

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    wenn du das dataset nebenläufig befüllst, werden lauter Events geworfen, die an die Databinding-Infrastruktur addressiert sind, und somit an den GUI-Thread.
    Du hast da also unzulässige Threadübergreifende Zugriffe, aber leider unter Umgehung der dafür zuständigen Exception.
    Ich fürchte, du musst alle Bindingsources vorher abkoppeln und hinterher wieder ankoppeln.
    Vielleicht reicht auch, bs.RaiseListChangedEvents zu suspendieren, mit dem hier:

    VB.NET-Quellcode

    1. <Extension()> _
    2. Public Sub ListChangedEnabled(bs As BindingSource, value As Boolean)
    3. bs.RaiseListChangedEvents = value
    4. If value Then bs.ResetBindings(False)
    5. End Sub
    Ja, ist bei mir entsprechend im EnableGUI.
    Sorry, ich sollte schon im Eingangspost vermittelt haben, dass ich das ab- und anschalten der BindingSource tue wie es sein soll, das habe ich wohl für zu selbstverständlich gehalten.
    Morgen früh lass ich mir noch ein paar Spielereien einfallen, vielleicht finde ich noch mehr raus.
    Mit BeginLoadData EndLoadData konnte ich keine Veränderung erzielen.
    Aber ich habs nochmal weiter schrumpfen können.

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. DS1.Test.Clear() 'Wenn ich undisabled cleare gibts keine Fehler
    3. DisableGUI()
    4. Await Task.Run(AddressOf DataUpdate)
    5. EnableGUI()
    6. End Sub

    VB.NET-Quellcode

    1. Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. DisableGUI()
    3. DS1.Test.Clear() 'Wird hier gecleart, knallts im Update nach Aufruf von Test.Fill und bevor diese returnt, der Fehler taucht aber im RowPrePaint Handler auf.
    4. Await Task.Run(AddressOf DataUpdate)
    5. EnableGUI()
    6. End Sub

    Verfrachte ich das Clear in das DataUpdate, entsteht derselbe Fehler nach Aufruf von .Fill
    Da Fill nebenläufig ausgeführt wird kommt da also irgendein Impuls in den Hauptthread

    Der Fehler selbst hat aber damit zutun, dass die Tabelle geleert wurde die BindingSource das aber noch gar nicht mitgekriegt hat. (DisableGUI)
    Der RowPrePaint-Eventhandler läuft also immer; da dieser aber über das Binding zurück auf eine Datenzeile will, gibts dann den Fehler, die Zeile is ja weg. Der Fehler ist demnach meines Erachten vollkommen verständlich und richtig.

    Aber das RowPrePaint-Event sollte da nicht auslösen denke ich.

    Jetzt kann ich zwar Clearen einfach vors Disablen setzen, aber das ist ja nicht die einzige Möglichkeit DataTable und BindingSource zu desynchronisieren.
    Das DataUpdate selbst kann ja schon Daten auf eine Weise ändern, die zu den gleichen Konflikten führen und das kann ich nicht vor das Disable setzen.

    Dementsprechend denke ich ist ein Removehandler/AddHandler wohl notwendig...
    Die Frage beschränkt sich in diesem Fall vollständig auf die DataTable.

    Ich habe das Problem, dass beim Debuggen, wenn eine Exception auftritt, die Referenz zu einer Tabellenzeile fälschlicherweise Nothing anzeigt.
    Ich nehme an das liegt daran, dass die Methode im Nebenthread ausgeführt wird. Und ich deswegen beim Debuggen nicht in die dort erzeugten Instanzen gucken kann.