DGV ohne Databinding in eine DataTable (Column-Count-Problem?)

  • VB.NET
  • .NET (FX) 4.0

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von tragl.

    DGV ohne Databinding in eine DataTable (Column-Count-Problem?)

    Moin zusammen.
    Ich hab' mir ne Methode für einen Excel-Export gebastelt, welche mir Daten aus mehreren Gebundenen oder ungebundenen DataGridViews in jeweils eine DataTable
    packt und die dann in eine gemeinsame Excel-Datei mit mehreren Worksheets Exportiert.

    Im Beispiel meines Urlaubsplaners hab ich DGVs, wo ich die MitarbeiterID-Spalte im DGV ausgeblendet hab. Die soll natürlich auch nicht mit in die Excel-Datei.
    Filtere ich die ausgeblendete Spalte im Code nicht weg, kommt die mit in die Excel - es läuft aber sauber durch.
    Filtere ich die aber raus kommt er komischerweise mit der Column-Anzahl nicht klar, obwohl die übereinstimmend ist (das seh ich ja an Debug.Print).... habich was übersehen?
    Bei Zeile 35 läuft er dann in den Fehler für die Dezember-Col.. ?(

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Sub ExportDgvsToExcel(DI As Dictionary(Of DataGridView, String))
    2. Dim excelFile = saveAs("Excel-Dateien (*.xlsx)|*.xlsx")
    3. If excelFile = "" Then Return
    4. If File.Exists(excelFile) Then File.Delete(excelFile)
    5. For Each entry In DI
    6. Dim dgv = entry.Key
    7. Dim wsn = entry.Value
    8. ExportDgvWsnToExcel(dgv, wsn, excelFile)
    9. Next
    10. If msgQuestionInfo($"Der Export wurde unter {excelFile} gespeichert.{Environment.NewLine}Soll die Datei geöffnet werden?") = DialogResult.Yes Then
    11. Process.Start(excelFile)
    12. End If
    13. End Sub
    14. Private Sub ExportDgvWsnToExcel(dgv As DataGridView, wsn As String, excelFile As String)
    15. Dim eFi = New FileInfo(excelFile)
    16. Using pck As New ExcelPackage(eFi)
    17. Dim wks = pck.Workbook.Worksheets.Add(wsn)
    18. Dim bsDGV = DirectCast(dgv.DataSource, BindingSource)
    19. Dim dtExport As New DataTable
    20. If bsDGV IsNot Nothing Then 'DGV ist gebunden
    21. dtExport = bsDGV.DataTable.DefaultView.ToTable()
    22. Else 'DGV ist ungebunden
    23. Dim iCol = 0 'Test für Debug.Print
    24. For Each col As DataGridViewColumn In dgv.Columns
    25. If col.Visible = True Then dtExport.Columns.Add(col.HeaderText) : Debug.Print($"{col.HeaderText}|col-add|{iCol}") : iCol += 1
    26. Next
    27. For Each rw As DataGridViewRow In dgv.Rows
    28. Dim irCol = 0 'Test für Debug.Print
    29. dtExport.Rows.Add()
    30. For Each cell As DataGridViewCell In rw.Cells
    31. If cell.OwningColumn.Visible = True Then
    32. Debug.Print($"{cell.OwningColumn.HeaderText}|row-add|{irCol}") : irCol += 1
    33. If cell.Value IsNot Nothing Then
    34. dtExport.Rows(dtExport.Rows.Count - 1)(cell.ColumnIndex) = cell.FormattedValue.ToString
    35. Else
    36. dtExport.Rows(dtExport.Rows.Count - 1)(cell.ColumnIndex) = ""
    37. End If
    38. End If
    39. Next
    40. Next
    41. End If
    42. wks.Cells("A1").LoadFromDataTable(dtExport, True)
    43. pck.Save()
    44. End Using
    45. End Sub


    Hier noch die Debug-Print-Ausgabe:
    Spoiler anzeigen

    Quellcode

    1. Mitarbeiter|col-add|0
    2. Gesellschaft|col-add|1
    3. Standort|col-add|2
    4. Urlaubsanspruch|col-add|3
    5. Urlaub verplant|col-add|4
    6. Urlaub unverplant|col-add|5
    7. Resturlaub Vorjahr|col-add|6
    8. Krank|col-add|7
    9. Januar|col-add|8
    10. Februar|col-add|9
    11. März|col-add|10
    12. April|col-add|11
    13. Mai|col-add|12
    14. Juni|col-add|13
    15. Juli|col-add|14
    16. August|col-add|15
    17. September|col-add|16
    18. Oktober|col-add|17
    19. November|col-add|18
    20. Dezember|col-add|19
    21. Mitarbeiter|row-add|0
    22. Gesellschaft|row-add|1
    23. Standort|row-add|2
    24. Urlaubsanspruch|row-add|3
    25. Urlaub verplant|row-add|4
    26. Urlaub unverplant|row-add|5
    27. Resturlaub Vorjahr|row-add|6
    28. Krank|row-add|7
    29. Januar|row-add|8
    30. Februar|row-add|9
    31. März|row-add|10
    32. April|row-add|11
    33. Mai|row-add|12
    34. Juni|row-add|13
    35. Juli|row-add|14
    36. August|row-add|15
    37. September|row-add|16
    38. Oktober|row-add|17
    39. November|row-add|18
    40. Dezember|row-add|19
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Beispiel: Du hast 3 Spalten. Die 2. ist unsichtbar. Damit werden der DataTable 2 Spalten hinzugefügt: eine mit Index 0 und eine mit 1. Und dann versuchst Du aber später über cell.ColumnIndex auf die 3. Spalte, also die mit dem Index 2 zuzugreifen, weil Du ja die mit 1 überspringen willst. Boom!
    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, aber!:

    Ich prüfe vor dem Hinzufügen der Columns zur DataTable, ob die Visible ist:
    If col.Visible = True Then dtExport.Columns.Add(col.HeaderText)
    also added er die garnicht erst zur DataTable

    Das Gleiche mache ich nochmal beim Hinzufügen der DataRows:
    If cell.OwningColumn.Visible = True Then
    also added er nicht den Cell-Wert von die Owning-Col unsichtbar ist.

    Er springt auch drauf an, dass die nicht vorhanden ist - folglich sollte er dich doch (auch beim Counten) überspringen? Also muss die Anzahl doch auch wieder passen...
    Oder ich steh' grad total aufm Schlauch :S
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Ja, hab ich nun verstanden - bin davon ausgegangen, dass er den Zell-Wert genauso überspringt wie oben die Column auch, hätte ja klappen können ;)
    Aber was nun? Dann muss ich ja irgendwie die Indexe vergleichen (eigentlich lieber den Headertext aber das bekomm ich grad iwie net hin)

    Edit: Hab's - so funzt das nun:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub ExportDgvWsnToExcel(dgv As DataGridView, wsn As String, excelFile As String)
    2. Dim eFi = New FileInfo(excelFile)
    3. Using pck As New ExcelPackage(eFi)
    4. Dim wks = pck.Workbook.Worksheets.Add(wsn)
    5. Dim bsDGV = DirectCast(dgv.DataSource, BindingSource)
    6. Dim dtExport As New DataTable
    7. For Each col As DataGridViewColumn In dgv.Columns
    8. If col.Visible = True Then dtExport.Columns.Add(col.HeaderText)
    9. Next
    10. For Each rw As DataGridViewRow In dgv.Rows
    11. dtExport.Rows.Add()
    12. For Each cell As DataGridViewCell In rw.Cells
    13. If cell.OwningColumn.Visible = True Then
    14. Dim colHeader = cell.OwningColumn.HeaderText
    15. If cell.Value IsNot Nothing Then
    16. dtExport.Rows(dtExport.Rows.Count - 1)(colHeader) = cell.FormattedValue.ToString
    17. Else
    18. dtExport.Rows(dtExport.Rows.Count - 1)(colHeader) = ""
    19. End If
    20. End If
    21. Next
    22. Next
    23. wks.Cells("A1").LoadFromDataTable(dtExport, True)
    24. pck.Save()
    25. End Using
    26. End Sub
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:

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

    ich bin ja nicht so Froind tieflicher Verschachtelichulierungen...
    guggemodies:

    VB.NET-Quellcode

    1. Private Sub ExportDgvWsnToExcel(dgv As DataGridView, wsn As String, excelFile As String)
    2. Dim eFi = New FileInfo(excelFile)
    3. Using pck As New ExcelPackage(eFi)
    4. Dim wks = pck.Workbook.Worksheets.Add(wsn)
    5. Dim bsDGV = DirectCast(dgv.DataSource, BindingSource)
    6. Dim dtExport As New DataTable
    7. Dim visibleColNames = dgv.Columns.Cast(Of DataGridViewColumn).Where(Function(x) x.Visible).Select(Function(x) x.HeaderText).ToList
    8. visibleColNames.ForEach(AddressOf dtExport.Columns.Add)
    9. For Each rwDgv As DataGridViewRow In dgv.Rows
    10. Dim rwExport = dtExport.Rows.Add()
    11. visibleColNames.ForEach(Sub(col)rwExport(col) = CStr(rwDgv.Cells(col).FormattedValue))
    12. Next
    13. wks.Cells("A1").LoadFromDataTable(dtExport, True)
    14. pck.Save()
    15. End Using
    16. End Sub
    ;)
    Das wichtigste ist wohl, dassich gern so kleine Listen mache mit den Sachen, die gebraucht werden - hier: visibleColNames.
    Ein anderer Trick ist mit CStr(): Während die ObjektMethode .ToString() bei Nothing eine Exception wirft, kann CStr() auch Nothing konvertieren - zu ""
    Edit: Und .ForEach() mag ich auch gerne, damit kann man aus 3-Zeilern Einzeiler machen.

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

    ErfinderDesRades schrieb:

    dassich gern so kleine Listen mache mit den Sachen, die gebraucht werden

    Das muss ich mir auch ma angewöhnen, ist praktisch.

    Das mit CStr(), dass es da keine Exception gibt sonderen er das zu "" umwandelt wusst' ich nicht - ist ein nettes Feature. ;)
    Aber dein Code läuft nicht durch, er meckert, dass er eine bestimmte Spalte nicht finden kann (Zeile 12)

    Zeile 7-8 tun ihren Dienst einwandfrei
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup:
    Da alle Spaltennamen in Z#8 der DataTable hinzugefügt werden, ist es eigentlich nicht möglich, dass Z#12 rebelliert. Der Code hat aber vermutlich seine Tücken, nämlich wenn ein Spaltenname doppelt vergeben wurde (»Dezember«; aber Spekulatius). Ist der angemeckerte Spaltenname in visibleColNames drin? Hat die Spalte überhaupt einen Namen, die erwähnt wird?
    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.
    Mit Bezug auf Zeile 11 von Edr's Post:

    Mit der Testzeile visibleColNames.ForEach(Sub(col) rwExport(col) = "test") läuft es durch.
    Es liegt dann daran, dass der Column-Headertext ein anderer ist als der Columnname.
    Er versucht in dem Code aber mit dem Name zu arbeiten CStr(rw.Cells(col).FormattedValue) müsste sowas wie CStr(rw.Cells(col.headertext).FormattedValue) heißen
    dann würde das auch klappen. Die Property gibt's da aber nicht.

    Trotzdem ist mein Code nun was kürzer:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub ExportDgvWsnToExcel(dgv As DataGridView, wsn As String, excelFile As String)
    2. Dim eFi = New FileInfo(excelFile)
    3. Using pck As New ExcelPackage(eFi)
    4. Dim wks = pck.Workbook.Worksheets.Add(wsn)
    5. Dim bsDGV = DirectCast(dgv.DataSource, BindingSource)
    6. Dim dtExport As New DataTable
    7. Dim visibleColNames = dgv.Columns.Cast(Of DataGridViewColumn).Where(Function(x) x.Visible).Select(Function(x) x.HeaderText).ToList
    8. visibleColNames.ForEach(AddressOf dtExport.Columns.Add)
    9. For Each rw As DataGridViewRow In dgv.Rows
    10. dtExport.Rows.Add()
    11. For Each cell As DataGridViewCell In rw.Cells
    12. If cell.OwningColumn.Visible = True Then
    13. Dim colHeader = cell.OwningColumn.HeaderText
    14. dtExport.Rows(dtExport.Rows.Count - 1)(colHeader) = CStr(cell.FormattedValue)
    15. End If
    16. Next
    17. Next
    18. wks.Cells("A1").LoadFromDataTable(dtExport, True)
    19. pck.Save()
    20. End Using
    21. End Sub
    "Na, wie ist das Wetter bei dir?"
    "Caps Lock."
    "Hä?"
    "Shift ohne Ende!" :thumbsup: