Mehrere Markierte Zeilen im Datagridview löschen

  • VB.NET

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Mehrere Markierte Zeilen im Datagridview löschen

    Hallo ich würde gern erneut Eure Hilfe in Anspruch nehmen.
    Mit folgendem Code versuche ich mehrere markierte Zeilen eines Datagridviews zu löschen.
    Leider funzt das nicht wie gewünscht. Ich hab das Gefühl das willkürlich eine Anzahl von markierten Zeilen gelöscht wird.

    Vielleicht habt Ihr einen hilfreichen Tipp für mich? :?:
    Vielen Dank im voraus.

    VB.NET-Quellcode

    1. For Each Row As DataGridViewRow In DGValleVertraege.Rows
    2. DGValleVertraege.Rows.RemoveAt(DGValleVertraege.CurrentRow.Index)
    3. Next​
    Schlimmer als ein Elefant im Porzellanladen, ist ein Igel in der Kondomfabrik und Nutella hat Lichtschutzfaktor 9,7 8)

    Steamy2010 schrieb:

    Leider funzt das nicht wie gewünscht.
    For Each funktioniert nicht.
    Mach eien For-Schleife, die rückwärts die Items durchläuft, so dass beim Löschen die Collection da, wo noch zugegriffen werden muss, nicht umgebaut wird.
    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!
    Zunächst danke für die Antworten, jedoch wenn ich (vorausgesetzt ich habe es richtig umgesetzt) es so mache
    gibt es immer einen "Der Index lag außerhalb des Bereichs" Fehler.

    VB.NET-Quellcode

    1. For i = DGValleVertraege.Rows.Count - 1 To 0 Step -1
    2. If DGValleVertraege.SelectedRows(i).Selected = True Then
    3. DGValleVertraege.Rows.RemoveAt(DGValleVertraege.CurrentRow.Index)
    4. End If
    5. Next​
    Schlimmer als ein Elefant im Porzellanladen, ist ein Igel in der Kondomfabrik und Nutella hat Lichtschutzfaktor 9,7 8)

    Steamy2010 schrieb:

    Fehler
    Wenn, dann so (ungetestet):

    VB.NET-Quellcode

    1. For i = DGValleVertraege.Rows.Count - 1 To 0 Step -1
    2. If DGValleVertraege.Rows(i).Selected Then ' dies hier
    3. DGValleVertraege.Rows.RemoveAt(i) ' und dies hier
    4. End If
    5. Next
    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!
    Die SelectedRows-Auflistung representiert doch alle ausgewählten Zeilen im DGV, da brauchst du die Selected-Eigenschaft nicht extra abrufen...

    VB.NET-Quellcode

    1. For i = DGValleVertraege.SelectedRows.Count - 1 To 0 Step -1
    2. DGValleVertraege.SelectedRows(i).Remove
    3. Next

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

    Ups, hast recht - diesen Member gibt's da gar nicht :/ Sorry - obiges war nur aus dem Kopf...
    Da habe ich damals doch die Bindingsource dazu hergenommen...

    VB.NET-Quellcode

    1. DeineBindingSource.RemoveAt(DGValleVertraege.SelectedRows(i).Index)
    oder bei ungebundenen DGV's...

    VB.NET-Quellcode

    1. DGValleVertraege.Rows.RemoveAt(DGValleVertraege.SelectedRows(i).Index)

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

    Da der Thread noch nicht all zu alt ist möchte ich ein Problem vorstellen und mich anschließen:

    Ich möchte in meinem DGV ebenfalls mehrere Zeilen löschen können.
    Das DGV ist gebunden an Typdataset, also soll in der BS gelöscht werden.

    Zusätzlich soll jedoch geprüft werden ob Childrows da sind da ich keine Löschweitergabe im Dataset will (sonst sind mal eben bei unsachgemäßer Bedienung sehr viele Datensätze weg!).
    Fehler:
    Ein Ausnahmefehler des Typs "System.ArgumentOutOfRangeException" ist in mscorlib.dll aufgetreten.

    Zusätzliche Informationen: Der Index lag außerhalb des Bereichs. Er muss nicht negativ und kleiner als die Auflistung sein.



    Hier der Code:

    Quellcode

    1. If FrmDialogLoeschen.DialogResult = Windows.Forms.DialogResult.OK Then
    2. If TblCatEinrichtungBindingSource.Count > 0 Then
    3. 'ab hier der Code um mehrere markierte Zeilen zu löschen
    4. For i = DgvTblCatEinrichtung.Rows.Count - 1 To 0 Step -1
    5. If DgvTblCatEinrichtung.Rows(i).Selected = True Then
    6. MessageBox.Show("RoW: " & CStr(i))
    7. Dim rwCat = DirectCast(DirectCast(TblCatEinrichtungBindingSource.Item(DgvTblCatEinrichtung.SelectedRows(i).Index), DataRowView).Row, DS.tblCatEinrichtungRow)
    8. AnzahlCatEinrichtungen = rwCat.GettblEinrichtung_Rows.Count
    9. If AnzahlCatEinrichtungen > 0 Then
    10. MessageBox.Show("Diese Kategorie wird noch bei " & AnzahlCatEinrichtungen & " Datensätzen angewendet!" & vbCrLf & "Sie kann daher nicht gelöscht werden!", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
    11. Else
    12. TblCatEinrichtungBindingSource.RemoveCurrent()
    13. End If
    14. End If
    15. Next
    16. Else
    17. MessageBox.Show("In einer leeren Tabelle kann nichts gelöscht werden!", "Tabelle leer!", MessageBoxButtons.OK, MessageBoxIcon.Information)
    18. End If
    19. End If


    Fällt Euch was ein?

    edit: sehe grad da steckt noch ein Remote current drin was natürlich Mist ist... Stammt von vor der änderung auf mehrere Zeilen löschen
    Gruß Hannes

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „hans im glück“ ()

    vlt. hat dein DGV Hinzufügen aktiviert, also eine ZufügeZeile.
    Diese Zeile ist eine zuviel für die BindingSource, denn da ist ja kein Datensatz drin.

    Aber mach doch wie vorgeschlagen, über die SelectedRows-Auflistung. Da erhälst du zuverlässig nur Indizees, die auch da sind.

    Übrigens würde ich empfehlen, den MVB-Namespace - GeneralImport zu entfernen.

    Und übrigens du brauchst niemals mit True zu vergleichen: Boolean, Vergleiche und bedingte Verzweigungen

    ErfinderDesRades schrieb:

    vlt. hat dein DGV Hinzufügen aktiviert, also eine ZufügeZeile.
    Diese Zeile ist eine zuviel für die BindingSource, denn da ist ja kein Datensatz drin.

    Aber mach doch wie vorgeschlagen, über die SelectedRows-Auflistung. Da erhälst du zuverlässig nur Indizees, die auch da sind.


    also die Bearbeitung des DGV ist über den Designer komplett gesperrt, habe hierfür Detail VIew.

    Die Selected Rows Auflistung habe ich doch im Direct Cast drin? Funktioniert aber trotzdem nicht.
    Gruß Hannes
    uih - ja, so ist das natürlich ganz falsch.
    Weil die äussere Schleife zählt noch immer alle DGV-Rows durch, und natürlich gibts mehr DGV-Rows als es SelectedRows gibt.

    Du dir die SelectedRows erstmal in eine Array umkopieren, denn möglicherweise verhält sich eine SelectedRowCollection noch komischer, wenn eine Row davon gelöscht wird (vlt. geht dann die Selection gleich verloren.)
    Und dann das Array rückwärts durchlaufen - nicht die DGV-Rows.
    so nun ist es spät, ich habe jedoch folgendes zusammen gebracht was scheinbar auch funktioniert.(mir als anfänger ist aber ehrlich gesagt im augenblick nicht mehr klar ob ich alle eventualitäten beachtet habe).

    kritik erwünscht, hoffe ich habe es richtig verstanden:

    Quellcode

    1. If FrmDialogLoeschen.DialogResult = Windows.Forms.DialogResult.OK Then
    2. 'Prüfen ob überhaupt Rows/datensätze vorhanden sind
    3. If TblCatEinrichtungBindingSource.Count > 0 Then
    4. 'Array Dimension Anhand der Bindingsource festlegen
    5. Dim index(TblCatEinrichtungBindingSource.Count - 1) As Integer
    6. Dim ai As Integer = 0
    7. For i = DgvTblCatEinrichtung.Rows.Count - 1 To 0 Step -1
    8. If DgvTblCatEinrichtung.Rows(i).Selected = True Then
    9. 'Zum Verständnis (Testphase) Reihe und Array Index sowie Wert anzeigen lassen
    10. MessageBox.Show("RoW: " & CStr(i))
    11. index(ai) = i
    12. MessageBox.Show("Array Index: " & CStr(ai) & "DGV Rw Index: " & CStr(i))
    13. ai += 1
    14. Else
    15. 'Alle nicht selektierten Rows erhalten einen negativen Wert damit sie folgend ausgefiltert werden können
    16. index(ai) = -1
    17. ai += 1
    18. End If
    19. Next
    20. 'Messagebox zum Verständnis der nächsten Phase (Testbetrieb)
    21. MessageBox.Show("Jetzt wird der im Array gespeicherte Wert rückwärts abgerufen")
    22. For y = 0 To index.Count - 1 Step 1
    23. If index(y) >= 0 Then
    24. MessageBox.Show("Schleifenwert/ Array Index: " & CStr(y) & "Array Index Inhalt" & index(y))
    25. Dim rwCat = DirectCast(DirectCast(TblCatEinrichtungBindingSource.Item(DgvTblCatEinrichtung.Rows(index(y)).Index), DataRowView).Row, DS.tblCatEinrichtungRow)
    26. MessageBox.Show(rwCat.Category)
    27. Dim childrows As Integer = rwCat.GettblEinrichtung_Rows.Count
    28. If childrows > 0 Then
    29. MessageBox.Show("Diese Kategorie wird noch bei " & childrows & " Datensätzen angewendet!")
    30. Else
    31. TblCatEinrichtungBindingSource.RemoveAt(DgvTblCatEinrichtung.Rows(index(y)).Index)
    32. End If
    33. End If
    34. Next
    35. Else
    36. MessageBox.Show("In einer leeren Tabelle kann nichts gelöscht werden!", "Tabelle leer!", MessageBoxButtons.OK, MessageBoxIcon.Information)
    37. End If
    38. End If
    Gruß Hannes

    VB.NET-Quellcode

    1. Private Sub DeleteRows()
    2. If FrmDialogLoeschen.DialogResult = Windows.Forms.DialogResult.OK Then
    3. Dim selectedIndicees = From rw In DgvTblCatEinrichtung.SelectedRows.Cast(Of DataGridViewRow)() Select rw.Index Order By Index Descending
    4. If Not selectedIndicees.Any Then
    5. MessageBox.Show("nichts ist angewählt!")
    6. Return
    7. End If
    8. For Each indx In selectedIndicees
    9. Dim rwCat = DirectCast(DirectCast(TblCatEinrichtungBindingSource(indx), DataRowView).Row, DS.tblCatEinrichtungRow)
    10. MessageBox.Show(rwCat.Category)
    11. Dim childrows As Integer = rwCat.GettblEinrichtung_Rows.Count
    12. If childrows > 0 Then
    13. MessageBox.Show("Diese Kategorie wird noch bei " & childrows & " Datensätzen angewendet!")
    14. Else
    15. TblCatEinrichtungBindingSource.RemoveAt(indx)
    16. End If
    17. Next
    18. End If
    19. End Sub

    Bitte jetzt nicht erschrecken wg

    VB.NET-Quellcode

    1. Dim selectedIndicees = From rw In DgvTblCatEinrichtung.SelectedRows.Cast(Of DataGridViewRow)() Select rw.Index Order By Index Descending
    Das ist einfach eine Methode, die aus DgvTblCatEinrichtung die SelectedRows abruft, von denen die Indicees, und dann absteigend sortiert.
    Wenn du Linq nicht magst, schreib dir selbst eine kleine Methode, die das kann - die könnte etwa eine List(Of Integer) returnen.

    Der wichtige Punkt ist, dass ich nirgends DGV.Rows benötige.
    Weil ich hab ja die DGV.SelectedRows - an die muss ich mich halten.
    Und da brauch ich auch nicht If DgvTblCatEinrichtung.Rows(i).Selected = True zu prüfen - ich weiß ja, dass die SelectedRows selected sind.
    Und übrigens du brauchst niemals mit True zu vergleichen: Boolean, Vergleiche und bedingte Verzweigungen

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

    vielen dank für die ausführliche antwort.

    ich werde es entsprechend ändern.

    aber eine frage (für mich als anfänger wichtig): mein code, der mit sicherheit umständlicher ist, hat der fehler? ein bischen stolz wäre ich ja schon wenns vom prinzip her richtig ist... ;)
    Gruß Hannes
    naja - ist halt extrem krude.
    index ist ein Array, so groß wie alle Zeilen.
    Dann gehst du das DGV durch, und schreibst in index überall -1 rein, ausser wenn die Row selected ist - dann schreibst du den RowIndex nach index (könntest ebensogut auch 99 reinschreiben oder whatever).
    Somit hast du also eine eigene (sehr komisch strukturierte) .SelectedIndex-Auflistung erstellt, wohl weil die .SelectedRows-Auflistung des DGVs dir nicht gefällt ;)
    Und dann gehst du das index durch, und immer wenner nichtnegativ ist, holst du dir vom Index den Index, damit holst du die DGV-Row, und davon den Index. Mit letzterem Index holst du die DataRow:

    VB.NET-Quellcode

    1. Dim rwCat = DirectCast(DirectCast(TblCatEinrichtungBindingSource.Item(DgvTblCatEinrichtung.Rows(index(y)).Index), DataRowView).Row, DS.tblCatEinrichtungRow)


    Einfacher wäre, du würdest die DataRow gleich mit y holen, da steht nämlich auch nix anneres drin - also

    VB.NET-Quellcode

    1. Dim rwCat = DirectCast(DirectCast(TblCatEinrichtungBindingSource(y), DataRowView).Row, DS.tblCatEinrichtungRow)
    müsste auch gehen.

    Fehler, die zum Absturz führen, kann ich nicht erkennen, aber was da vorgeht ist so verschroben, dasses mir eher wie durch Herumprobieren entstanden aussieht.

    Eine Zielstrebige Vorgehensweise - auch ohne .SelectedRows-Auflistung - hätte eine List(Of Integer) angelegt, und in der ersten Schleife befüllt, und in der 2. Schleife rückwärts durchlaufend ausgewertet.
    das hat mir sehr weiter geholfen, vielen dank.


    ich habe nun folgendes problemchen: wenn in einer Zeile keine Bezeichnung eingetragen ist, möchte ich gerne (durch die übernahme vorhandener Datasets) die Felder der Spalten mit einem Standardwert belegen.

    Wenn ich nun prüfen will:

    Quellcode

    1. If IsDBNull(rwEin.Bezeichnung) Then
    2. MessageBox.Show("Keine Bezeichnung eingetragen! Wird jetzt zugewiesen!")
    3. rwEin.Bezeichnung = "manueller bezeichner"
    4. MessageBox.Show(rwEin.Bezeichnung)
    5. End If


    kommt trotzdem die fehlermeldung:

    Zusätzliche Informationen: Der Wert für Spalte Bezeichnung in Tabelle tblEinrichtung ist DBNull.




    Edit: Und noch eins häng ich gleich mit ran:

    Bei einer späteren Linq Abfrage über die Tabelle schmeists
    ​Auf gelöschte Zeileninformationen kann nicht über die Zeile zugegriffen werden.




    Ich habe dahre nach dem löschen DS.Acceptchanges angehängt.

    Ist das die korrekte Art?
    Wieso sind die removte Rows noch da? Damit ich sie wieder zurück holen kann?
    Gruß Hannes

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hans im glück“ ()

    Es heisst

    VB.NET-Quellcode

    1. if rwEin.IsBezeichnungNull() Then
    und ist eine generierte, typisierte Methode.
    Wo kommt das IsDBNull her - ist das nicht aus dem Deppen-Namespace? Visual Studio - Empfohlene Einstellungen



    die Removten Zeilen bleiben drin, damit die Änderungsverfolgung die Löschung auch an die DB übermittlen kann. Um mit Linq nicht auf eine gelöschte Zeile zu treten muss man den RowState der Datarow abfragen.

    Von AcceptChanges besser die Finger lassen - das löscht die Änderungsverfolgung (ja, und dann sind die gelöschten Zeilen auch aussem Dataset richtig weg.)
    Ausserdem, wenn du dich darauf stützen willst, darfst du das nie vergessen.

    Denkbar wäre auch, mit DatarowCollection.Remove/.RemoveAt zu removen - das lässt die Zeile ganz still verschwinden, als wäre sie nie da gewesen.