Beantwortet Datagridview, Paralleltask führt zur Exception

  • Montag, 6. August 2012 11:37
     
      Enthält Code

    Hallo zusamen,

    ich habe heute Nacht ein merkwürdigen Fehler in einer Anwendung herausgefunden. Ich fülle eine Datatable über einen SQLDataAdapter und binde diesen an ein DataGridView. Wenn fertig gebunden, wird das DataBindingComplete Event ausgelöst und dabei ein neuer Task gestartet der Daten im DGV überprüft und Zellen mit Bildern versieht. Soweit klappt der Vorgang auch problemlos, nur sobald ich die Spalten sortiere, bekomme ich aus dem Task die Fehlermeldung, dass eine Spalte nicht vorhanden ist. Warum passiert das?

            Dim Icons_Anpassen = Threading.Tasks.Task.Factory.StartNew(Sub()
                                                                           Try
                                                                               For Each rw As DataGridViewRow In Me.dgvKVPListe.Rows
                                                                                   Dim _icons = (Sub(r As DataGridViewRow)
                                                                                                     r.Cells("KVPImg").Value = New System.Drawing.Bitmap(System.Drawing.Image.FromFile(My.Application.Info.DirectoryPath & r.Cells("KVPStatus").Value.ToString), New System.Drawing.Size(20, 20))
                                                                                                     r.Cells("PrioImg").Value = System.Drawing.Image.FromFile(My.Application.Info.DirectoryPath & r.Cells("Priorität").Value.ToString)
    
                                                                                                     TryCast(r.Cells("Anhangimg"), DataGridViewImageCell).Value = New System.Drawing.Bitmap(System.Drawing.Image.FromFile(My.Application.Info.DirectoryPath & "\icons\weiss.png"), New Drawing.Size(30, 18))
    
                                                                                                     If IO.Directory.Exists("I:\Produktion\PPRep\KVP_" & r.Cells("KVPID").Value.ToString.PadLeft(5, "0").ToString) = True Then
                                                                                                         If System.IO.Directory.GetFiles("I:\Produktion\PPRep\KVP_" & r.Cells("KVPID").Value.ToString.PadLeft(5, "0").ToString).Count > 0 Then
                                                                                                             TryCast(r.Cells("Anhangimg"), DataGridViewImageCell).Value = New System.Drawing.Bitmap(System.Drawing.Image.FromFile(My.Application.Info.DirectoryPath & "\icons\Anhang.png"), New Drawing.Size(18, 18))
                                                                                                         End If
                                                                                                     End If
                                                                                                 End Sub)
                                                                                   Me.dgvKVPListe.Invoke(_icons, rw)
                                                                               Next
    
                                                                           Catch ex As Exception
    
                                                                           End Try

Alle Antworten

  • Montag, 6. August 2012 12:57
     
     
    Hi David,
    welche Ausnahme kommt denn?
     
    Ich sehe in Deinem Codeabschnitt nicht, wie Du den thread-übergreifenden Zugriff organisierst bzw. absicherst. Ich vermute, dass das ein Problem ist und zur Ausnahme führt.
     
    --
    Viele Gruesse
    Peter
  • Montag, 6. August 2012 12:58
     
     

    Hi David,

    wenn ich das gerade Richtig sehe probierst du in einem Eigenen Thread auf das DataGridView zu zugreifen.

    Während du in den Anderen einen Filter ausführst und somit die Zeile Entfernst.

    Zugriffe auf Steuerelemente sollten nur in Ihrem eigenen Thread gemacht werden.

    MFG

    Björn

  • Montag, 6. August 2012 14:08
     
     

    Hallo zusammen,

    der Fehler ist der folgende...

    Threadübergreifenden Zugriff auf ein Steuerelement kann man mit Invoke realisieren. Wenn man eine Spalte umsortiert werden doch die Zeilen nicht gelöscht?! Sogar wenn .... im Thread wird mit einer for each Schleife gearbeitet und wenn zu diesem Zeitpunkt keine Zeilen vorhanden sind, sollte da auch nichts durchlaufen werden.

  • Montag, 6. August 2012 14:09
     
     

    Hallo Peter,

    was genau meinst du mit organisieren bzw. absichern?


    Meinst du damit  Try-Catch?
    • Bearbeitet Desert-Fox Montag, 6. August 2012 14:13
    •  
  • Montag, 6. August 2012 19:31
     
     

    Hi David,

    ok du Sortierst die eine Spalte.

    Wenn ich das jetzt richtig im Kopf habe, ändert sich dadurch die Reihenfolge in der Rows Collection.
    Was dann beim For Each Probleme macht könnte.

    Wie du Richtig festgestellt hat kann man aus anderen Threads auf Steuerelemente zugreifen, man sollte es aber nicht wenn es sich Vermeiden lässt.

    MFG

    Björn

  • Montag, 6. August 2012 20:59
     
     

    Hallo Björn,

    ich habe mich dazu entschieden dies so zu tun, damit das Prüfen einer Situation im Hintergrund vorgenommen werden kann. Für den Enduser ist die Form dann sofort da und läuft 1-2 Sek nach .... das ist aber nicht so schlimm als auf die Form 1-2Sek zu warten.

    Außerdem ist der Threadübergreifende Zugriff doch eine extrem coole Sache!! Alles läuft flüssig und im Hintergrund wird gearbeitet. Ist doch 1000mal schöner als immer auf die Anwendung warten zu müssen :-)

    Übrigens hat eine einfache TryCatch bei meinem Problem echt wunder vollbracht :-)

  • Dienstag, 7. August 2012 09:11
     
     

    Hi David,

    Fehler die bei Threadübergreifenden Zugriffen Entstehen können, sind aber eine wirklich uncoole Sache.!!

    Das sind Fehler, die dann nur beim Kunden auftreten, weil er zB. eine andere Festplatte hatte und die Daten von der Platte schneller oder langsamer geladen werden.

    Du kannst dann den Fehler nicht bei dir nicht nachvollziehen und brauchst dann Ewigkeiten, um den Fehler zu beheben, falls du ihn überhaupt findest.

    Meine Idee für dein Problem Lade die Bilder Parallel zum Laden der Daten in eine Liste.

    Wenn du dann die Bilder und die Daten geladen hast, setze die Bilder ins Datatabel (nicht ins Grid) .

    Und dann Binde das Tabel ans Grid.

    Wie so:

    Wenn ich das Oben richtig gesehen habe, hast du nur 2 Unterschiedliche Bilder.

    Statt also für jede Zeile ein neues Bild in den Speicher zu laden hast du jetzt nur 2 Bilder im Speicher und setzt nur den Verweis auf das Bild.

    Beim setzten von 100.000 Verweisen sind, wir dann irgendwo im Millisekunden Bereich, die der Kunde dann Warten muss.

    Und ins Tabel setzt du die Vereise, damit du Daten und View getrennt hast.

    Zusätzlich (wenn ich das jetzt Richtig im Kopf habe), geht das DataGridView beim Binden hin und erzeugt Erstmal nur für eine Bestimmte Anzahl von Datensätzen die Spalten und nicht direkt für alle. Was wider Performance bringt .    

    Wie ein Try Catch jetzt deinen Fehler gelöst haben soll, ist mir ehrlich gesagt nicht klar.

    Wenn du jetzt einfach einen Lehren Catch-Block hast, ist der Fehler immer noch da. Er wird nur abgefangen.

    Ich denke das Resultat ist das eine Zeile die eigentlich ein Bild haben sollte keins hat.

    Wenn du noch was anderes machst Poste doch bitte deine Lösung, damit andere die das gleiche Problem habe, sie vielleicht nutzen können.

    MFG

    Björn

  • Dienstag, 7. August 2012 22:24
     
     

    Hallo Björn,

    freue mich hier eine kleine Disskussion gestartet zu haben :-) Mein ich wirklich ernst weil ich in diesem Thema noch nicht viel Erfahrung habe.

    Bei dem Task den ich im ersten Beitrag gepostet habe, wird auf einem Netzlaufwerk geschaut ob in den jeweiligen Unterordner Dokumente vorhanden sind. Alleine diese Abfrage dauert schon eine kleine Ewigkeit! Das Binden der Bilder ist an der Stelle das kleinere Übel.

    Bei einer anderen Übung wird mit einem DataView auf eine DataTable zugegriffen und geprüft ob ein Mitarbeiter Urlaub hat oder nicht. Die Abfrage ist super schnell und die Bilder sind fast zeitgleich geladen wie die Form! Trotzdem bekomme ich den oben gezeigten Fehler wenn ich nun das DataGridView umsortiere! Hängt es an der Stell wirklich am anderen Thread und vorallem warum? Hierbei wird nichts von der Festplatte oder Netzwerk geladen! Alle Bilder sind im Arbeitsspeicher! Warum kommt der Fehler trotzdem?

    Als Abhilfe habe ich es momentan nur mit einem leeren Catch-Block realisieren können. Ich bin um ehrlich zu sein auch nicht sehr zufrieden mit der Lösung aber sie funktioniert erstmal zuverlässig.

    Meinst du also, eine DataTable mit den entsprechenden Bildern direkt an ein DGV zu binden würde noch mehr performance rausholen?

    Beste Grüße
    David

  • Mittwoch, 8. August 2012 04:34
     
     Beantwortet
    Hi David,
    in dem geposteten Codestück greifst Du auf auf die DataGridViewImageCell aus einem anderen thread zu.
     
    Du musst Dir immer bewusst sein, dass threading auf CPU-Niveau ausgeführt wird. Das bedeutet, dass ein komplexer Ablauf, der in VB oder C# als ein Befehl geschrieben wird, in viele CPU-Befehle übersetzt wird. Das Umschalten zwischen den threads an beliebiger Stelle der CPU-Befehlsfolge kann zu Inkonsistenzen des Zustandes eines Objektes führen. Um diese Inkonsistenzen zu vermeiden ist entweder mit viel Aufwand der Zugriff threadsicher zu gestalten oder einfach nur der threadübergreifende Zugriff durch den Anwender zu vermeiden. Vermieden werden kann der threadübergreifende Zugriff, indem die konkreten (meist Schreibbefehle) mittels Invoke in den Eigentümer-thread so eingeordnet werden, dass sie an einer ungefährlichen Stelle im Programmablauf ausgeführt werden.
     
    Der Einbau von try/catch zum Unterdrücken entstehender Fehler ist vergleichbar mit dem Führen eines Autos mit verbundenen Augen, um einen möglichen Crash nicht zu sehen.
     
    --
    Viele Gruesse
    Peter
  • Montag, 3. September 2012 11:53
    Besitzer
     
     

    Hallo David Stania,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.