Einfügen in Liste vor oder nach der aktuellen Cursor Position

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

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

    Einfügen in Liste vor oder nach der aktuellen Cursor Position

    Hi,

    Ich zeige eine Liste von Lesezeichen in einer DatagridView an. Die Liste hat drei Spalten. Und sie hat keine Sortierreihenfolge.

    Nun würde ich gern in diese Liste neue Zeilen einfügen. Wenn keine Zeile ausgewählt ist, dann wird am Ende der Liste angefügt. Das ist unproblematisch.

    Wenn aber eine Zeile ausgewählt ist, dann möchte ich gern vor bzw. nach der ausgewählten Zeile die neue Zeile einfügen.

    Soweit ich das sehe, gibt es nur die Methode .Add zum Anfügen an das Ende der Liste ... Muss ich für mein Vorhaben also die ganze Liste entladen und dann neu aufbauen?

    Na, vielleicht geht das ja doch ein bissl eleganter.

    LG
    Peter

    Peter329 schrieb:

    Die Liste hat drei Spalten.
    Gib ihr eine vierte Spalte, die Du nicht anzeigst und in die Du Ranking-Werte packst. Häng Deine neuen Werte immer hinten dran und sortiere dann nach der Ranking-Spalte.
    Ansonsten gugst Du hier, da werden Zeilen eines DGV getauscht.
    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!
    ok ... ich habe jetzt eine list(of Bookmark) erstellt ... Bookmark ist eine von mir erstellte Klasse, welche die Komponenten des Lesezeichens (Pfad, Subdirectory und File) enthält.

    Die Liste lade ich in eine DataGridView.

    Mit dem nachfolgenden Coding kann ich ausgewählte Zeilen löschen und an anderer Stelle je nach Auswahl wieder einfügen.

    VB.NET-Quellcode

    1. Dim sb As New Bookmark 'saved bookmark
    2. Dim BookmarkList As New List(Of Bookmark)
    3. Private Sub cmdCut_Click(sender As System.Object, e As System.EventArgs) Handles cmdCut.Click
    4. 'Cut selected entry
    5. If dgvBookmarks.SelectedRows.Count = 0 Then Exit Sub
    6. Dim k As Integer = dgvBookmarks.SelectedRows(0).Index
    7. sb.BookmarkPath = dgvBookmarks.Item(0, k).Value.ToString
    8. sb.BookmarkSubdir = dgvBookmarks.Item(1, k).Value.ToString
    9. sb.BookmarkFile = dgvBookmarks.Item(2, k).Value.ToString
    10. BookmarkList.RemoveAt(k)
    11. 'reload data grid view and position selection
    12. LoadDgv()
    13. If dgvBookmarks.Rows.Count = 0 Then Exit Sub
    14. If k >= dgvBookmarks.Rows.Count Then k -= 1
    15. dgvBookmarks.Rows(k).Selected = True
    16. End Sub
    17. Private Sub cmdPaste_Click(sender As System.Object, e As System.EventArgs) Handles cmdPaste.Click
    18. 'Paste saved bookmark
    19. Dim k As Integer = dgvBookmarks.SelectedRows(0).Index
    20. BookmarkList.Insert(k, sb)
    21. 'reload data grid view and position selection
    22. LoadDgv()
    23. dgvBookmarks.Rows(k).Selected = True
    24. End Sub
    25. Private Sub LoadDgv()
    26. dgvBookmarks.Rows.Clear()
    27. For Each bm In BookmarkList
    28. dgvBookmarks.Rows.Add(bm.BookmarkPath, bm.BookmarkSubdir, bm.BookmarkFile, True)
    29. Next
    30. dgvBookmarks.ClearSelection()
    31. End Sub


    Was natürlich blöde ist ... ich muss die DGV jedesmal komplett löschen und wieder neu aufbauen.

    Kann man das nicht eleganter also etwa über DataBinding realisieren ?

    LG
    Peter

    Peter329 schrieb:

    DataBinding
    mit Deiner eigenen Sortierung, siehe die 4. Spalte.

    Peter329 schrieb:

    VB.NET-Quellcode

    1. Dim sb As New Bookmark
    geht vor die Hose, wenn Du nur eine einzige Instanz von erstellst.
    Instanziiere sb da, wo Du dessen Properties setzt (Sub cmdCut_Click())!
    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!

    RodFromGermany schrieb:

    geht vor die Hose, wenn Du nur eine einzige Instanz von erstellst.


    Ich darf nur eine Instanz erstellen ! sb ist doch die "SavedBookmark" ... in Cut merke ich mir den Inhalt der Bookmark und in Paste füge ich den wieder ein ! Mit anderen Worten sb muss prozedurübergreifend erhalten bleiben.

    RodFromGermany schrieb:

    mit Deiner eigenen Sortierung, siehe die 4. Spalte.


    Also ... ich füge meiner DGV eine unsichtbare Spalte hinzu, nennen wir sie Sequ as Integer

    Jetzt habe ich meinetwegen 10 Zeilen gespeichert und die Sequence Numbers 1 ... 10 vergeben. Wenn ich jetzt nach der 3. Zeile einfügen möchte, welche Sequence Number erhält dann die neu eingefügte Zeile? Na, vermutlich, muss ich Sequ als Decimal definieren und dann den Mittelwert bilden. Und natürlich muss ich das Einfügen VOR der ersten Zeile und das Anfügen NACH der letzten Zeile gesondert behandeln. Außerdem muss ich den Sort auf alle anderen Spalten deaktivieren, da sonst die Sache mit dem Mittelwert ausgehebelt wird ! Bei aller Wertsschätzung, aber das scheint mir eine schaurig schöne Lösung zu sein.

    Mhh ... so ganz happy bin ich mit der Lösung noch nicht ...

    Ich hatte einen typedDataset für die Bookmarks erstellt und den mit Databinding an die DataGridView gebunden. Aber blöderweise gibt es für eine DataSource nur die Methode .Add ... und .RemoveAt .... Die Methode .Insert(index, ...) fehlt, soweit ich das sehe. Vielleicht gibt es zu der verborgenen sequence column keine Alternative ... na, mal sehen, was ihr dazu meint ...

    LG
    Peter

    [edit]

    ErfinderDesRades schrieb:

    man könnte das übrigens durchaus auch in einem typisierten Dataset integrieren.
    Auch DataTable hat zur Not eine Insert-Funktion.


    oops ... genau das habe ich gesucht aber bisher nicht gefunden ! Das hier ist wohl zu schön, um wahr zu sein:

    VB.NET-Quellcode

    1. DataSet1.BookmarkList.InsertBookmarkListRow(5, ...)


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

    Peter329 schrieb:

    welche Sequence Number erhält dann die neu eingefügte Zeile?
    Diese Reihenfolge musst Du beim Einfügen / Anhängen unmittelbar vor dem Sortieren festlegen. Also 1 bis 5 der vorhandenen Daten, 6 bis 12 der einzufügenden Daten und 13 bis 17 der hinterzuschiebenden vorhandenen Daten.
    "SavedBookmark"
    OK, das kam aus Deinem Post nicht heraus.
    Wenn Du dessen Properties in sb überschreibst, werden sie in BookmarkList.Insert(k, sb) mit überschrieben, das ist dieselbe Instanz!
    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!

    RodFromGermany schrieb:

    Diese Reihenfolge musst Du beim Einfügen / Anhängen unmittelbar vor dem Sortieren festlegen. Also 1 bis 5 der vorhandenen Daten, 6 bis 12 der einzufügenden Daten und 13 bis 17 der hinterzuschiebenden vorhandenen Daten.


    Mhh ... das kann ich jetzt leider nicht so richtig nachvollziehen. Der Anwender wird in der BookmarkList mal die 3. Zeile löschen, nach der 5. Zeile einfügen ... dann wird am Ende eine neue Zeile angefügt ... dann wird diese Zeile gelöscht und vor der 1. Zeile eingefügt ... usw. usw .... Cut & Paste halt ... wie soll ich da die Reihenfolge der Zeilen vorher wissen ...

    RodFromGermany schrieb:

    OK, das kam aus Deinem Post nicht heraus.
    Wenn Du dessen Properties in sb überschreibst, werden sie in BookmarkList.Insert(k, sb) mit überschrieben, das ist dieselbe Instanz!


    VB.NET-Quellcode

    1. Dim sb As New Bookmark 'saved bookmark
    2. Dim BookmarkList As New List(Of Bookmark)


    sb und Bookmarklist sind doch zwei ganz verschiedene Instanzen von verschiedenen Klassen! Also bei mir wird nix überschrieben ... Oder meinst du, dass sb in beiden Anweisungen auf die gleiche Instanz verweist? Das ist doch gerade was ich erreichen möchte ! Ich will die gespeicherten Daten an anderer Stelle wieder einfügen.

    Mhh ... ich suche immer noch nach der Möglichkeit in meinen typisierten Dataset mit Insert(index, ...) einzufügen ...

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

    Peter329 schrieb:

    Also bei mir wird nix überschrieben
    Deine eine sb-Instanz wird an 2 Stellen aufbewahrt:

    VB.NET-Quellcode

    1. Dim sb As New Bookmark
    2. ' ...
    3. BookmarkList.Insert(k, sb)
    Wenn Du sb mehrfach in die BookmarkList einfügst, sind die Instanzen identisch und somit auch ihr Inhalt.
    Teste dies:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private myList As New List(Of Test)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Dim tt = New Test
    5. tt.Value = 1
    6. myList.Add(tt)
    7. tt.Value = 2
    8. myList.Add(tt)
    9. tt.Value = 3
    10. myList.Add(tt)
    11. tt.Value = 4
    12. myList.Add(tt)
    13. End Sub
    14. End Class
    15. Public Class Test
    16. Public Property Value As Integer
    17. End Class


    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!
    Huch ! Das verstehe ich jetzt nicht!

    Ich hab dein Beispiel nachvollzogen ... tatsächlich läuft das so, wie gezeigt. Aber das WARUM verstehe ich noch nicht. Wieso wirkt sich beim .Add die Änderung von tt.Value auf ALLE Zeilen der Liste aus?

    Irgendwie fehlt mir da etwas im grundlegenden Verständnis !

    Peter329 schrieb:

    Aber das WARUM verstehe ich noch nicht.
    Die Instanz ist genau ein Mal mit New erzeugt worden. Danach wird die Property Value n Mal überschrieben. Das letzte Schreiben ist gültig, die vorherigen Werte werden halt überschrieben.
    Damit das so funktioniert wie Du denkst, dass es funktionieren soll, musst Du jedes Mal eine neue Instanz erstellen:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private myList As New List(Of Test)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Dim tt = New Test
    5. tt.Value = 1
    6. myList.Add(tt)
    7. tt = New Test
    8. tt.Value = 2
    9. myList.Add(tt)
    10. tt = New Test
    11. tt.Value = 3
    12. myList.Add(tt)
    13. tt = New Test
    14. tt.Value = 4
    15. myList.Add(tt)
    16. End Sub
    17. End Class
    18. Public Class Test
    19. Public Property Value As Integer
    20. End Class
    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!

    Peter329 schrieb:

    Mhh ... ich suche immer noch nach der Möglichkeit in meinen typisierten Dataset mit Insert(index, ...) einzufügen ...
    Hast du mal im ObjectBrowser nachgeguckt?
    Auch in den Basisklassen deiner DataTables?
    Welchen Typ hat die DataTable.Rows-Property?
    Und wenn man da mal hin-browst zu dem Typ, da findet man was mit Insert - was garnet weiter schwierig aussieht.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private myList As New List(Of Test)
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Dim tt = New Test
    5. tt.Value = 1
    6. myList.Add(tt)
    7. tt.Value = 2
    8. myList.Add(tt)
    9. tt.Value = 3
    10. myList.Add(tt)
    11. tt.Value = 4
    12. myList.Add(tt)
    13. End Sub
    14. End Class
    15. Public Class Test
    16. Public Property Value As Integer
    17. End Class


    In Zeile 2 wird eine neue Instanz von myList als List(of Test) erstellt. Diese Liste ist zunächst mal leer.
    In Zeile 4 wird eine neue Instanz von tt erstellt. Die einzige Property ist das Integer Feld: Value
    In Zeile 5 wird die Property Value mit dem Wert 1 belegt
    In Zeile 6 wird die Instanz von tt nun als erste row der Instanz myList hinzugefügt. Value hat den Wert 1.

    Bis dahin ist ja alles klar.

    In Zeile 7 wird die Property der Instanz von tt mit dem Wert 2 belegt.
    In Zeile 8 wird der Instanz von myList eine zweite Zeile hinzugefügt. Value hat den Wert 2.

    WIESO, um alles in der Welt, erhält die Property der ERSTEN Zeile der Instanz von myList nun auch den Value 2 ????

    Hier habe ich offensichtlich eine grundlegende Verständnislücke! Die Übergabe von Variablen vom Typ Integer, String etc. muss offensichtlich ganz anders verlaufen als bei "komplexen" Objekten mit selbst definierten Properties ...

    @EDR
    Ich hab deinen Beitrag gelesen ... aber eins nach dem anderen ... jetzt will ich erst mal die Sache mit der Instanzierung und den Properties verstehen.

    LG
    Peter

    Peter329 schrieb:

    den Value 2 ?
    Weil das dieselbe Instanz ist.
    Sie wird sowohl als Vatiable tt in der Schleife als auch in allen Items von myList gebunkert.
    Genau das ist der Unterschied zwischen ValueType und ReferenceType.
    Wenn Du aus der Klasse Test (ReferenceType) eine Struktur machst (ValueType), geht es so wie Du glaubst.
    Deswegen musst Du da höllisch aufpassen.
    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!
    Ok ... jetzt hab ich (glaube ich wenigstens) das richtige Stichwort. Value Types und Reference Types.

    Die Anweisung

    VB.NET-Quellcode

    1. myList.Add(tt)


    setzt einen VERWEIS auf die Instanz von tt innerhalb der Instanz von

    Quellcode

    1. myList


    Und wenn ich nun die Quelle des Verweises ändere, dann wirkt sich das auf ALLE Objekte aus, die darauf verweisen ...

    Ich hoffe, dass ich das jetzt richtig verstanden habe, wie der Hase läuft.

    Jetzt versuche ich mal meine Routine dahingehend zu modifizieren !

    Ich bin dir für deine Ratschläge und deine unendliche Geduld wirklich sehr dankbar ! Mal sehen, wie weit ich damit jetzt komme ... :)

    LG
    Peter

    Peter329 schrieb:

    Ich hoffe, dass ich das jetzt richtig verstanden habe, wie der Hase läuft.
    Ja, so isses.
    Wenn Du C++ kannst, lässt sich das ganze mit Pointern wesentlich einfacher erklären, obwohl es .NDET-intern ziemlich genau dasselbe ist, nur unmanaged.
    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!
    okie dokie ... das mit dem Pointer verstehe ich ... und ich habe jetzt die Sache auch ans Laufen gebracht! Da hab ich jetzt etwas Wesentlichens gelernt: man muss in diesen Fällen die Datenquelle neu instanzieren, um solche Effekte zu vermeiden. Da hätte ich lange suchen können ... Ganz herzlichen Dank also für deine Schulung in VB Basics ... schade, dass ich dir kein Bier ausgeben kann! :)

    Jetzt aber zu EDR:

    Ich habe meinen typed Dataset wieder reaktiviert. Das Laden der DGV und das Löschen (und Zwischenspeichern) eines ausgewählten Eintrags über die DataSource klappt (wie zuvor) auch ohne Probleme.

    Jetzt versuche ich das gezielte Einfügen in die DataSource.

    Naiv wie ich nun mal bin, hab ich das (nach eingehender Konsultation des ObjectExplorers und der Intellisense Vorschläge) wie folgt versucht:

    VB.NET-Quellcode

    1. DataSet1.BookmarkList.Rows.InsertAt(k, sb.BookmarkPath, sb.BookmarkSubdir, sb.BookmarkFile, True)


    Das klappt aber nicht, weil die Syntax des .InsertAt wohl vom .Add abweicht ... Die Kiste verlangt eine DataRow als Parameter ... und das kriege ich irgendwie nicht hin.

    Ich hoffe, dass ich freundliche und sachdienliche Hinweise erhalte ... ohne, dass ich wieder auf den ObjectExplorer oder Intellisense verwiesen werde. :)

    Na, man kann in VB eben alles verlieren ... nur eins sollte man nicht verlieren: seinen Humor ... hehehe :)

    LG
    Peter
    welchen Datentyp verlangt .InsertAt(index, row) als 2. Parameter?

    Und kann ich dir auch Unterricht geben in VB-Basics (werden deinen Humor schon kleinkriegen :evil: ) : Einer Methode mit 2 Parametern kann man keine 5 Parameter übergeben.

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