VB.NET: Dateinamen aus Ordner in Tabelle speichern und als .csv speichern

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

Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von Rostam.

    VB.NET: Dateinamen aus Ordner in Tabelle speichern und als .csv speichern

    Hallo allerseits,
    habe nach langem stillen Mitlesen mich gerade hier angemeldet und hoffe, dass Ihr Profis auch meine Anfängerfragen beantworten könnt.

    Also ich habe es inzwischen geschafft alle Dateinamen aus einem Ordner per ButtonClick in eine ListBox zu schreiben. Nur ich muss diese Dateinamen auch noch kommentieren können. Dafür habe ich an eine Tabelle gedacht. Nur ich bin blutjunger Anfänger, keinen Plan wie ich das realisieren soll, aber ich lerne immer gerne dazu. Ich habe an vier Spalten gedacht und je Datei soll eine neue Zeile angelegt werden. Das Ganze soll nach dem Kommentieren per "Speichern unter"-Dialog als CSV-Datei gespeichert werden um das dann auch wieder öffnen zu können.

    Würde mich über jede Hilfe und Tipp sehr freuen.

    Es kommen bestimmt noch ganz viele Fragen. Das ist das erste richtige Projekt in .Net :D
    Das mit der Tabelle hört sich ja ganz gut an. Das speicher in CSV finde ich auch ok. Alternativ kann man auch ein DataSet nehmen oder eine serialisierbare List(Of T).
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Willkommen im Forum.
    Wie Du bestimmt schon mitbekommen hast, bietet die ListBox keinen Mehrspaltenbetrieb. Viele Einsteiger verwenden als nächste Stufe dann ein ListView. Überspring das bitte gleich und nimm gleich ein DataGridView her. Darauf kann man dann später prima auch aufbauen, wenn wir bei dem Thema typ. DataSet und effektives Abspeichern ankommen.
    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.
    Also hab jetzt ein DataGridView eingefügt und ich kann die Dateinamen in die jeweils erste Spalte einlesen. Es gibt dabei ein paar Punkte, die mir noch unklar sind.

    1.) Ist es irgendwie möglich die Bezeichnungen zweizeilig zu machen? Ich würde bei den beiden kleinen Feldern nur "Ja" und "Nein" schreiben. Darüber (also über die beiden) soll dann stehen "Bezahlt?". Ist das irgendwie machbar? (Bild 1)

    2.) Die beiden kleinen Felder sollen dann nur per Klick befüllt werden. Ich habe versucht Radio-Buttons einzufügen, aber die liegen ja dann drüber und nicht in der Zelle. Wie kann man die Funktionalität ohne Radio-Buttons realisieren? Das heißt für jede Zeile, die eingelesen wird, ist standardmäßig die rechte Seite "Nein" befüllt mit roter Farbe. Wenn man dann in das linke Feld "Ja" klickt, wird dieses Grün und das "Nein" wird farblos. Wie wäre das zu realisieren?

    3.) Wie kann ich das ganze Ding anpassen an die Fenstergröße? Bspw. 80%, sodass es auch beim Vergrößern des Fensters die Größe behält. (Bild 2)

    4.) Wenn ich jetzt wie im Beispiel einen Ordnerinhalt eingelesen habe und kommentiere ist ja alles gut. So, wenn ich dann aber den gleichen Ordner nochmal einlese kriege ich alle Dateinamen doppelt. (Bild 3) Ich möchte DataGridView aber aktualisieren und die neue Datei "BC.txt" in eine neue Zeile zwischen "BB" und "CC" einsetzen.

    Habt Ihr dazu Ideen oder Tipps?
    Bilder
    • DataGridView1.png

      249,66 kB, 1.250×700, 137 mal angesehen
    • DataGridView2.png

      79,07 kB, 1.250×700, 140 mal angesehen
    • DataGridView3.png

      228,79 kB, 1.880×800, 140 mal angesehen

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

    Die 2. Spalte richtest Du als ComboBoxColumn ein, Titel: "bezahlt" (ggf. mit Fragezeichen, nach Belieben). Dann kannst Du dort ein Häkchen setzen oder es rausnehmen. RadioButtons sind nicht möglich.
    Die Größenanpassung der DGV an sich läuft wie mit den meisten: Die Property Anchor setzen, sodass Top, Left und Right, ggf. auch Bottom angegeben ist. Dadurch "verhakt" sich das DGV mit dem Form und wird in seiner Größe mit dem Fenster/Form mitgeändert. Die DGV-Spalten können auch mit dem AutoSizeMode jeder Spalte angepasst werden: Ich setze immer alle Spalten auf auf AllCells und eine, deren Inhalt notfalls auch abgeschnitten werden darf (z.B. Dateiname) auf Fill. So werden alle Spalten bis auf die eine an die Inhalte und Headergrößen angepasst und die eine füllt den Rest der DGV-Breite aus.
    Das Datenaktualisieren musst Du über den Code machen. Da ist dann Programmierung angesagt.
    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.
    für mich ist die hauptsache ja immer das typisierte Dataset.
    2. Hauptsache ist dann das DGV, was unerhört super-gut mit dem Dataset interagiert.

    Also wenn deine typDataset-Tabelle eine Boolean-Spalte "Bezahlt" hat, so erzeugt das daran angebundene DGV automatisch eine CheckboxSpalte "Bezahlt", und Einträge sind entweder gecheckt oder nicht - will sagen: 2 Spalten "Bezahlt - nichtBezahlt" sind garnet erfordelich.
    Tutorial zum TypDataset: Daten laden und speichern

    Tut zum anneren Thema, Layout: Layout in Windows.Forms
    Danke für die Antwort. Das mit der Größenanpassung hab ich gefunden, danke schön!

    Wegen der zweiten Zelle... wollte es gerne mit zwei Zellen machen, aber ja so geht es auch.

    Folgende zwei Punkte müssten durch Programmierung gelöst werden:
    1. Beim Generieren jeder Zeile die zweite Zelle standardmäßig Rot einfärben und bei Klick dann Grün färben. Wie kann ich diese Zelle denn ansprechen?
    2. Ist schon klar, dass auch bei der Datenaktualisierung Programmierung angesagt ist. Die Frage ist WIE man das am besten realisiert. Vielleicht könntest Du mir da etwas den Weg weisen? Würde mich sehr freuen!
    @ErfinderDesRades
    Danke für den Tipp mit typDataset. Habe jetzt ein DataSet erstellt und das in einer neuen DGV (Name: "InvoiceDGV") eingebunden.
    Aber wie kann ich denn jetzt die einzulesenden Dateinamen in das DataSet/DGV schreiben? Bisher mit einem normalen DGV sah es so aus

    Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
    2. Dim sPath As String
    3. sPath = TextBox1.Text
    4. If sPath.EndsWith("\") And sPath.Length > 3 Then
    5. sPath = sPath.Substring(0, sPath.Length - 1)
    6. End If
    7. Dim oDir As New System.IO.DirectoryInfo(sPath)
    8. Dim oFiles As System.IO.FileInfo() = oDir.GetFiles()
    9. Dim oFile As System.IO.FileInfo
    10. For Each oFile In oFiles
    11. DataGridView1.Rows.Add(oFile.Name)
    12. 'DataGridView1.
    13. Next
    14. End Sub

    und mit dem typDataset geht

    Quellcode

    1. InvoiceDGV.Rows.Add(oFile.Name)
    offenbar nicht.

    2. Frage: Jetzt hast Du ja in Deinem Tutorial darüber das Ganze direkt in eine XML "Dataset1.xml" geschrieben. Aber wie mache ich das wenn ich per "Save as" den Ort und den Dateinamen selber bestimmen lassen will? Sodass ich bspw. mehrere solche Dinger abspeichern kann und dann auch wieder öffnen?

    3. Frage: Da wäre auch noch das Problem mit der Aktualisierung der Tabelle? Was würdest Du hierfür raten?
    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!
    @Rostam: Wenn Du ein tDS schon erstellt hast, kannst Du da mal bitte aus dem tDS-Designer einen Screenshot posten, damit wir wissen, wie es konkret weitergehen kann? Grundsätzlich arbeitest Du nicht mehr mit dem DGV, sondern es geht mit dem tDS weiter, indem Du zu Deinen DataTables passende Zeilen hinzufügst, also z.B. DeinTds.FileTable.AddFileTableRow(FileName, IsAlreadyPaid, Remark). Wie die konkrete Syntax bei Dir dann auszusehen hat, ist direkt von Deiner DataTable und den darin deklarierten Spalten+deren Typen abhängig.
    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.
    Klar, hier der Screenshot. Mein tDS heißt "InvoiceOverviewDataSet".

    Dabei würde ich auch gerne das Feld "date" erst aktivieren wenn "paid" angehakt wird.

    Der zweite Screenshot zeigt das DGV der tDS. Da ist unten noch das alte DGV, aber das kommt dann später weg wenn das oben läuft. Speichern und Öffnen soll dann wie bei jedem Programm über das "File"-Menü gehen. Auch das Feld und der "Load"-Button sind jetzt nur zum Testen da. Im Feld schreibe ich aktuell noch den Ordnerpfad rein. Das soll später in den Settings einstellbar sein und vorne in einem Label nur der Pfad angezeigt werden und einen Button "Aktualisieren" geben. Soweit die erste Vorstellung.... :)
    Bilder
    • InvoiceOverviewDataSet.jpg

      655,65 kB, 1.920×1.014, 114 mal angesehen
    • InvoiceOverviewGUI.png

      435,42 kB, 1.920×1.014, 152 mal angesehen
    • File-Menu.png

      434,71 kB, 1.920×1.014, 141 mal angesehen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Rostam“ ()

    Das ist doch ml ein guter Anfang. Nur fehlt in Deiner DataTable noch die m.E. obligatorische ID-Spalte (Int32, AutoIncrement, Unique). Irgendwo las ich mal: Wer glaubt, dass er keine braucht, weiß einfach nur noch nicht, dass er sie braucht. Aber: Deine Entscheidung ;) .
    Ich vermute mal, dass invoice und information vom Typ String und date vom Typ DateTime ist.
    Dass Du das Datefeld erst aktivieren willst, wenn das Häkchen gesetzt ist, dafür ist mir keine Möglichkeit bekannt. Das von Dir früher erwähnte Farbensetzen ist möglich, aber auch nicht ganz ohne. Letztenendes gehst Du zu einem gewissen Zeitpunkt (z.B. BindingSource.CurrentChanged*) alle Zeilen der DataTable durch und schaust nach deren paid-Wert. Aufgrunddessen setzt Du dann im DGV die Farben.
    Die anderen Vorhaben sind sinnvoll. Damit kommst Du klar?

    btw:
    Man kann sich noch ne eigene DateTime-DGVColumn basteln, ist aber ggf. Overkill für den Anfang. Hier im Forum gibt's auch was zum Thema eigene Control-Spalten im DGV.

    *Beachte bitte, dass das Hakensetzen noch nicht zum CurrentChanged-Event führt. Erst wenn Du die Zeile verlässt und so die Änderung bestätigst, wird das Event ausgelöst.

    ##########

    Aber statt dem "echten" Deaktivieren kannst Du die entsprechenden Zellen ReadOnly machen und ausgrauen.
    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.

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

    VaporiZed schrieb:

    Das ist doch ml ein guter Anfang. Nur fehlt in Deiner DataTable noch die m.E. obligatorische ID-Spalte (Int32, AutoIncrement, Unique). Irgendwo las ich mal: Wer glaubt, dass er keine braucht, weiß einfach nur noch nicht, dass er sie braucht. Aber: Deine Entscheidung ;) .

    Die ID-Spalte hatte ich ganz vergessen. Hast Du völlig Recht! Hab jetzt im DataSet eine neue Spalte "ID" eingefügt, aber die ist da jetzt ganz am Ende. Hat zwar auf die Funktion keinen Einfluss, aber ich fände es schöner wenn die ID am Anfang steht. Kann man das nachträglich noch verschieben oder muss ich die ganzen anderen Spalten löschen und nochmal neu erstellen? (Kann ich mir eigentlich kaum vorstellen.) Die nächste Frage zur ID: Wenn ich das auf AutoIncrement setze dann müsste ich doch AutoIncrementSeed auf "1" setzen um bei 1 anzufangen und AutoIncrementStep auch auf "1" um jeweils um 1 zu erhöhen, richtig? Weil momentan stehen beide noch auf "-1".

    VaporiZed schrieb:

    Ich vermute mal, dass invoice und information vom Typ String und date vom Typ DateTime ist.

    Ja, richtig. Wobei ich noch nicht genau weiß wie ich mit DateTime umgehen muss. Weil ich habe nirgendwo gefunden wo ich einstellen kann welches Eingabeformat (TT.MM.JJJJ) akzeptiert werden soll. Oder macht der das automatisch, auch wenn man z.B. nur T.M.JJ eingibt?

    VaporiZed schrieb:


    Dass Du das Datefeld erst aktivieren willst, wenn das Häkchen gesetzt ist, dafür ist mir keine Möglichkeit bekannt. Das von Dir früher erwähnte Farbensetzen ist möglich, aber auch nicht ganz ohne. Letztenendes gehst Du zu einem gewissen Zeitpunkt (z.B. BindingSource.CurrentChanged*) alle Zeilen der DataTable durch und schaust nach deren paid-Wert. Aufgrunddessen setzt Du dann im DGV die Farben.
    [...]
    *Beachte bitte, dass das Hakensetzen noch nicht zum CurrentChanged-Event führt. Erst wenn Du die Zeile verlässt und so die Änderung bestätigst, wird das Event ausgelöst.
    [...]
    Aber statt dem "echten" Deaktivieren kannst Du die entsprechenden Zellen ReadOnly machen und ausgrauen.

    Ok, da hatte ich mich falsch ausgedrückt. Ich meinte das genau so wie Du schreibst. "date" sollte am Anfang ReadOnly und ausgegraut sein und beim CurrentChange von "paid" dann Weiß und beschreibbar werden. Ist das machbar? Das könnte dann nur problematisch werden wegen dem Zeitpunkt des CurrentChanged-Event, wie Du schreibst. Wenn der Event nicht mit dem Hakensetzen ausgelöst wird, dann muss wohl nach dem Hakensetzen erst in "info" rein, damit der Event überhaupt ausgelöst und "date" Weiß wird??

    Aber auch das ist ein Nice-to-Have und kein Must-Have.... von daher, erstmal die Grundfunktionalität hinbekommen, dann solche Details :)

    VaporiZed schrieb:

    Die anderen Vorhaben sind sinnvoll. Damit kommst Du klar?

    Leider noch nicht so ganz :S eher so gar nicht. Ich weiß z.B. noch nicht wie ich beim Klick auf ein Menü-Element eine darüberliegende Form öffne bspw. Settings. Und wie ich das Ganze speichern und wieder öffnen kann. Aber erstmal muss das einlesen der Dateinamen aus dem Ordner in das DataSet klappen, damit ich überhaupt etwas zum speichern habe....

    VaporiZed schrieb:


    btw:
    Man kann sich noch ne eigene DateTime-DGVColumn basteln, ist aber ggf. Overkill für den Anfang. Hier im Forum gibt's auch was zum Thema eigene Control-Spalten im DGV.

    Ja, das ist für jetzt dann wirklich etwas zu viel Overkill. Wär ja schon froh wenn das was ich jetzt so vor habe bald mal richtig läuft. :/



    Rostam schrieb:

    Kann man das nachträglich noch verschieben
    Klar. Im tDS-Designer die ID-Spalte auswählen, z.B. mit Strg+X ausschneiden, die bisher 1. Spalte auswählen und einfügen.
    Da Du (normalerweise) nie auf die ID-Werte an sich zugreifst (oder zugreifen solltest), ist die Richtung, in die die IDs gehen, so ziemlich wurscht. Wenn Du glaubst, dass Du die IDs doch auswerten musst, dann liegt m.E. meist ein Datenmodellierungsfehler vor und die DataTable hätte gerne eine zusätzliche Spalte mit einem entsprechenden Auswahlkriterium. Denn: Die Reihenfolge, in der die Datenzeilen in der Tabelle abgespeichert werden, sollte niemals relevant sein. Meines Erachtens. Also: einfach bei den default-values -1 und -1 belassen ;)
    Auch die Art, wie das Datum im Datensatz abgespeichert wird, ist wurscht. Wie das Datum im DGV dargestellt wird, ist Einstellungssache. Wo? Genau: im DGV selbst.
    Bzgl. Aktualisierung der Date-Spaltenfarbe: BindingSource_CurrentChanged ist schon richtig. Dann kannst Du sowas z.B. schreiben*:

    VB.NET-Quellcode

    1. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    2. ColorizeDgv()
    3. End Sub
    4. Private Sub Bs_CurrentChanged(sender As Object, e As EventArgs) Handles Bs.CurrentChanged
    5. ColorizeDgv()
    6. End Sub
    7. Private Sub ColorizeDgv()
    8. Dim IndexOfDateColumn = 2
    9. For i = 0 To Dgv.RowCount - 1
    10. Dim Current = DirectCast(DirectCast(Bs.List(i), DataRowView).Row, InvoiceOverviewDataSet.InvoiceOverviewRow)
    11. Dgv.Item(1, IndexOfDateColumn).ReadOnly = Not Current.paid
    12. Dgv.Item(1, IndexOfDateColumn).Style.BackColor = If(Current.paid, Color.White, Color.LightGray)
    13. Next
    14. End Sub


    *vielleicht haben @ErfinderDesRades oder @VB1963 oder noch jemand noch ne bessere Methode.

    Das BS_CurrentChanged-Event wird dann ausgelöst, wenn Du zu einer anderen Daten-/DGV-Zeile wechselst. Leider kenne ich keinen codeseitigen Befehl, um die Bearbeitung der Datenzeile sonst abzuschließen. @ErfinderDesRades: Um Dir zuvorzukommen: Nein, BindingSource_EndEdit, DGV.CommitEdit und Me.Validate funktionieren nicht. (Aber da kommt bestimmt noch was, was ich übersehen habe. Wäre sehr hilfreich.) Nur der BindingSource-Positionswechsel konnte bisher bei mir helfen. BindingSource.EndEdit hilft doch. Die Werte sind danach korrekt in der DataTable hinterlegt. Danach einfach nur noch die ColorizeDgv-Sub aufrufen. Man kann die beiden Aufrufe z.B. dann machen, wenn das DGV den Eingabefokus verliert oder wenn tatsächlich der Haken gesetzt wurde. Da gab's neulich schon mal einen Thread dazu. Ich setz als Extraantwort noch Code nach, sobald ich es gefunden habe.

    Rostam schrieb:

    Ich weiß z.B. noch nicht wie ich beim Klick auf ein Menü-Element eine darüberliegende Form öffne bspw. Settings.
    guckst Du beim RfG-Tutorial

    Rostam schrieb:

    Und wie ich das Ganze speichern und wieder öffnen kann.
    guckst Du beim EdR-Tutorial
    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.

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

    Hab's zumindest durch t&e herausgefunden:

    VB.NET-Quellcode

    1. Private Sub Dgv_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles Dgv.CellContentClick
    2. Dim IndexOfPaidColumn = 1
    3. If e.ColumnIndex <> IndexOfPaidColumn Then Exit Sub
    4. Dgv.CommitEdit(DataGridViewDataErrorContexts.Commit)
    5. Bs.EndEdit()
    6. ColorizeDgv()
    7. End Sub
    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.
    Danke schön! Ich komme nur mit der Hauptfunktionalität noch nicht so ganz zurecht. Habe schon mehreres getestet Wie kann ich denn nun die Dateinamen in das Dataset schreiben? Du hattest mir mal das als Anhaltspunkt gegeben: DeinTds.FileTable.AddFileTableRow(FileName, IsAlreadyPaid, Remark) aber ich sehe bei mir kein AddFileTableRow().... (siehe Screenshot). Was mache ich falsch?
    Bilder
    • Tds-add-row.png

      131,46 kB, 885×545, 128 mal angesehen

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

    Nahe dran. InvoiceOverviewDataTable ist ein Klassenname. Du willst aber die Klasseninstanz. Daher nur InvoiceOverview verwenden.
    Also InvoiceOverviewDataSet.InvoiceOverview.AddInvoiceOverviewRow() - falls InvoiceOverviewDataSet auch der Name der Formular-tDS-Instanz ist!
    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.

    VaporiZed schrieb:

    ... - falls InvoiceOverviewDataSet auch der Name der Formular-tDS-Instanz ist!
    Daaa lag der Fehler bei mir! Irgendwie, warum auch immer war bei der tDS-Instanz der Name DataSet11 drin. Jetzt bekomme ich auch das .AddInvoiceOverviewRow aber kann da den String nicht einfügen. Der sagt dann
    Fehler BC30311 Der Wert vom Typ "String" kann nicht in "InvoiceOverviewDataSet.InvoiceOverviewRow" konvertiert werden.


    Und muss ich da vier Werte übergeben weil mein tDS vier Spalten hat? Oder lässt der die dann einfach leer wenn ich nichts eingebe?