Excel in DataGridView importieren

  • VB.NET

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

    oooooh ja, das ist der Fehler :S ...

    VB.NET-Quellcode

    1. Using connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & xlsFile & ";Extended Properties=Excel 12.0;")
    2. connection.Open()
    3. Using dataadapter = New OleDbDataAdapter("Select * From [Tabelle1$]", connection)
    4. dataadapter.Fill(Me.DataSetXLS.Tabelle1)
    5. End Using
    6. End Using
    Form1 enthält:
    DGV: DataGridView1
    Button1: btn_import
    Button2: btn_export
    TextBox: tboxDurch

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.IO
    3. Imports System.Text
    4. Imports Excel = Microsoft.Office.Interop.Excel
    5. Imports System.Data.OleDb
    6. Public Class Form1
    7. Dim savePath As String 'Pfad in den gespeichert wird
    8. Dim Dateiname As String
    9. Dim excel As String 'Pfad Excel-Dateien
    10. Dim OpenFileDialog As New OpenFileDialog
    11. Dim ds As DataSet
    12. Dim dt As DataTable
    13. Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    14. Dim programPath As String 'Pfad der Anwendung
    15. Dim parentPath As String 'Übergeordneter Pfad der Anwendung
    16. programPath = Application.StartupPath.ToString() 'Pfad der Anwendung
    17. parentPath = My.Computer.FileSystem.GetParentPath(programPath) 'Ordner, in dem die Anwendung läuft
    18. 'Legt neuen Ordner in übergeordnetem Verzeichnis des Programms an sofern er noch nicht existiert
    19. If My.Computer.FileSystem.DirectoryExists(parentPath & "\Bibliothek") = False Then
    20. My.Computer.FileSystem.CreateDirectory(parentPath & "\Bibliothek")
    21. End If
    22. savePath = parentPath & "\Bibliothek\" 'Hier werden die Tabellen abgelegt
    23. End Sub
    24. Private Sub btn_export_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn_export.Click
    25. Dim xls_Appl As Excel.Application 'Excel Anwendung
    26. Dim xls_Mappe As Excel.Workbook 'Excel Arbeitsmappe
    27. Dim xls_Blatt As Excel.Worksheet 'Excel Blatt (Tabelle)
    28. Dim Anzahlzeilen As Integer 'Zeilencount
    29. Dim Datum As String = DateTime.Now.Month & "_" & DateTime.Now.Year 'Ausgabe: Monat_Jahr (m_jjjj)
    30. Dim Durchmesser As String = tboxDurch.Text
    31. xls_Appl = New Excel.Application() ' Excel Instanz bilden
    32. xls_Mappe = xls_Appl.Workbooks.Add()
    33. xls_Blatt = xls_Mappe.ActiveSheet
    34. xls_Appl.Visible = False
    35. With DataGridView1
    36. For Spalte As Integer = 0 To .Columns.Count - 1
    37. xls_Blatt.Cells(1, Spalte + 1).Value = .Columns(Spalte).HeaderText
    38. xls_Blatt.Cells(1, Spalte + 1).Font.Bold = True
    39. Next
    40. Anzahlzeilen = .Rows.Count
    41. If .AllowUserToAddRows = True Then
    42. Anzahlzeilen = Anzahlzeilen - 1 ' Leerzeile abziehen
    43. End If
    44. For Zeile As Integer = 0 To Anzahlzeilen - 1
    45. For Spalte As Integer = 0 To .Columns.Count - 1
    46. xls_Blatt.Cells(Zeile + 2, Spalte + 1).Value = .Rows(Zeile).Cells(Spalte).Value.ToString
    47. Next
    48. Next
    49. End With
    50. 'Speichern in die Bibliothek
    51. Dateiname = savePath & Durchmesser & "_" & Datum & ".xls"
    52. xls_Appl.ActiveWorkbook.SaveAs(Dateiname)
    53. 'MessageBox Abfrage: Excel Öffnen / weitermachen
    54. If MsgBox("Speichern erfolgt. Möchten Sie die Excel-Datei jetzt sehen?", vbYesNo, "Hinweis") = MsgBoxResult.Yes Then
    55. xls_Appl.Visible = True
    56. Else : xls_Appl.Quit()
    57. End If
    58. End Sub
    59. Private Sub btn_import_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btn_import.Click
    60. Dim connection As OleDbConnection
    61. Dim dataadapter As OleDbDataAdapter
    62. OpenFileDialog.InitialDirectory = savePath 'Pfadangabe des Speicherorts
    63. OpenFileDialog.Filter = "All Files (*.*)|*.*|Excel files (*.xlsx)|*.xlsx|CSV Files (*.csv)|*.csv|XLS Files (*.xls)|*xls" 'Filter nach excel-files
    64. If (OpenFileDialog.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK) Then
    65. Dim fileinfo As New FileInfo(OpenFileDialog.FileName)
    66. 'Dim FileName As String = OpenFileDialog.FileName
    67. excel = fileinfo.FullName
    68. 'Stelle Verbindung her
    69. connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excel + ";Extended Properties=Excel 12.0;")
    70. 'Öffne Leitung
    71. connection.Open()
    72. dataadapter = New OleDbDataAdapter("Select * From [Tabelle1$]", connection)
    73. dt = New DataTable("Tabelle1")
    74. dataadapter.Fill(dt)
    75. DataGridView1.DataSource = dt
    76. 'Schließe Leitung
    77. connection.Close()
    78. End If
    79. End Sub
    80. Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles tboxDurch.KeyPress
    81. MyBase.OnKeyPress(e)
    82. Dim input As Integer = Convert.ToInt32(e.KeyChar)
    83. If (input >= 47 AndAlso input <= 57) OrElse (input = 8) Then Return
    84. e.Handled = True
    85. End Sub
    86. End Class

    Edit by ErfinderDesRades: unnötige Leezeilen entfernt
    Edit: Die Leerzeilen haut's einem automatisch rein sobald man es hier einbindet

    Hab hier noch eine Alternativlösung gemacht. Ist zwar nicht sonderlich schön, aber das Importieren klappt.

    VB.NET-Quellcode

    1. Private Sub btn_import_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_import.Click
    2. Dim excel As String 'erstellt eine neue Excelinstanz
    3. Dim OpenFileDialog As New OpenFileDialog
    4. Dim Felder() As String
    5. Dim Zeile As String
    6. Const ANZAHLSPALTEN As Integer = 3
    7. Const TRENNZEICHEN As Char = ";"
    8. Dim zeilenzähler As Integer = 0
    9. '*** Öffnen des Dateiexplorers und auswahl der Excel-Datei ***
    10. OpenFileDialog.InitialDirectory = savePath 'Pfadangabe des Speicherorts
    11. OpenFileDialog.Filter = "All Files (*.*)|*.*|Excel files (*.xlsx)|*.xlsx|CSV Files (*.csv)|*.csv|XLS Files (*.xls)|*xls" 'Filter nach excel-files
    12. If (OpenFileDialog.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK) Then
    13. Dim fileinfo As New FileInfo(OpenFileDialog.FileName)
    14. Dim FileName As String = OpenFileDialog.FileName
    15. excel = fileinfo.FullName
    16. '***
    17. Dim dt = New DataTable()
    18. Dim sr = My.Computer.FileSystem.OpenTextFileReader(excel, System.Text.Encoding.Default)
    19. For i As Integer = 0 To ANZAHLSPALTEN
    20. dt.Columns.Add() 'Spaltenüberrschriften erzeugen
    21. Next
    22. Do While (sr.Peek > -1) 'Dateiende abfragen
    23. Zeile = sr.ReadLine 'Eine Datenzeile lesen
    24. Felder = Zeile.Split(TRENNZEICHEN) 'Splitten in Felder
    25. If zeilenzähler = 0 Then 'Zeile 0 wird als Überschrift angelegt
    26. For k As Integer = 0 To 3
    27. dt.Columns(k).ColumnName = Felder(k)
    28. Next k
    29. zeilenzähler = 1
    30. Else 'die übrigen Zeilen werden normal hinzugefügt
    31. Dim dr As DataRow = dt.NewRow 'Leere Datenzeile erstellen
    32. dr.ItemArray = Felder 'In DataRow speichern
    33. dt.Rows.Add(dr) 'Felder zur Datatable hinzufügen
    34. End If
    35. Loop
    36. DataGridView1.DataSource = dt 'DataTable in DataGridView zeigen
    37. End If
    38. End Sub

    Bilder
    • dataset.jpg

      100,8 kB, 1.628×367, 206 mal angesehen
    • form.jpg

      260,26 kB, 1.621×933, 234 mal angesehen

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „Cistbesser“ ()

    Form1 enthält: ...
    ja, fehlt das typisierte Dataset und mindestens eine Bindingsource
    Wie gesagt: schau das Tut - sonst hast du unendlich Möglichkeiten ganz oder teilweise zu failen.
    Oder guck zumindest die Sample-Solutions an, auch wenn du das - mangels Video - noch nicht nachbauen kannst.

    Ach hier noch ein altes, auch animiert, aber geht auch ohne Ton: "Datenbank in 10 Minuten" auf Movie-Tuts
    Beachte, dass hier nun aus einer DB befüllt wird.
    @Cistbesser
    Laut Bild (form.jpg) enthält deine Form ein Dataset und eine Bindingsource von der Table1. Schaue darunter in das Komponentenfach.
    Aber du verwendest das Dataset im Code nicht...
    (Ich machte oben den Fehler, dass beim Füllvorgang ein neu deklariertes Dataset mit Daten gefüttert wurde, anstatt gleich jenes von der Form herzunehmen. Daher musste ich bei der Bindingsource unnötigerweise die Datenabindung erneuern)

    bei mir ... dataadapter.Fill(Me.DataSetXLS.Tabelle1)
    bei dir ... dataadapter.Fill(Me.DataSet1.DataTable1)

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

    Zwischen Open und Close:

    VB.NET-Quellcode

    1. dataadapter = New OleDbDataAdapter("Select * From [Tabelle1$]", connection)
    2. dataadapter.Fill(Me.DataSet1.DataTable1)
    3. DataGridView1.DataSource = DataSet1

    Das entspricht ja dem Code, den @VB1963 gepostet hat. Aber: Zeile 2 ->"Constraint Exception wurde nicht behandelt. Einschränkungen konnten nicht aktiviert werden. Mindestens eine Zeile enthält Werte die die Einschränkungen non-null, unique or foreign-key verletzen."

    Es macht ja aber auch Sinn, wenn man den Code mal liest:
    Erstelle neuen Adapter, der durch die Connection alles aus Tabelle1 auswählt.
    Adapter füllt DataTable1 im DataSet1.
    DGV1 bezieht Daten aus dem DataSet1.

    Oder verstehe ich das jetzt falsch?

    Cistbesser schrieb:

    VB.NET-Quellcode

    1. DataGridView1.DataSource = DataSet1
    ist unnötig, evtl. gar ein Fehler: Bei designergestützter Vorgehensweise ist die Datasource im Form-Designer einmal richtig konfiguriert und gut ist. Die Codezeile zeigt, dasses falsch gemacht wurde, oder zumindest ohne es richtig zu verstehen.


    Deine Constraint-Exception bemeckert die Daten selbst, und nennt die 3 möglichen Fehler-Ursachen
    1. non-null: Für eine Spalte ist im Dataset AllowNull=False festgelegt, der Abruf von Excel liefert aber an einer Stelle einen Nullwert
    2. unique: Für eine Spalte ist Unique=True festgelegt, der Abruf liefert aber Doubletten
    3. foreign-key: Eine Spalte ist per DataRelation so eingerichtet, dass ihre Werte zwingend auf einen gültigen Primärschlüsselwert eines übergeordneten Datensatzes verweisen - die Abfrage liefert aber Fremdschlüsselwerte, die "hängen".
    Ist bisserl blöd, dass diese Exception nicht genauer geht, sondern dass du jetzt alle Restriktionen des Datasets überprüfen musst. Meist sind die Restriktionen aber notwendig, also baue keine Restriktion auf Kosten der Stimmigkeit des Datenmodells ab - nur damit das Dataset lädt.
    Anschließend musste dir die Excel-Tabellen vorknöpfen - vlt. siehst du die og. Fehler (Dubletten, Nullwerte) ja selber, ansonsten musste auch mal Test-Tabellen anlegen, und durch Rauslöschen und Rumprobieren die bösen Datensätze identifizieren.

    Der Datenabruf von Excel ist leider buggy und teilweise undefiniert, also der OledbProvider führt da in EigenregieTypumwandlungen, lässt ihm unpassend erscheinende Werte aus, und so Scherze.


    Aber überleg dir ernsthaft: Wenn das deine Arbeitszeit ist, und du nun losläufst und mw. in 2h ein Headset kaufen kannst, und anschließend dir die Vids mit Ton anguckst, dann bist du in vlt. 4 Stunden auf einem Stand den du mit selber rumprobieren eigentlich überhaupt nicht erreichen kannst, auch in Tagen oder Wochen nicht.
    Ausserdem bist du imstande zu vermeiden, dir schlechte Angewohnheiten anzugewöhnen, oder größeres auf einem suboptimalen Fundament aufzubauen.
    Zeile 3 hab ich rausgehauen, in Dataset die Spaltenwerte AllowNull=True gesetzt; es geht.
    Aber die Spalte Nachnamen bleibt trotzdem leer. Ich nehme mal an, dass er die nicht lädt (warum auch immer), und er bei AllowNull=False deshalb meckert.

    Zwecks den Tutorials: Ich bin kein Informatiker, sondern grad am Bachelor in Mechatronik dran und werde später zu 99% nie wieder etwas von Datenbanken und VB hören. Von daher glaube ich nicht, dass es immens notwendig ist, dass ich alles davon verstehe. (Ja ich weiß, ist ne scheiß Einstellung). Zudem liegt der Schwerpunkt bei dem Programm auch nicht auf den Datenbanken. Das ist nur ein good to have, was die Eumel hier haben wollen.

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

    Ok, nun musst du Datenmodellierung ernst nehmen: Kannst du einfach die Spalten auf AllowNull setzen?
    Deim Dataset-Bildle entnehme ich, dass es um Personen bzw. Kontakte geht.
    1. nenne die DataTable entsprechend: "Kontakt"
    2. gib der Datatable einen zusätzlichen Primärschlüssel mit Autowert
    3. Überlege, ob AllowNull vom Datenmodell her zulässig ist. Auf keinen Fall zulässigs scheint es mir etwa für die Spalte Nachname.
      Ich persönlich würde noch enger modellieren, und sagen: "Es gibt auch keine Person ohne Vorname, und keine ohne Ort und ohne PLZ"
      Also bei mir wäre keine der Spalten AllowNull, und ich würde im Excel nachgucken, wieso da so komische Datensätze auftreten.
    Aber ich fürchte, das Bildle ist sowieso fiktiv, und tatsächlich arbeitest du an anneren Daten. In deim Code hab ich iwas gesehen, wo Datumse in Strings umgewandelt werden - ebenfalls ein krasser Datenmodell-Fehler.
    Also wenn du dein Datenmodell bisserl angeguckt haben möchtest, musst du konkreter erzählen, was du am programmieren bist.
    Ja, das was ich hier gepostet habe ist nur für mich ein Beispiel-Programm, das ich als Grundlage verwende, damit ich den Code außerhalb des eigentlichen Programms nachvollziehen kann und damit es übersichtlich bleibt (das eigentliche Programm besteht mittlerweile aus 800 Zeilen Code und da drin rumzufummeln wäre ein riesen Aufwand).

    Ok, aber worum es gehen soll: Das Haupt-Programm ist für die Erstauslegung von E-Motoren zuständig. Man hat mehrere Tabellen, zB eine in der Geometriedaten stehen, eine in der Daten zum thermischen Modell stehen, etc. Die Tabellen sind von den Spalten alle gleich aufgebaut: Bezeichnung, Formelkürzel, Wert, Einheit. Bis auf die Spalte Wert wird in den Tabellen nichts verändert. Ich habe die einzelnen Tabellen nochmals unterteilt in Input und Output. Bsp: Bei der Tabelle Geometriedaten Input steht der Stator-Durchmesser, der per Hand eingegeben wird. Eine Funktion liest den Wert aus und berechnet damit die Polschuhbreite und gibt diesen Wert im entsprechenden Feld in der Output-Tabelle aus.

    Wie am Thread-Anfang beschrieben ist dieses Thema dazu da, Konfigurationen zu speichern und auch wieder zu laden, falls man mal einen ähnlichen Motor hat und nur ein paar Werte ändern muss.
    Das Datum wird in einen String gewandelt, da es Teil vom Dateinamen werden soll. Man soll eine Konfiguration später unter dem Firmennamen, für die der Motor gemacht wurde, dem Außendurchmesser, dem Typ und dem Datum im Ordner finden können.
    Der Dateiname soll dann etwa so aussehen: FirmaXY_MX210_120_092014.
    Ggf wird am Ende noch eine Funktion eingebaut, mit der man zB nach dem Außendurchmesser filtern lassen kann und dann nur die entsprechenden Konfigurationen vorliegen hat.
    ja, das kann man jetzt datenbänkerisch ausnormalisieren, wenn man will.
    Also Einheit wäre eine eigene Tabelle, und ebenso FormelKürzel (weil so Formelkürzel bedeuten ja irgendetwas).
    Wenn die Tabellen alle gleich aufgebaut sind, liegt höchstwahrscheinlich ein weiterer Modell-Fehler vor, denn ein Datenmodell enthält normal niemals gleich aufbebaute Tabellen.
    Ja, und das mit den Konfigurationen ist auch eine schöne Aufgabe zu modellieren: Eine Konfig-Tabelle würde über eine Mittler-Tabelle evtl. auf verschiedene Wert-Datensätze verweisen, aus denen die Konfiguration sich zusammensetzt.

    Also so in die Richtung würde man das datenbänkerisch anpacken - ist klar, dass sowas in Excel nur sehr unbefriedigend umgesetzt werden kann.

    Das mit den Datumsen in Dateinamen versteh ich.
    Allenfalls die Frage, wozu viele Dateien. Eine Datenverarbeitung bevorzugt, alle Daten in einer Datei zu halten, weil darin die Relationen gesichert werden können.

    Aber wie sexy son ausbaldowertes Datenmodell ist erschließt sich dir natürlich erst, wenn du lernst, mit Databinding und Co da eine leistungsfähige Oberfläche drauf aufzubauen. Womit wir wieder bei den Videos wären »Ich geh euch doch nicht etwa auf die Nerven?«

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

    Also das ursprüngliche Programm liegt mir momentan in Excel vor, und ich soll es einfach überarbeiten. Überflüssiges raus, neue Features rein, Oberfläche überarbeiten. Es wurden in Excel über die Jahre immer mehr Tabellen angefügt und Makros geschrieben, dass man jetzt nur noch schwer durchblickt. Man hat nur ein Sheet, in dem alle diese Tabellen sind. (siehe Bild) Es verändert sich wirklich nur die Spalte mit den Werten. Alles andere ist fest. Ein Datenmodell liegt gar nicht vor. Das haben Ingenieure geschrieben als Hilfsmittel ;) Da wurde nix von Informatikern oder professionellen Codern gemacht.

    Ich glaube ich erkär das alles schlecht, deshalb nochmal zu dem Begriff Konfiguration speichern: Damit meinte ich, dass ein Abbild aller Tabellen erstellt wird.

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

    also wenn du es richtig machen willst, musst du es relational lösen. Alles andere ist aus einem Unfug einen anderen Unfug machen.
    Um eine Konfiguration zu speichern muss man keinesfalls sämtliche Tabellen kopieren - ein durchdachtes relationales Datenmodell hat da ganz andere Möglichkeiten.
    die relationale GrundIdee

    aber überprüfe auch mal deine Datenverarbeitungs-Vorraussetzungen insgesamt.
    Ok, also scheinbar habe ich nur 2 Möglichkeiten:
    1. Das vorhandene Excel Programm einfach von der Oberfläche her anpassen, d.h. Tabellen einfach verschieben etc.
    2. Ein Programm komplett neu aufsetzen inkl. Datenbanken.

    Werde das meinem Betreuer mal besprechen und mir dann wohl ein Buch aus der Bibliothek ausleihen...
    fast richtig, nur Moglichkeit 2 ist ohne Datenbank. Relationales Datenmodell im typisierten Dataset ja - Datenbank nein.
    Datenbank kannste jederzeit später hinterlegen, ohne irgendwas am typDataset ändern zu müssen.
    Aber was in eine (oder auch 50) Excel-Sheets passt, das passt auch in ein auf Platte gespeichertes typisiertes Dataset.