Verständnisfrage, Listbox Auflistung

  • VB.NET

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von samson.

    Verständnisfrage, Listbox Auflistung

    Moin Moin Zusammen,

    ich bin mal wieder Blind vor Code...
    Ich möchte alle Dateien im Ordner ausgeben lassen, (was auch geht) jedoch ohne Pfadangaben...



    Verwendeter Code:

    Quellcode

    1. Private Sub list_files()
    2. ListBox1.Items.Clear()
    3. For Each Datei As String In My.Computer.FileSystem.GetFiles(FileSystemWatcher1.Path, FileIO.SearchOption.SearchTopLevelOnly)
    4. ListBox1.Items.Add(Datei)
    5. Next
    6. End Sub


    Zudem wäre interessant für mich, wie ich das realisiert bekomme, das zudem noch Dateiinformationen in einer weiteren "Spalte" angezeigt werden können...

    Grüße Stefan alias SaMsOn
    Nein! Doch! OHH!
    @samson Ganz einfach.
    Lies nicht Dateinamen ein, sondern FileInfo-Instanzen:

    VB.NET-Quellcode

    1. Dim fi() = New DirectoryInfo("c:\Temp").GetFiles("*.*", TopDirectoryOnly)
    2. ListBox1.DataSource = fi
    3. ListBox1.DisplayMember = "Name" ' Name der Property, die angezeigt werden soll, kann dynamisch geändert werden
    (nicht getestet)
    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!
    Hallo @samson

    Ich habs jetzt zum demontrieren als Stringausführung gemacht. Das kann man ganz sicher noch verbessern.

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Imports System.IO
    4. Public Class Form1
    5. Dim fi() As FileInfo
    6. Private sb As New SolidBrush(Color.Black)
    7. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    8. Me.ListBox1.DrawMode = DrawMode.OwnerDrawFixed
    9. Me.fi = New DirectoryInfo("C:\MyFolder").GetFiles("*", SearchOption.AllDirectories)
    10. Me.ListBox1.DataSource = fi
    11. End Sub
    12. Private Sub ListBox1_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles ListBox1.DrawItem
    13. If e.Index < 0 Then Return
    14. e.DrawBackground()
    15. Me.sb.Color = e.ForeColor
    16. Dim s As String = Me.fi(e.Index).Name & vbTab & _
    17. Me.fi(e.Index).Length.ToString & vbTab & _
    18. Me.fi(e.Index).LastAccessTimeUtc.ToString
    19. Dim sf As New StringFormat
    20. sf.SetTabStops(0, New Single() {200, 100})
    21. e.Graphics.DrawString(s, e.Font, sb, e.Bounds, sf)
    22. If CBool(e.State And DrawItemState.Focus) Then
    23. e.DrawFocusRectangle()
    24. End If
    25. End Sub
    26. End Class


    Freundliche Grüsse

    exc-jdbi

    samson schrieb:

    Zudem wäre interessant für mich, wie ich das realisiert bekomme, das zudem noch Dateiinformationen in einer weiteren "Spalte" angezeigt werden können...

    Falls Du nicht auf ne ListBox fixiert bist, nimm doch gleich ein passendes, weil dafür geeignetes, mehrspaltiges CE. Da bietet sich das ListView (schließlich wird das ja auch in Windows dafür verwendet; eine der wenigen Ausnahmen, bei dem ich ein LV akzeptieren könnte) oder besser gleich das DGV an.
    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.
    @exc-jdbi Danke für den Beispielcode, werde ich mir mal anschauen.
    @VaporiZed Danke für den Tipp... An Listview hab ich noch garnicht gedacht.

    Hintergrund warum ich das brauche...
    Wir haben in der Firma ein Ordner, in den ständig neue PDFs gepackt werden.
    Diese muss ich dann abarbeiten... Da der Pfad aber extrem kompliziert auf einem NW-Laufwerk liegt hab ich mir das kurz zusammen gestrickt...
    Damit ich aber auch immer das älteste zuerst habe, dacht ich mir ich bau das so ein, das es gleich sortiert ist.

    Grüße Stefan alias SaMsOn
    Nein! Doch! OHH!
    Da kann ich nur empfehlen auf eine DGV oder ListView auszuweichen. Bei beiden Controls kann man mit einem Mausklick, die Sortierung über den Columntitel machen. Bedingt aber, dass das relevante Datum in einer der Column erfasst ist.

    Ich bin mir fast sicher, hier im Forum gibt es sogar Beispiele von deinem vorhaben. Gesucht habe ich aber nicht.

    Edit: Jetzt ist mir gerade noch was eingefallen. Es würde sich auch über eine ListBox realisieren, wenn du auf die Mehrspaltigkeit verzichten würdest. Man könnte die Fileinfos in die ListBox einspielen, und die gewünschten Displaymembers in eine ComboBox.
    So ist es auch möglich an die gewünschten Infos zu kommen, bedingt aber, das noch eine Sort-Routine geschrieben wird.
    Ich denke jedoch die Vorteile der ListView oder DGV darf man auf ekinem Fall vernachlässigen.


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi Danke für die Tips... Habe mit DGV noch nie was gemacht... Ist das kompliziert?
    Ich brauche ja eigentlich nur den Dateinamen und das Erstellungsdatum der Datei, wenn ich es dann in der Liste doppelt anklicke, soll die Datei aufgehen.
    Den Pfad den der FileSystemWatcher überwacht hab ich in den Einstellungen von My.Settings.CheckDir.
    Grüße Stefan

    EDIT:
    Habe mir gerade mal DataGridView angeschaut, das ist ganz und garnicht das was ich gebrauchen kann.
    ListView ist perfekt für mein Vorhaben.
    Erstmal danke... Ich google mal, wenn was ist, meld ich mich hier wieder ;)
    Nein! Doch! OHH!

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

    Genau so etwas, wie im Link von EDR habe ich oben gemeint.

    Eine ListView-Varaiante lässt sich sicher auch einfach bewerkstelligen. Ich glaube bei dieser Variante müsste man noch die Column-Sortierung selber schreiben, was aber mit einer ICompare-Implementierung leicht sein sollte.
    Die DGV-Varainte hat sie meines erwachtens schon drin.

    Bei der ListView Variante geht das etwa so
    - Die Fileinfos in eine öffentliche Varriable ListOfT oder FileInfo-Array
    - Dann die Column setzen (z.B. Namen, LastAccess etc)
    - Die ListView befüllen (BeginnUpdate, EndUpdate). Eventuell eine Subroutine um die SubItems zu befüllen
    - Die ColumnHeader noch an die Textlängen anpassen

    Für die Sortierung, sofern sie noch nicht dabei ist. Hier.
    Dieses Beispiel könnte man sogar übernehmen. Einfach bei der Sub New noch den Type und Sortierungsform mitgeben.

    Die DoppelClick-Event sollte auch einfach sein. Da ja durch FileInfos der vollständige Pfad bekannt ist.
    Process.Start wäre hier ein Stichwort.

    um die Column zu erstellen

    VB.NET-Quellcode

    1. Private Sub SetLvColumn()
    2. With Me.LvMain
    3. .Items.Clear()
    4. With .Columns
    5. .Clear() : .Add("Name")
    6. .Add("Length") : .Add("LastAccess")
    7. End With
    8. .View = View.Details
    9. .FullRowSelect = True
    10. .HideSelection = False
    11. End With
    12. End Sub


    Um die Daten der ListOfT in die Listview zu bekommen

    VB.NET-Quellcode

    1. Private Sub SetListView()
    2. If (Me.lstFI IsNot Nothing) AndAlso (Me.lstFI.Count > 0) Then
    3. With Me.LvMain
    4. .BeginUpdate()
    5. '.MultiSelect = True
    6. .Items.Clear()
    7. lstFI.ForEach(New Action(Of FileInfo)(AddressOf ItemList))
    8. For Each ch As ColumnHeader In .Columns
    9. ch.Width = -2
    10. Next
    11. .EndUpdate()
    12. End With
    13. End If
    14. End Sub
    15. Private Sub ItemList(ByVal lvi As FileInfo)
    16. Dim LvItem As New ListViewItem(lvi.Name)
    17. With LvItem.SubItems
    18. .Add(lvi.Length.ToString)
    19. .Add(lvi.LastAccessTimeUtc.ToString)
    20. End With
    21. Me.LvMain.Items.Add(LvItem)
    22. End Sub


    Sortierung der Column
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub LvMain_ColumnClick(ByVal sender As Object, ByVal e As ColumnClickEventArgs) Handles LvMain.ColumnClick
    2. Me.ColumnSort(e.Column)
    3. End Sub
    4. Private Sub ColumnSort(ByVal columnindex As Int32)
    5. Dim lastcolumn As Int32 = -1
    6. Dim col As Int32 = columnindex
    7. 'Sortierung umkehren
    8. If Not sortord = SortOrder.Ascending Then
    9. sortord = SortOrder.Ascending
    10. Else : sortord = SortOrder.Descending
    11. End If
    12. Dim typ As Type = GetColumnType(col)
    13. Me.LvMain.ListViewItemSorter = New ListViewItemComparer(col, typ, sortord)
    14. End Sub


    VB.NET-Quellcode

    1. Public Class ListViewItemComparer
    2. Implements IComparer
    3. Private type As Type, col As Int32, sortorder As SortOrder
    4. Public Sub New(ByVal column As Int32, ByVal typ As Type, ByVal sortord As SortOrder)
    5. Me.col = column : Me.type = typ : Me.sortorder = sortord
    6. End Sub
    7. Public Function Compare(ByVal x As Object, ByVal y As Object) As Int32 Implements IComparer.Compare
    8. If GetType(String) = type Then
    9. If sortorder = sortorder.Ascending Then
    10. Return [String].Compare(CType(x, ListViewItem).SubItems(col).Text, CType(y, ListViewItem).SubItems(col).Text)
    11. Else : Return [String].Compare(CType(y, ListViewItem).SubItems(col).Text, CType(x, ListViewItem).SubItems(col).Text)
    12. End If
    13. End If
    14. If GetType(Int32) = type Then
    15. If sortorder = sortorder.Ascending Then
    16. Return Decimal.Compare(CDec(CType(x, ListViewItem).SubItems(col).Text), CDec(CType(y, ListViewItem).SubItems(col).Text))
    17. Else : Return Decimal.Compare(CDec(CType(y, ListViewItem).SubItems(col).Text), CDec(CType(x, ListViewItem).SubItems(col).Text))
    18. End If
    19. End If
    20. If GetType(Date) = type Then
    21. If sortorder = sortorder.Ascending Then
    22. Return Date.Compare(CDate(CType(x, ListViewItem).SubItems(col).Text), CDate(CType(y, ListViewItem).SubItems(col).Text))
    23. Else : Return Date.Compare(CDate(CType(y, ListViewItem).SubItems(col).Text), CDate(CType(x, ListViewItem).SubItems(col).Text))
    24. End If
    25. End If
    26. Return -1
    27. End Function
    28. End Class



    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Ich hab die DGV-Variante noch nicht angeschaut.

    Bei der ListView-Version könnte man eine Bindung über Bindungslist (System.ComponentModel) + BindingContext realisieren, und das zu einem CurrencyManager casten.

    VB.NET-Quellcode

    1. Dim cm = TryCast(LV.BindingContext(BindingList(Of FileInfo)), CurrencyManager)


    Mit cm.GetItemProperties() und cm.List hat man alle Daten die notwendig sind, um ColumnHeader zu erstellen, sofern sie nicht mit dem Designer gemacht worden sind. Auch die SubItems der ListViewItem lassen sich mit diesen Propertiesfüllen. Das Text-Property kann leider jedoch nur als String bestückt werden. Sofern das Object (hier FileInfo) rein muss, sehe ich nur den Weg über das Tag-Property. So sind dann auch alle Daten wenn notwendig im ListViewItem und sofort griffbereit.

    Man könnte natürlich auch ein eigenes ListView machen, das wiederum finde ich ein sehr umständlicher Weg, hat aber den Vorteil, dass dann auch Objects übergeben werden können. Der Aufwand ist aber enorm.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    @ErfinderDesRades, @exc-jdbi
    Danke erstmal für die ganzen Antwort. Danke danke danke...!
    Nur bitte beachtet,... ich möchte "NUR" eine Liste der Dateien in einem Verzeichnis auflisten mit dem Erstellungsdatum der Datei...
    Bei neuer Datei soll diese mit aufgelistet werden (SystemFileWatcher-Events)
    Und die gelisteten Dateien möchte ich mit einem doppelklick öffnen können... (Process.Start("Pfad zur Datei/Datei"))

    Muss ich da wirklich eine riesen Aufriss mit DGV machen?
    Ist das nicht überzogen?
    Nein! Doch! OHH!
    Guten Abend @samson

    In #9 habe ich alles schon geschrieben was es braucht für eine Listview. Ok es sind bei dem Beispiel 3 Spalten (name, Length, LastAccessTimeUtc) aber vom Prinzip her ist alles genau gleich. Die Grundbasis zum holen der pdf-Dateien hat RFG schon geschrieben in #2

    VB.NET-Quellcode

    1. Private lstFI As List(Of FileInfo)
    2. Private sortord As SortOrder = SortOrder.Ascending
    3. Private PropertyColumn() As String = {"Name", "Length", "LastAccessTimeUtc"}
    4. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    5. Dim fi = New DirectoryInfo("MyFolder").GetFiles("*.pdf", SearchOption.AllDirectories)
    6. Me.lstFI = New List(Of FileInfo)(fi)
    7. Me.SetLvColumn()
    8. Me.SetListView()
    9. Me.SetColumnType()
    10. End Sub

    VB.NET-Quellcode

    1. Private Sub LvMain_MouseDoubleClick(ByVal sender As Object, ByVal e As MouseEventArgs) Handles LvMain.MouseDoubleClick
    2. Dim tag = DirectCast(sender, ListView).SelectedItems(0).SubItems(0).Tag
    3. Dim fullname = DirectCast(tag, FileInfo).FullName
    4. Process.Start(fullname)
    5. End Sub

    Hast du es den schon probiert?
    @exc-jdbi
    Bin gerade dabei :)
    Hab mir den Code von Dir nochmal angesehen... irgendwo hab ich schon wieder Grütze im Kopf...

    Sollte ich nicht besser

    Quellcode

    1. Dim fi = New DirectoryInfo("MyFolder").GetFiles("*.pdf", SearchOption.AllDirectories)
    2. Me.lstFI = New List(Of FileInfo)(fi)
    3. Me.SetLvColumn()
    4. Me.SetListView()
    5. Me.SetColumnType()

    in den Event setzen bei Änderungen im Ordner?
    Nein! Doch! OHH!

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

    Wie meist du das mit em Event? Meinst du etwas das kontinuirlich nachfragt, ob es aktuelle pdf's gibt?
    Man könnte einen Button machen, den man klicken kann, um die Liste zu aktualisieren.

    in diesem Falle nur diese drei Zeilen.
    Dim fi = New DirectoryInfo("MyFolder").GetFiles("*.pdf", SearchOption.AllDirectories)
    Me.lstFI = New List(Of FileInfo)(fi)
    Me.SetListView()

    In die Funktion Me.SetListView() müsste dann noch ganz am Anfang
    Me.LvMain.Items.Clear()
    Damit die Items komplett gecleart werden.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi Danke nochmal...

    ich hab es jetzt einfach mal komplett zusammenkopiert (aus mehreren Projektdateien)
    Warum auch immer will er den Fetzen Me.SetColumnType() nicht nehmen.

    Zudem gefällt Ihm das nicht Dim typ As Type = ColumnStyle(col)
    VB kennt "ColumnStyle(col)" nicht. wenn ich die Zeilen auskommentiere gehts.

    ich hab die Zeilen

    Quellcode

    1. Dim fi = New DirectoryInfo("C:\Users\KellerKinder\Downloads").GetFiles("*.pdf", SearchOption.AllDirectories)
    2. Me.lstFI = New List(Of FileInfo)(fi)
    3. Me.SetLvColumn()
    4. Me.SetListView()

    jetzt in einen Private Sub reload() gepackt und in die Events


    Quellcode

    1. Private Sub reload()
    2. Dim fi = New DirectoryInfo(My.Settings.CheckFolder).GetFiles("*.pdf", SearchOption.TopDirectoryOnly)
    3. Me.lstFI = New List(Of FileInfo)(fi)
    4. Me.SetLvColumn()
    5. Me.SetListView()
    6. 'Me.SetColumnType()
    7. End Sub
    8. Private Sub FSW_Changed(sender As Object, e As FileSystemEventArgs) Handles FSW.Changed
    9. reload()
    10. End Sub
    11. Private Sub FSW_Created(sender As Object, e As FileSystemEventArgs) Handles FSW.Created
    12. reload()
    13. End Sub
    14. Private Sub FSW_Deleted(sender As Object, e As FileSystemEventArgs) Handles FSW.Deleted
    15. reload()
    16. End Sub
    17. Private Sub FSW_Renamed(sender As Object, e As FileSystemEventArgs) Handles FSW.Renamed
    18. reload()
    19. End Sub


    Ich hab irgendwie das Gefühl das es to much Code ist für das Vorhaben...
    Irre ich mich?
    Lassen wir mal die Sortierung der Spalten ausser acht...
    Wenn ich in dem ListView Element die Spalten
    "Dateiname", "Erstellt", "Dateigröße"
    von hand anlege, muss ich doch nur über eine Schleife die Daten laden.
    ListView.Items.Add("Dateiname", "Erstellt", "Größe")
    ?!?!
    Nein! Doch! OHH!

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

    Die Me.SetLvColumn() würde ich nur einmal setzen, und das ganz am Anfang. Genau so auch die 'Me.SetColumnType() die ist oben noch nicht geschrieben wird aber gebraucht um die Sortierung nachher problemlos durchführen zu können. Man könnte beide in den Konstrukter verlegen, oder per Designer machen.


    Die Funktion Me.SetColumnType()

    VB.NET-Quellcode

    1. 'Irgend eine Datei, die es ganz sicher immer gibt.
    2. 'Ist leider notwending, da min 1x für die Erkennung
    3. 'des Types eine FileInfo-Instanz gemacht werden muss
    4. Dim fis As New FileInfo(Application.ExecutablePath)
    5. Dim prop = fis.GetType.GetProperties
    6. For i As Int32 = 0 To Me.PropertyColumn.Length - 1
    7. For j As Int32 = 0 To prop.Count - 1
    8. If prop(j).Name = Me.PropertyColumn(i) Then
    9. Me.LvMain.Columns(i).Tag = prop(j).PropertyType
    10. Exit For
    11. End If
    12. Next
    13. Next


    VB.NET-Quellcode

    1. Private Function GetColumnType(ByVal col As Int32) As Type
    2. Return DirectCast(Me.LvMain.Columns(col).Tag, Type)
    3. End Function


    VB.NET-Quellcode

    1. Private Sub ItemList(ByVal lvi As FileInfo)
    2. Dim lvitem As New ListViewItem(lvi.Name)
    3. lvitem.Tag = lvi
    4. With lvitem.SubItems
    5. .Add(lvi.Length.ToString)
    6. .Add(lvi.LastAccessTimeUtc.ToString)
    7. lvitem.SubItems(0).Tag = lvi
    8. lvitem.SubItems(1).Tag = lvi
    9. End With
    10. Me.LvMain.Items.Add(LvItem)
    11. End Sub
    12. Private Sub SetLvColumn()
    13. With Me.LvMain
    14. .Items.Clear()
    15. With .Columns
    16. .Clear() : .Add("Name")
    17. .Add("Length") : .Add("LastAccess")
    18. End With
    19. .Columns(0).Tag = Me.PropertyColumn(0)
    20. .Columns(1).Tag = Me.PropertyColumn(1)
    21. .Columns(2).Tag = Me.PropertyColumn(2)
    22. .View = View.Details
    23. .FullRowSelect = True
    24. .HideSelection = False
    25. End With
    26. End Sub


    Wenn natürlich noch Löschen und Umbenennen dazu kommt, finde ich den Weg über Reload ganz gut.
    Was ist FSW.Created? Und wann kommt FSW.Changed

    So jetzt sollte alles vorhan sein. damit das gelöst werden kann. Viel Erfolg noch. Ich geh mal schlafen.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi Danke du auch.
    Ich such aktuell nach der einfachsten aller sachen...
    Alle Dateien auslesen... ok ... geht.
    Dim fi() = New DirectoryInfo(My.Settings.CheckFolder).GetFiles("*.pdf", SearchOption.TopDirectoryOnly)
    ich bekomm es aktuell nur nicht hin die Daten vernüftig aufbereitet in die dafür vorgesehenen Spalten zu packen...
    Ich scheiter gerade sogar schon an der einfachen liste...
    Es wird Zeit.
    Nein! Doch! OHH!