2 Zeilen im Datatabel/Datagridview vertauschen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 15 Antworten in diesem Thema. Der letzte Beitrag () ist von icekuhn.

    2 Zeilen im Datatabel/Datagridview vertauschen

    Hallo zusammen,

    ich habe ein Datagridview (KundenlisteDataGridView) welches mittels DataSource=KundenlisteBindingSource am DataSet 1 gebunden ist.

    Das Dataset erhält seine Daten aus einer XML Datei.

    Ich möchte jetzt im Datagridview bzw. im Datatabel 2 Zeilen miteinander vertauschen.

    Meine Idee war jetzt einfach die Werte der ID Spalte zu tauschen, jedoch meckert er verständlicher Weise dann, dass die Werte nur einmal vorkommen dürfen.
    Deshalb lese ich erst die Werte der beiden Zeilen aus, lösche sie dann und befülle das Tabel danach neu.

    Zum Schluss lass ich dann nach der Spalte „ID“ sortieren.

    Soweit funktioniert auch alles, jedoch muss es doch auch noch elegantere Lösungen für sowas geben, oder? ?(


    VB.NET-Quellcode

    1. Imports DGV_Zeilen_verschieben.DataSet1
    2. Dim Zeile1, Zeile2 As Integer
    3. Dim Name1, Name2 As String
    4. Dim Adresse1, Adresse2 As String


    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. For i As Integer = 1 To 5
    3. KundenlisteBindingSource.AddNew()
    4. Dim kr = KundenlisteBindingSource.At(Of KundenlisteRow)()
    5. kr.Name = "Name " & i
    6. kr.Adresse = "Adresse " & i
    7. KundenlisteBindingSource.EndEdit()
    8. Next
    9. End Sub


    VB.NET-Quellcode

    1. Private Sub bt_Wert1_Click(sender As Object, e As EventArgs) Handles bt_Wert1.Click
    2. Dim rwZeile1 = KundenlisteBindingSource.At(Of KundenlisteRow)()
    3. Zeile1 = rwZeile1.Id
    4. Name1 = rwZeile1.Name
    5. Adresse1 = rwZeile1.Adresse
    6. rwZeile1.Delete()
    7. End Sub
    8. Private Sub bt_Wert2_Click(sender As Object, e As EventArgs) Handles bt_Wert2.Click
    9. Dim rwZeile2 = KundenlisteBindingSource.At(Of KundenlisteRow)()
    10. Zeile2 = rwZeile2.Id
    11. Name2 = rwZeile2.Name
    12. Adresse2 = rwZeile2.Adresse
    13. rwZeile2.Delete()
    14. End Sub


    VB.NET-Quellcode

    1. Private Sub bt_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Tauschen.Click
    2. KundenlisteBindingSource.AddNew()
    3. Dim NeueZeile = KundenlisteBindingSource.At(Of KundenlisteRow)()
    4. NeueZeile.Id = Zeile2
    5. NeueZeile.Name = Name1
    6. NeueZeile.Adresse = Adresse1
    7. KundenlisteBindingSource.EndEdit()
    8. KundenlisteBindingSource.AddNew()
    9. Dim NeueZeile2 = KundenlisteBindingSource.At(Of KundenlisteRow)()
    10. NeueZeile2.Id = Zeile1
    11. NeueZeile2.Name = Name2
    12. NeueZeile2.Adresse = Adresse2
    13. KundenlisteBindingSource.EndEdit()
    14. KundenlisteDataGridView.Refresh()
    15. KundenlisteBindingSource.Sort = "Id DESC"
    16. End Sub
    Man soll die ID's unberührt lassen...
    Mach's umgekehrt - merke dir die Inhalte der einen Zeile und überschreibe die Werte der einen Zeile von der anderen Zeile. Danach überschreibst du die Werte der anderen Zeile mit den gemerkten Werten der einen Zeile...
    Danke für den Tipp,

    ich habe den Code jetzt soweit angepasst.
    Dadurch spar ich mir das löschen und neu sortieren ;)

    VB.NET-Quellcode

    1. Private Sub bt_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Tauschen.Click
    2. 'Suche Zeile zu Wert 1 und befülle mit Wert2
    3. For i = 0 To Me.KundenlisteBindingSource.Count - 1
    4. Dim person = DirectCast(DirectCast(KundenlisteBindingSource(i), DataRowView).Row, KundenlisteRow)
    5. If person.Id Like Zeile1 Then
    6. KundenlisteBindingSource.Position = i
    7. person.Name = Name2
    8. person.Adresse = Adresse2
    9. End If
    10. Next
    11. 'Suche Zeile zu Wert 2 und befülle mit Wert1
    12. For i = 0 To Me.KundenlisteBindingSource.Count - 1
    13. Dim person = DirectCast(DirectCast(KundenlisteBindingSource(i), DataRowView).Row, KundenlisteRow)
    14. If person.Id Like Zeile2 Then
    15. KundenlisteBindingSource.Position = i
    16. person.Name = Name1
    17. person.Adresse = Adresse1
    18. End If
    19. Next
    20. End Sub
    @darkman203: also was da gemacht wird ist abenteuerlich:
    Da tauschen 2 Kunden ihre Namen. Sowas kann man nicht bringen.
    Das ist wie wenn ich den Namen darkman203 annehme, und du den Namen ErfinderDesRades. Wir bleiben dennoch dieselben Identitäten, und das Verwirrspiel wird nur Verwirrung schaffen.

    Normalerweise sortiert man Datensätze, und nur in seltenen Spezialfällen ist die Reihenfolge, wie die Datensätze in der DataTable angeordnet sind, von Belang - im Grunde liegt sogar ein Design-Fehler vor, wenn solch tatsächlich nötig sein sollte, auf jeden Fall aber ein Hack.
    Es ist übrigens möglich - aber wie gesagt: ein Hack:

    VB.NET-Quellcode

    1. Private Sub swapRows(indx0 As Integer, indx1 As Integer, tb As DataTable)
    2. If indx0 >= indx1 Then Throw New ArgumentException("indx0 muss kleiner sein als indx1!")
    3. Dim enforced = tb.DataSet.EnforceConstraints
    4. If enforced Then tb.DataSet.EnforceConstraints = False
    5. Dim rw0 = tb.NewRow, rw1 = tb.NewRow
    6. rw0.ItemArray = tb(indx0).ItemArray
    7. rw1.ItemArray = tb(indx1).ItemArray
    8. tb.Rows.RemoveAt(indx1)
    9. tb.Rows.RemoveAt(indx0)
    10. tb.Rows.InsertAt(rw1, indx0)
    11. tb.Rows.InsertAt(rw0, indx1)
    12. If enforced Then tb.DataSet.EnforceConstraints = True
    13. End Sub
    Das habe ich getestet mit einer Tabelle ohne Primärschlüssel, und ohne Beziehungen zu anderen Tabellen.
    Gut möglich, dass sich in "richtigen" Szenarien Probleme ergeben.
    Hallo ErfinderDesRades,das war nur eine ausgegliederte Musteranwendung.
    (Das Beispiel war wohl nicht so günstig gewählt.)

    Im konkreten Fall geht es darum das einmalig Schecklisten im Programm erstellt werden können und diese dann zum Kunden (1 zu n Beziehung) gespeichert werden.
    Jetzt kann es aber vorkommen, dass man sich eine Scheckliste mit sagen wir 60 Fragen erstellt hat und im Nachgang feststellt, dass eine weitere Frage die Thematisch sagen wir mal zwischen Frage 30 und 31 passen würde erstellen möchte.
    Oder aber eine Frage Thematisch gesehen lieber an einer anderen Stelle platzieren will.
    Deshalb habe ich nach einer Möglichkeit gesucht die Zeilen zu tauschen.

    Hoffe ich konnte die Problematik verständlich rüber bringen.

    Habe den Code jetzt angepasst.

    VB.NET-Quellcode

    1. Private Sub bt_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Tauschen.Click
    2. Dim Position1, Position2 As Integer
    3. 'Suche Zeile zu Wert 1 und befülle mit Wert2
    4. Position1 = KundenlisteBindingSource.FindX("Id", Zeile1)
    5. Dim person1 = DirectCast(DirectCast(KundenlisteBindingSource(Position1), DataRowView).Row, KundenlisteRow)
    6. person1.Name = Name2
    7. person1.Adresse = Adresse2
    8. 'Suche Zeile zu Wert 2 und befülle mit Wert1
    9. Position2 = KundenlisteBindingSource.FindX("Id", Zeile2)
    10. Dim person2 = DirectCast(DirectCast(KundenlisteBindingSource(Position2), DataRowView).Row, KundenlisteRow)
    11. person2.Name = Name1
    12. person2.Adresse = Adresse1
    13. End Sub


    Mfg
    darkman203
    (3 Fragen/Themen - wäre nett, du würdest auf jedes bisserl eingehen)


    Und das (der jetzige Code) funktioniert nun?



    annere Frage: BindingSource.FindX() - ist das eine meiner Methoden?
    Weil in dem HelpersProjekt ist auch die BindingSource.At(Of KundenlisteRow)(pos) Methode, mit der man sich diese hässlichen doppelten Casts etwas aus den Augen schafft.



    ...dass eine weitere Frage die Thematisch sagen wir mal zwischen Frage 30 und 31 passen würde erstellen möchte.
    Oder aber eine Frage Thematisch gesehen lieber an einer anderen Stelle platzieren will.
    Das sind aber doch keine Tausch-Vorgänge.
    Sondern a) einfügen, b) moven

    Ein Tausch hingegen ist ein Doppel-Move: das eine Item hin, das annere in Gegen-Richtung.
    Ja das sind deine Methoden/Erweiterungen :thumbup:

    Habe Sie erst kürzlich entdeckt und bin schon jetzt ein riesen Fan davon.
    Danke für den Tipp:

    VB.NET-Quellcode

    1. ​BindingingSource.At
    kannte ich noch nicht.

    Und ja; es funktioniert tadellos.
    Ich muss das jetzt noch alles schön verpacken und dann beim anderen Projekt implementieren.

    Aber ist es aus deiner Sichtweise ok, wenn man die Positionen von Zeilen einer Checkliste verschieben will, oder würdest du das gänzlich anders lösen?


    VB.NET-Quellcode

    1. Private Sub bt_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Tauschen.Click
    2. Dim Position1, Position2 As Integer
    3. 'Suche Zeile zu Wert 1 und befülle mit Wert2
    4. Position1 = KundenlisteBindingSource.FindX("Id", Zeile1)
    5. Dim person1 = KundenlisteBindingSource.At(Of KundenlisteRow)(Position1)
    6. person1.Name = Name2
    7. person1.Adresse = Adresse2
    8. 'Suche Zeile zu Wert 2 und befülle mit Wert1
    9. Position2 = KundenlisteBindingSource.FindX("Id", Zeile2)
    10. Dim person2 = KundenlisteBindingSource.At(Of KundenlisteRow)(Position2)
    11. person2.Name = Name1
    12. person2.Adresse = Adresse1
    13. End Sub
    vor allem stört mich, dass du diese doch etwas hanebüchene Operation nicht ordentlich in eine Methode kapselst.

    Sieh dir mein Beispiel an - da ist alles klar: Alle für die Operation nötigen Informationen werden als Argumente hineingereicht - sind ja gar net so viele.

    So versteht man meinen Code ganz leicht, und muss sich nicht fragen, wo denn nun so eigentümliche Sachen wie Zeile1, Zeile2, Name2 und Addresse2 herkommen, welchen Datentyp die wohl haben, und was die bedeuten sollen.

    Mangels dieses Durchblicks kann ich nur den Aufbau bemängeln, aber vonne Funktion her nicht, weil die verstehe ich garnet.
    Und da dein Problem was mit Checklisten zu tun hat, dein Code aber nichts von Checklisten zeigt, sondern nur von Kunden - also wenns in deinem Sinne funktioniert - fein!
    Denke so sollte es jetzt ok sein?


    VB.NET-Quellcode

    1. 'Erste Zeile im DGV auswählen
    2. Private Sub bt_Wert1_Click(sender As Object, e As EventArgs) Handles bt_Wert1.Click
    3. Dim _Zeile1 = SchecklisteBindingSource.At(Of SchecklisteRow)()
    4. Id1 = _Zeile1.Id
    5. Frage1 = _Zeile1.Frage
    6. InfoText1 = _Zeile1.InfoText
    7. Status1 = _Zeile1.Status
    8. End Sub
    9. 'Zweite Zeile im DGV auswählen
    10. Private Sub bt_Wert2_Click(sender As Object, e As EventArgs) Handles bt_Wert2.Click
    11. Dim _Zeile2 = SchecklisteBindingSource.At(Of SchecklisteRow)()
    12. Id2 = _Zeile2.Id
    13. Frage2 = _Zeile2.Frage
    14. Infotext2 = _Zeile2.InfoText
    15. status2 = _Zeile2.Status
    16. End Sub


    VB.NET-Quellcode

    1. 'Den Inhalt der Ersten Zeile in die Zeite und umgekehrt schreiben.
    2. Private Sub bt_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Tauschen.Click
    3. 'Suche Zeile1 und befülle mit Daten vo Zeile2
    4. ZeilenTauschen(SchecklisteBindingSource, "Id", Id1, Frage2, Infotext2, Status2)
    5. 'Suche Zeile2 und befülle mit Daten von Zeile1
    6. ZeilenTauschen(SchecklisteBindingSource, "Id", Id2, Frage1, InfoText1, Status1)
    7. End Sub


    VB.NET-Quellcode

    1. ''' <summary>
    2. '''2 Zeilen Tauschen
    3. ''' </summary>
    4. ''' <param name="_Bindingsource">Die BindingSource</param>
    5. ''' <param name="_Spalte">Der Spaltenname, wo nach gesucht werden soll</param>
    6. ''' <param name="_Id">Der Wert der _Spalte wonach gesucht werden soll.</param>
    7. ''' <param name="_Frage">Die Frage die in der Scheckliste steht.</param>
    8. ''' <param name="_InfoText">Der Infotext der in der Scheckliste steht.</param>
    9. ''' <param name="_Status">Der Stauts der in der Scheckliste steht.</param>
    10. ''' <returns></returns>
    11. ''' <remarks></remarks>
    12. Public Function ZeilenTauschen(ByVal _Bindingsource As BindingSource, ByVal _Spalte As String, ByVal _Id As Integer, ByVal _Frage As String, ByVal _InfoText As String, ByVal _Status As Boolean)
    13. Dim Position = _Bindingsource.FindX(_Spalte, _Id)
    14. Dim Wert = _Bindingsource.At(Of SchecklisteRow)(Position)
    15. Wert.Frage = _Frage
    16. Wert.InfoText = _InfoText
    17. Wert.Status = _Status
    18. _Bindingsource.EndEdit()
    19. Return Nothing
    20. End Function



    MFG
    darkman203
    Die Methode heißt zwar ZeilenTauschen, aber sie macht was ganz anderes: Sie füllt einfach ein paar Werte in eine SchecklisteRow.

    Das könnte man auch wesentlich einfacher haben.

    Ich würde auch keine Tausch-Funktionalität coden, sondern eine Move-Funktionalität.
    Dazu wählt man einen Datensatz an, und klickst ein "Select"-Menü, was nix macht, als sich die derzeitig gewählte Position zu merken.
    Dann geht man auf die Ziel-Position und klickst ein "Paste"-Menü. Hierbei wird die DataRow von der gemerkten auf die aktuelle Position verschoben.



    Edit: Ach, das wichtigste glatt vergessen: Visual Studio - Empfohlene Einstellungen
    Must-Read, Must-Do - no Excuses!

    Mit den VorEinstellungen, in denen VB.Net ausgeliefert wird, ist es keine ernstzunehmende objektorientierte Sprache, und es ist im Grunde garnicht möglich, damit vernünftig programmieren zu lernen.

    Im Gegenteil: Man lernt damit zwangsläufig unvernünftig zu programmieren, und das ist schlimmer als wenn mans garnet lernte.

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

    Guten Morgen ErfinderDesRades,

    hmmm sehe schon habe mal wieder zu kompliziert gedacht.....
    Ich progge übrigens nur für mich alleine um mir meine tägliche Arbeit ein wenig zu vereinfachen...leider muss ich immer wieder feststellen das mir da noch ne Menge Wissen fehlt.

    Wie dem auch sei, hier meine Überarbeitete Version.


    VB.NET-Quellcode

    1. #Region "Audit Fragen verschieben rauf, runter."
    2. Dim _Startzeile As ds_Audit_Katalog.Audit_FragenRow
    3. Dim _Start_Id As Integer = Nothing
    4. Dim Tauschen As Boolean = False
    5. Private Sub bt_Einstellungen_Audtit_Frage_runter_Click(sender As Object, e As EventArgs) Handles bt_Einstellungen_Audtit_Frage_runter.Click
    6. 'Beim ersten click Werte und Position der Startzeile ermitteln
    7. If Tauschen = False Then
    8. _Startzeile = FKAuditTypenAuditFragenBindingSource.At(Of ds_Audit_Katalog.Audit_FragenRow)()
    9. _Start_Id = FKAuditTypenAuditFragenBindingSource.Position
    10. End If
    11. 'In der Liste einen runter springen
    12. FKAuditTypenAuditFragenBindingSource.Position += 1
    13. 'Tauschen auf True setzen, damit die Startzeile nicht überschrieben wird
    14. Tauschen = True
    15. End Sub
    16. Private Sub bt_Einstellungen_Audit_Frage_Rauf_Click(sender As Object, e As EventArgs) Handles bt_Einstellungen_Audit_Frage_Rauf.Click
    17. 'Beim ersten click Werte und Position der Startzeile ermitteln
    18. If Tauschen = False Then
    19. _Startzeile = FKAuditTypenAuditFragenBindingSource.At(Of ds_Audit_Katalog.Audit_FragenRow)()
    20. _Start_Id = FKAuditTypenAuditFragenBindingSource.Position
    21. End If
    22. 'In der Liste einen rauf springen
    23. FKAuditTypenAuditFragenBindingSource.Position -= 1
    24. 'Tauschen auf True setzen, damit die Startzeile nicht überschrieben wird
    25. Tauschen = True
    26. End Sub
    27. Private Sub bt_Einstellungen_Audit_Fragen_Tauschen_Click(sender As Object, e As EventArgs) Handles bt_Einstellungen_Audit_Fragen_Tauschen.Click
    28. 'Werte der Aktuellen Zeile Speichern
    29. Dim AktuelleZeile = FKAuditTypenAuditFragenBindingSource.At(Of ds_Audit_Katalog.Audit_FragenRow)()
    30. Dim Frage As String = AktuelleZeile.Frage
    31. Dim ToDo As String = AktuelleZeile.ToDo
    32. 'Werte der Aktuellen Zeile mit den Werten der Startzeile überschreiben
    33. AktuelleZeile.Frage = _Startzeile.Frage
    34. AktuelleZeile.ToDo = _Startzeile.ToDo
    35. FKAuditTypenAuditFragenBindingSource.EndEdit()
    36. 'Werte der Startzeile mit der zuletzt ausgewählten Zeile überschreiben
    37. FKAuditTypenAuditFragenBindingSource.Position = _Start_Id
    38. Dim Zeile = FKAuditTypenAuditFragenBindingSource.At(Of ds_Audit_Katalog.Audit_FragenRow)()
    39. Zeile.Frage = Frage
    40. Zeile.ToDo = ToDo
    41. FKAuditTypenAuditFragenBindingSource.EndEdit()
    42. Tauschen = False
    43. End Sub
    44. #End Region


    PS: Ich würde auch gerne mal ein Bild anhängen, komme jedoch mit der Funktion nicht klar. (URL?)
    @TE: Willst du noch verbesserungs-Hinweise?
    du brauchst nicht 3 Klassen-Variablen, sondern es reicht eine Variable _TauschZeilPosition. Ist sie negativ, bedeutet das, dass nicht getauscht wird, ist sie positiv, soll getauscht werden, und die Tauschzeile kannst du dann ja nochmal abrufen, wenns soweit ist.

    Prinzip: Je weniger klassenvariablen in einer Klasse herumfahren, desto besser.