DGV mit DataTable für ein String Array, Strings per Doppelklick bearbeite,

  • VB.NET
  • .NET 4.0

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

    DGV mit DataTable für ein String Array, Strings per Doppelklick bearbeite,

    Moin Leute.
    Ich habe einen Dialog, der ein DataGridView enthält. In diesem sollen Strings editiert werden, die Strings sind in einer DataTable an das DGV gebunden.
    Nun kann es vorkommen, dass dort sehr lange Strings editiert werden sollen, dazu rufe ich per Doppelklick auf die Zelle einen Dialog mit einer Multiline-Textbox auf.
    Ist ein String vorhanden, ist alles in Ordnung.
    Doppelklicke ich auf die letzte Zeile, werden zwei zusätzliche leere Zeilen angehängt:
    =>
    Ich hab mal ein rudimentäres Projekt (Form mit DataGridView) gemacht, das den Effekt reproduziert. Statt des Dialogs werden einfach die Strings editiert.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Table As DataTable
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Me.Table = New DataTable("Messages")
    5. Me.Table.Columns.Add("Message", GetType(String))
    6. Me.DataGridView1.DataSource = Table
    7. End Sub
    8. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    9. Dim index = e.RowIndex
    10. Dim msg = String.Empty
    11. If index < Me.Table.Rows.Count Then
    12. ' Klick auf eine vorhandene Zeile
    13. msg = Me.Table.Rows(index)(0).ToString()
    14. End If
    15. If index < Me.Table.Rows.Count Then
    16. ' Klick auf eine vorhandene Zeile
    17. Me.Table.Rows(index)(0) = msg & " edit" ' Kennung für editiert
    18. Else
    19. ' Klick auf die letzte Zeile
    20. msg = "neue Zeile"
    21. Dim row = Me.Table.NewRow()
    22. row(0) = msg
    23. Me.Table.Rows.Add(row)
    24. End If
    25. End Sub
    26. End Class

    Frage:
    Wie muss ich die zu editierende Zeile behandeln, um das "normale" DGV+DataTable-Verhalten einer befüllten Zeile zu realisieren?
    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!
    Wenn ich das Problem richtig verstanden habe, liegt es daran das die letzte Zeile zum hinzufügen einer neuen leeren Zeile da ist. Diese kann man in den Eigenschaften des DGV abschalten. IsEditable oder ähnlich müsste es heißen. Sorry das ich keine genaue Angabe machen kann, ich sitze gerade nicht am Laptop.

    Edit: AllowUserToAddRows heißt die Eigenschaft
    Rechtschreibfehler betonen den künstlerischen Charakter des Autors.
    Ein dirty workaround à la

    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    2. If e.RowIndex < Me.Table.Rows.Count Then Return
    3. Table.Rows.Add("neue Zeile")
    4. DataGridView1.Rows.RemoveAt(DataGridView1.Rows.Count - 2)
    5. DataGridView1.Rows(DataGridView1.Rows.Count - 2).Selected = True
    6. End Sub
    ist sicherlich nicht Dein Ziel …

    ##########

    Aber wenn Dein Ziel ist, die angeklickte Zelle zu bearbeiten und sei es die letzte, dann:

    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    2. DataGridView1.BeginEdit(True)
    3. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.

    VB.NET-Quellcode

    1. Imports System.Windows.Forms
    2. Imports System.Diagnostics
    3. Public Class frmForm1
    4. Private WithEvents Table As DataTable
    5. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    6. Me.Table = New DataTable("Messages")
    7. Me.Table.Columns.Add("Message", GetType(String))
    8. Me.DataGridView1.DataSource = Table
    9. End Sub
    10. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    11. Dim msg = DirectCast(Table.DefaultView(e.RowIndex), DataRowView)(0).ToString
    12. Debug.WriteLine($"-{msg}-") ' Ausgabe der gedoppelklickten
    13. End Sub
    14. Private Sub Table_TableNewRow(sender As Object, e As DataTableNewRowEventArgs) Handles Table.TableNewRow
    15. e.Row(0) = Date.Now.ToString("hh:mm:ss") 'Defaultwert
    16. End Sub
    17. End Class


    Allerdings ist das nur quicknDirty. Sobald einer auf den Spaltenkopf klickt wird umsortiert, und die Indizierung stimmt nimmeh.
    Dann fängste an, codeseitig die DataTable und das DGV auszubauen, und ist bald so umfangreich, dassde doch besser ein typisiertes Dataset genommen hättest.

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

    Danke für die Meldungen.
    Vier Möglichkeiten sind gewollt:
    Editieren einer vorhandenen Zeile mit F2 und Doppelklick,
    Editieren einer neuen Zeile mit F2 und Doppelklick.
    Ich hab jetzt noch ein wenig rumgespielt, da fiel mir auf, dass nicht am DGV eine weitere leere Zeile anhängt wurden, sondern dass an der DataTable eine leere Zeile erschien.
    Das habe ich jetzt so gelöst, dass ich während der "illegalen" Zeit .AllowUserToAddRows = False setze und nach allem Editieren wieder zurück auf True.
    Nun ist das Verhalten wie gewünscht.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Table As DataTable
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Me.Table = New DataTable("Messages")
    5. Me.Table.Columns.Add("Message", GetType(String))
    6. Me.DataGridView1.DataSource = Table
    7. End Sub
    8. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    9. Dim index = e.RowIndex
    10. Dim msg = String.Empty
    11. If index < Me.Table.Rows.Count Then
    12. ' Klick auf eine vorhandene Zeile
    13. msg = Me.Table.Rows(index)(0).ToString()
    14. End If
    15. If index < Me.Table.Rows.Count Then
    16. ' Klick auf eine vorhandene Zeile
    17. Me.Table.Rows(index)(0) = msg & " edit" ' Kennung für editiert
    18. Else
    19. ' Klick auf die letzte Zeile
    20. msg = "neue Zeile"
    21. Dim row = Me.Table.NewRow()
    22. row(0) = msg
    23. Me.Table.Rows.Add(row)
    24. DataGridView1.AllowUserToAddRows = False ' <<< Der hier
    25. End If
    26. End Sub
    27. Private Sub DataGridView1_CellEndEdit(...)
    28. DataGridView1.AllowUserToAddRows = True ' <<< Und der hier
    29. End Sub
    30. 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!

    RodFromGermany schrieb:

    VB.NET-Quellcode

    1. Dim row = Me.Table.NewRow()
    ist ein Holzweg, der zu überflüssigen Zeilen führt.

    Beim Click auf die ZufügeZeile wird bereits ein Table.NewRow ausgeführt - diese Row ist aber erstmal detached, also noch nicht Element der Table.
    Aber sie ist Element des DataViews (Table.DefaultView) - was im Hintergrund von Databinding diese Dinge verwaltet.

    wie's ohne geht Siehe mein CodeSample.
    @ErfinderDesRades Dein Weg funktioniert so allerdings auch nicht, denn das Event TableNewRow kommt vor dem Event CellDoubleClick.
    Möglicherweise spielt auch eine Rolle, dass ich im Event CellDoubleClick einen Dialog zum Editieren der Message aufrufe.
    Wäre also die Frage:
    Was muss ich zwischen .BeginEdit(false) und .EndEdit() aufrufen, damit das Editieren der neuen Zelle ordentlich funktioniert?
    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!
    Ich weiss grad nicht, worauf du dich beziehst - mit .BeginEdit habich ja nix vorgeschlagen.
    Und auch in deim Code kommt das nicht vor, und auch nix mit editieren.
    Insbes. "Editieren" ist nicht eindeutig: Man könnte den aktuellen Datensatz editieren wollen, oder aber auch nur die aktuelle DGV-Cell.
    Vielleicht nochmal aussagekräftigeren Sample-Code?

    hierma soweit das cell-edit mit einem Dialog (getestet):

    VB.NET-Quellcode

    1. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    2. Dim msg = DirectCast(BindingSource1(e.RowIndex), DataRowView)(0).ToString
    3. Dim newVal = VB6.InputBox("edit cell", "edit cell-Title", msg)
    4. DataGridView1(e.ColumnIndex, e.RowIndex).Value = newVal
    5. End Sub

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

    ErfinderDesRades schrieb:

    worauf du dich beziehst
    die erste Zeile von Post #7, Code ist immer noch der von Post #5, allerdings wird da zwischen Zeile 14 und 15 ein Dialog aufgerufen, der den String zurückgibt.
    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!
    Hä?
    ich frage dich, worauf post#7 sich bezieht, udn du antwortest mit einer Zeile aus demselben post?

    Und in post#5 kommt wie gesagt ".BeginEdit" nicht vor.

    Ebenfalls wie gesagt halte ich den post#5-Code für einen Holzweg.
    Insbes. zeile#25 ist mir unverständlich - da wird DGV.AllowAddRows negiert, nachdem es bereits stattgefunden hat (das findet nämlich statt, bevor _DoubleClick auslöst (wie du in post#7 richtig bemerkst)).
    keine Ahnung - vielleicht wird durch die Umstellung die bereits autogenerierte NewRow wieder weggeworfen - wie gesagt: Undurchsichtig und Holzweg.
    Imo straight-forward ist, die autogenerierte Row zu benutzen - und das habichja gezeigt.

    Mein TableNewRow-Eventhandler hat auch nix mit dem Problem zu tun, er dient einzig, dass ein eindeutiger Defaultwert vorhanden ist, wenn in die Hinzufüge-Zeile geklickst wird.
    (Mir scheint fast, du hast mein Code nicht probiert...)

    ErfinderDesRades schrieb:

    Mir scheint fast, du hast mein Code nicht probiert...
    Ich habe alles probiert, deswegen ist auch das .BeginEdit() noch drinne.
    Die auto-generierte Row ist da nicht vorhanden, jedenfalls ist Table.RowCount unverändert.
    AllowAddRows ist experimnentell reingekommen und erfüllt seinen Zweck.
    Ist diese Zeile auskommentiert:

    VB.NET-Quellcode

    1. 'DataGridView1.AllowUserToAddRows = False
    passiert das:

    Die Zeile

    VB.NET-Quellcode

    1. DataGridView1.AllowUserToAddRows = True
    ist erforderlich, damit beim Editieren ohne Dialog eine neue Zeile angehängt wird.
    Ich pack noch mal den aktuellen Code rein mit ner MessageBox, wo der Dialog zum Editieren aufpoppt:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Table As DataTable
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Me.Table = New DataTable("Messages")
    5. Me.Table.Columns.Add("Message", GetType(String))
    6. Me.DataGridView1.DataSource = Table
    7. End Sub
    8. Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
    9. Dim index = e.RowIndex
    10. Dim msg = String.Empty
    11. If index < Me.Table.Rows.Count Then
    12. ' Klick auf eine vorhandene Zeile
    13. msg = Me.Table.Rows(index)(0).ToString()
    14. End If
    15. MessageBox.Show("Edit Text")
    16. If index < Me.Table.Rows.Count Then
    17. ' Klick auf eine vorhandene Zeile
    18. Me.Table.Rows(index)(0) = msg & " edit" ' Kennung für editiert
    19. Else
    20. ' Klick auf die letzte Zeile
    21. msg = "neue Zeile"
    22. Dim row = Me.Table.NewRow()
    23. row(0) = msg
    24. Me.Table.Rows.Add(row)
    25. ' keine Leerzeile an der DataTable
    26. DataGridView1.AllowUserToAddRows = False
    27. End If
    28. End Sub
    29. Private Sub DataGridView1_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit
    30. ' Neue Zeile ohne Edit-Dialog
    31. DataGridView1.AllowUserToAddRows = True
    32. End Sub
    33. 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!