Automatische neuberechnung von Summen nach Änderungen in Bindingsource

  • VB.NET

Es gibt 7 Antworten in diesem Thema. Der letzte Beitrag () ist von DianonForce.

    Automatische neuberechnung von Summen nach Änderungen in Bindingsource

    Moin Com,

    ich steh mal wieder auf der Leitung.

    Ich hab in einem Formular ein Datagridview was mir eine Aufstellung zu den Artikeln eines Angebots anzeigt. Zusätzlich gibt es mehrere Textboxen die mir Summen über das ganze Angebot anzeigen. Das DGV ist gebunden an die Bindingsource bsKalkPos, die Textboxen sind ungebunden und deren Inhalt wird per Code berechnet. Um die Summen berechnen zu können, müssen allerdings pro Row erst Zwischensummern berechnet werden, die ich gleich als Info für die Anwender zurück in die Row schreibe.

    Wen an der Bindingsource des DGV Änderungen vorgenommen werden, soll eine Neuberechnung der Werte der Textboxen stattfinden. Dies klappt beim hinzufügen ohne Probleme, da ich hier die Berchnungen direkt nach dem hinzufügen der Row triggere.
    Beim Löschen mach ich das atm über

    VB.NET-Quellcode

    1. Private Sub bs_ListChanged(sender As Object, e As ListChangedEventArgs) Handles bsKalkPos.ListChanged, bsKalkUpos.ListChanged
    2. If e.ListChangedType = ListChangedType.ItemDeleted Then
    3. posBerechnungen()
    4. kalkBerechnungen()
    5. End If
    6. End Sub


    Wenn ein Anwender jetzt mehrer Zeilen im DGV selektiert und diese löschen will, wird allerdings nur eine Zeile gelöscht.Wenn ich meinen Code aus dem ListChanged Event entferne kann man allerdings mehrere Zeilen auf einmal löschen. Ich vermute das liegt daran, das ich in der getriggerten Berechnug ja auch Werte zurück in die Rows schreibe und sich somit das ListChanged übern den Umweg der Neuberechnung selber triggert.

    Wie bekomme ich es hin, das der Anwenderen mehrere Zeilen löschen kann, danach aber trotzdem eine neuberechnung ausgeführt wird?

    DianonForce schrieb:

    Wenn ein Anwender jetzt mehrer Zeilen im DGV selektiert und diese löschen will, wird allerdings nur eine Zeile gelöscht
    Bei mir wird das ListChanged-Event sooft gefeuert, wie Zeilen gelöscht werden. Da kannst Du letztenendes wohl nur mit Durchsteppen schauen, wo der Wolf verbuddelt liegt.
    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.
    Ja, durchsteppen ist so ne Sache, ich konnts jetzt auf nen Bereich eingrenzen, aber warum dieser verhindern soll, das das Event mehrfach gefeuert wird verstehe ich nicht.

    Zur Struktur des DS:

    kalkrow ist eine Row aus der parent Table
    kalkposrows sind die entsprechenden child rows zu kalkrow
    das DGV ist an die Bindingsorce für kalkpos, also die Tabelle der Childrows, gebunden. Demnach sollen auch mehrere Childrows gelöscht werden.

    Das hier wären die relevanten ausschnitte auf dem Form

    VB.NET-Quellcode

    1. Public Class KalkulationAnsicht
    2. Private kalkrow As kalkRow
    3. Private posrow As kalkposRow
    4. Private Sub KalkulatinAnsicht_Load(sender As Object, e As EventArgs) Handles Me.Load
    5. kalkrow = bsKalk.At(Of kalkRow)
    6. FillTables()
    7. End Sub
    8. Private Sub bsKalkPos_ListChanged(sender As Object, e As ListChangedEventArgs) Handles bsKalkPos.ListChanged, bsKalkUpos.ListChanged
    9. If e.ListChangedType = ListChangedType.ItemDeleted Then
    10. posBerechnungen()
    11. kalkBerechnungen()
    12. End If
    13. End Sub
    14. Private Sub kalkBerechnungen()
    15. With kalkrow
    16. .KopfAlleSummen
    17. Dim wartungGesamt As Double = .kalkWartungSwEk + .kalkWartungFarbeEk + .kalkWartungScanEk
    18. tbWartungGesamtEk.Text = (wartungGesamt).ToString("C2")
    19. tbWartungGesamtVk.Text = (.kalkWartungSwVk + .kalkWartungFarbeVk + .kalkWartungScanVk).ToString("C2")
    20. tbAllinEk.Text = (.kalkMieteEk + wartungGesamt).ToString("C2")
    21. tbHaspaProcent.Text = (.kalkAllinErtrag / (.kalkAllinVk * .kalkMietdauer)).ToString("P2")
    22. tbVolumenDruck.Text = (.kalkVolSw + .kalkVolFarbe).ToString()
    23. End With
    24. End Sub
    25. End Class

    wenn ich kalkBerechnungen auskommentiere im eigendlichen ListChanged Event auskommentiere wird das Event wieder mehrfach gefeuert.
    gleiches trifft auf .KopfAlleSummen zu, kommentier ich dies aus, wird auch wieder das Event mehrfach gefeuert
    Das ist die Sub kalkBerechnungen, kommentier ich hier .KopfAlleSummen aus, wird auch mehrfach gefeuert.

    Das ist KopfAlleSummen, darin finde ich aber nichts was eine Grund wäre, das das Event nicht mehrfach feuert

    VB.NET-Quellcode

    1. <Extension()>
    2. Public Sub KopfAlleSummen(row As kalkRow)
    3. If row.GetkalkposRows.Count > 0 Then
    4. row.kalkKaufEk = row.GetkalkposRows.Sum(Function(pos) pos.posEkGesamt)
    5. row.kalkKaufVk = row.GetkalkposRows.Sum(Function(pos) pos.posVkGesamt)
    6. row.kalkRestwert = row.GetkalkposRows.Sum(Function(pos) pos.posRestwert)
    7. row.kalkKaufErtrag = row.GetkalkposRows.Sum(Function(pos) pos.posVkGesamt) - row.GetkalkposRows.Sum(Function(pos) pos.posEkGesamt)
    8. row.kalkMieteEk = row.GetkalkposRows.Sum(Function(pos) pos.posMieteEk)
    9. row.kalkMieteVk = row.GetkalkposRows.Sum(Function(pos) pos.posMieteVk)
    10. row.kalkMieteErtrag = (row.GetkalkposRows.Sum(Function(pos) pos.posMieteVk) - row.GetkalkposRows.Sum(Function(pos) pos.posMieteEk)) / row.kalkMietfaktor
    11. row.kalkWartungSwEk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwEk)
    12. row.kalkWartungSwVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwVk)
    13. row.kalkWartungFarbeEk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeEk)
    14. row.kalkWartungFarbeVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeVk)
    15. row.kalkWartungScanEk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanEk)
    16. row.kalkWartungScanVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanVk)
    17. row.kalkAllinEk = row.GetkalkposRows.Sum(Function(pos) pos.posAllinEk)
    18. row.kalkAllinVk = row.GetkalkposRows.Sum(Function(pos) pos.posAllinVk)
    19. row.kalkAllinErtrag = (row.GetkalkposRows.Sum(Function(pos) pos.posAllinVk) - row.GetkalkposRows.Sum(Function(pos) pos.posAllinEk)) * row.kalkMietdauer
    20. row.kalkInstallationVk = row.GetkalkposRows.Sum(Function(pos) pos.posInstallationVk)
    21. row.kalkWkz = row.GetkalkposRows.Sum(Function(pos) pos.posWkz)
    22. row.kalkHfmBetragGesamt = row.GetkalkposRows.Sum(Function(pos) pos.posHfmBetragGesamt)
    23. row.kalkUhg = row.GetkalkposRows.Sum(Function(pos) pos.posUhgGesamt)
    24. row.kalkWartungEk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwEk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeEk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanEk)
    25. row.kalkWartungVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwVk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeVk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanVk)
    26. row.kalkWartungErtrag = (row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeVk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwVk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanVk) _
    27. - row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeEk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwEk) + row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanEk)) * row.kalkMietdauer
    28. row.kalkVolSw = row.GetkalkposRows.Sum(Function(pos) pos.posVolSwGesamt)
    29. row.kalkVolFarbe = row.GetkalkposRows.Sum(Function(pos) pos.posVolSwGesamt)
    30. row.kalkVolScan = row.GetkalkposRows.Sum(Function(pos) pos.posVolScanGesamt)
    31. Dim kalkWartungFarbeKlickFolgeVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungFarbeVk) / row.GetkalkposRows.Sum(Function(pos) pos.posVolFarbeGesamt)
    32. row.kalkWartungFarbeKlickFolgeVk = If(Not Double.IsNaN(kalkWartungFarbeKlickFolgeVk), kalkWartungFarbeKlickFolgeVk, 0)
    33. Dim kalkWartungSwKlickFolgeVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungSwVk) / row.GetkalkposRows.Sum(Function(pos) pos.posVolSwGesamt)
    34. row.kalkWartungSwKlickFolgeVk = If(Not Double.IsNaN(kalkWartungSwKlickFolgeVk), kalkWartungSwKlickFolgeVk, 0)
    35. Dim kalkWartungScanKlickFolgeVk = row.GetkalkposRows.Sum(Function(pos) pos.posWartungScanVk) / row.GetkalkposRows.Sum(Function(pos) pos.posVolScanGesamt)
    36. row.kalkWartungScanKlickFolgeVk = If(Not Double.IsNaN(kalkWartungScanKlickFolgeVk), kalkWartungScanKlickFolgeVk, 0)
    37. End If
    38. End Sub


    Es werden also eigendlich nur Felder in der parent Tabelle geändert, warum dies dazu führt das nur noch die erste der selektierten rows im DGV der Child Table gelöscht werden kann verstehe ich nicht. Vielleicht hat noch wer ne Idee.

    DianonForce schrieb:

    Ich vermute das liegt daran, das ich in der getriggerten Berechnug ja auch Werte zurück in die Rows schreibe und sich somit das ListChanged übern den Umweg der Neuberechnung selber triggert.

    Wie bekomme ich es hin, das der Anwenderen mehrere Zeilen löschen kann, danach aber trotzdem eine neuberechnung ausgeführt wird?


    Na, dann ist der Lösungsansatz doch klar:
    Deabonniere das ListChanged, wenn du massenoperationen tätigst, die weitere ListChanged auslösen würden.
    Danach wieder abonnieren.
    Stichwort AddHandler, RemoveHandler

    Oder besser noch die BindingSource.RaiseListchangedEvents - Property.

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

    Jap, über sowas habe ich auch schon nachgedacht, aber mir ist nicht klar wie ich feststellen soll, das die Löschoperationen fertig sind so das das Event wieder aboniert werden kann/soll.

    Ich find auch keinen Parmeter der mir vorab verrät wieviele Zeilen zum Löschen anstehen. Aber irgendwo muss es doch ne Liste geben von Zeilen die zum löschen markiert wurden, oder? Ich mein, ich kann mehrere Zeilen selektieren und die Entf-Taste drücken, also muss doch irgendwo bekannt sein was alles gelöscht werden soll, schließlich wird offensichtlich jede markierte Zeile einzeln gelöscht. Aus mir nicht verständlichem Grund muss anscheinend diese Liste geleert werden wenn ich die obrigen Codes ausführe. Wenn ich diese Liste unbewust manipuliern kann, sollte ich doch auch zumindest irgendwie darauf zugreifen können um rauszufinden was alles zum Löschen ansteht.

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

    Wenn du meine Extensions verwendest, kannst du auch versuchen, ein BusiDelay einzuschieben, sodass mit den Neuberechnungen erst begonnen wird, kurz bevor das Windows-BenachrichtigungsSystem in den WarteModus zurückfällt:

    VB.NET-Quellcode

    1. Private Sub Calculate()
    2. posBerechnungen()
    3. kalkBerechnungen()
    4. End Sub
    5. Private Sub bsKalkPos_ListChanged(sender As Object, e As ListChangedEventArgs) Handles bsKalkPos.ListChanged, bsKalkUpos.ListChanged
    6. If e.ListChangedType = ListChangedType.ItemDeleted Then
    7. BusyDelay.SetCallback(AddressOf Calculate)
    8. End If
    9. End Sub
    Einen Versuch wärs wert.