Einfacher Explorer-TreeView

    • VB.NET

    Es gibt 16 Antworten in diesem Thema. Der letzte Beitrag () ist von Soraja.

      Einfacher Explorer-TreeView

      Ich habe hier jetzt schon mehrfach gelesen, dass jemand die Ordner auf seiner Festplatte in einem TreeView anzeigen lassen will, ungefähr so wie im Windows-Explorer. Hier möchte ich nun eine objektorientierte, einfache und performante Möglichkeit vorstellen, so etwas zu realisieren.
      Es gibt in diesem Forum bereits Anleitungen zum rekursiven Auflisten aller Ordner innerhalb eines Ordners, jedoch sind diese Codes für unser Vorhaben nicht geeignet, da sie die gesamte Festplatte auf einem auslesen würden. Dies wollen wir aber nicht, da wir sonst Stunden vor dem ladenden TreeView sitzen würden.
      Stattdessen laden wir immer nur das, was auch tatsächlich angezeigt wird. Dies habe ich gelöst, indem ich von TreeNode geerbt habe und in dieser neuen Klasse beim Expanden automatisch alle Unterordner lade.

      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports System.IO
      2. Public Class ExplorerTreeView : Inherits TreeView
      3. Public ReadOnly Property SelectedDirectory As DirectoryInfo
      4. Get
      5. If SelectedNode Is Nothing Then Return Nothing
      6. Return DirectCast(SelectedNode, ExplorerTreeNode).GetDirectory()
      7. End Get
      8. End Property
      9. Public Sub LoadFilesystem()
      10. For Each drive In DriveInfo.GetDrives()
      11. Nodes.Add(New DriveTreeNode(drive))
      12. Next
      13. End Sub
      14. Private MustInherit Class ExplorerTreeNode : Inherits TreeNode
      15. Private expanded As Boolean = False
      16. Friend Sub OnExpand()
      17. If Not expanded Then GenerateSubNodes()
      18. expanded = True
      19. End Sub
      20. Protected MustOverride Sub GenerateSubNodes()
      21. Friend MustOverride Function GetDirectory() As DirectoryInfo
      22. End Class
      23. Private Class DriveTreeNode : Inherits ExplorerTreeNode
      24. Private drive As DriveInfo
      25. Sub New(drive As DriveInfo)
      26. Me.drive = drive
      27. If drive.IsReady Then
      28. Text = String.Concat(drive.Name.Substring(0, 2), " ", drive.VolumeLabel)
      29. Nodes.Add("")
      30. Else
      31. Text = String.Concat(drive.Name.Substring(0, 2))
      32. End If
      33. End Sub
      34. Protected Overrides Sub GenerateSubNodes()
      35. Nodes.Clear()
      36. If drive.IsReady Then
      37. For Each dir In drive.RootDirectory.EnumerateDirectories()
      38. Try
      39. Nodes.Add(New DirectoryTreeNode(dir))
      40. Catch ex As UnauthorizedAccessException : End Try
      41. Next
      42. End If
      43. End Sub
      44. Friend Overrides Function GetDirectory() As DirectoryInfo
      45. If drive.IsReady Then Return drive.RootDirectory
      46. Return Nothing
      47. End Function
      48. End Class
      49. Private Class DirectoryTreeNode : Inherits ExplorerTreeNode
      50. Private dir As DirectoryInfo
      51. Sub New(dir As DirectoryInfo)
      52. Me.dir = dir
      53. Text = dir.Name
      54. Nodes.Add("")
      55. End Sub
      56. Protected Overrides Sub GenerateSubNodes()
      57. Nodes.Clear()
      58. For Each d In dir.EnumerateDirectories()
      59. Try
      60. Nodes.Add(New DirectoryTreeNode(d))
      61. Catch ex As UnauthorizedAccessException : End Try
      62. Next
      63. End Sub
      64. Friend Overrides Function GetDirectory() As DirectoryInfo
      65. Return dir
      66. End Function
      67. End Class
      68. Private Sub ExplorerTreeView_BeforeExpand(sender As Object, e As TreeViewCancelEventArgs) Handles Me.BeforeExpand
      69. DirectCast(e.Node, ExplorerTreeNode).OnExpand()
      70. End Sub
      71. End Class

      Wir haben hier zwei Arten von Knoten, einmal den normalen Ordnerknoten und einmal den Laufwerkknoten. Letztere werden vom TreeView selbst erstellt und stellen den Anfang des Baumes dar.
      Beide Knoten erben von der selben Basisklasse, damit sie von dem TreeView einheitlich behandelt werden können. Das TreeView macht den ausgewählten Ordner nach außen hin mit der Eigenschaft "SelectedDirectory" verfügbar, der Aufrufer kommt mit den einzelnen Knoten nicht in Kontakt.
      Geladen wird die Ordnerstruktur mit einem Aufruf von "LoadFilesystem()". Dies musste ich leider in eine extra Methode verschieben, da es im Konstruktor Komplikationen mit dem Designer gab, welcher die Knoten manuell hinzufügte. 8|

      Im Anhang findet ihr auch noch ein kleines Beispielprojekt, in dem ich auf Basis dieses Controls einen kleinen Explorer entworfen habe. Dank dieses Controls und DataBinding reduziert sich der Code in der Form auf effektiv 3 Zeilen.
      Dateien
      Naja. Aufgemacht auf nen leeres Laufwerk geklickt, erstmal NullReferenceException.

      Quellcode

      1. System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. bei SimpleExplorer.Form1.ExplorerTreeView1_AfterSelect(Object sender, TreeViewEventArgs e) in E:\Mathis\Dokumente\Visual Studio 2012\Projects\ExplorerTreeView\ExplorerTreeView\Form1.vb:Zeile 4. bei System.Windows.Forms.TreeView.OnAfterSelect(TreeViewEventArgs e) bei System.Windows.Forms.TreeView.TvnSelected(NMTREEVIEW* nmtv) bei System.Windows.Forms.TreeView.WmNotify(Message& m) bei System.Windows.Forms.TreeView.WndProc(Message& m) bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)



      Und ansonsten recht langsam. Vll. async laden?


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      Der Fehler kam bei mir auch, allerdings nur in der Console, das Programm ist normal weitergelaufen.
      Liegt wohl daran, dass der TreeView in so einem Fall Nothing/null zurückgibt und die BindingSource damit nicht klar kommt. Ich kenn mich mit Binding aber leider nicht gut genug aus, um zu wissen, was man da tun kann.
      Danke für Deine Arbeit.
      Ich hätte gern den Inhalt der Listbox ebenfalls im Treeview, was muss ich dafür anpassen?

      Gibts in WPF eine ähnliche Methode?

      Btw.:

      VB.NET-Quellcode

      1. System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt. bei SimpleExplorer.Form1.ExplorerTreeView1_AfterSelect(Object sender, TreeViewEventArgs e) in E:\Mathis\Dokumente\Visual Studio 2012\Projects\ExplorerTreeView\ExplorerTreeView\Form1.vb:Zeile 4. bei System.Windows.Forms.TreeView.OnAfterSelect(TreeViewEventArgs e) bei System.Windows.Forms.TreeView.TvnSelected(NMTREEVIEW* nmtv) bei System.Windows.Forms.TreeView.WmNotify(Message& m) bei System.Windows.Forms.TreeView.WndProc(Message& m) bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

      Der Fehler kommt bei mir ebenfalls. Vielleicht sollte man abfragen, ob das Laufwerk.ready ist oder nicht.

      Hutzi schrieb:

      Vielleicht sollte man abfragen, ob das Laufwerk.ready ist oder nicht.
      ->

      Quelltext schrieb:

      VB.NET-Quellcode

      1. If drive.IsReady Then

      Daran liegt es nicht, das tue ich bereits.

      Wie gesagt, ich glaube nicht, dass der Fehler an dem obigen Code liegt, sondern am DataBinding. Wenn man nämlich ein leeres Laufwerk auswählt, dann gibt der TreeView als SelectedDirectory Nothing zurück, womit die BindingSource nicht klar kommt. Ich kenne mich mit DataBinding aber leider nicht gut genug aus um zu wissen, wie man das lösen könnte.


      Wenn du die Dateien auch im TreeView haben willst, dann musst du dir halt noch eine neue Klasse anlegen, die von ExplorerTreeNode erbt und ein FileInfo-Objekt verwaltet. Im DirectoryTreeNode musst du dann zusätzlich zu den Unterordnern auch die Dateien auflisten und diese als Knoten hinzufügen.
      Allerdings funktioniert das zurückgeben des SelectedDirectory dann nicht mehr, das musst du dann auf FileSystemInfo ändern, damit du sowohl Dateien als auch Ordner zurückgeben kannst.
      Hallo ich hab eine frage zu dem Projekt ich bekomme es absolut nicht hin einzelne Items aus der Listbox zu löschen versucht habe ich schon folgendes.




      1.
      Dim bs As New BindingSource(New List(Of IO.FileInfo)(New IO.DirectoryInfo("K:\NEU\ExplorerTreeView").GetFiles()), Nothing)
      ListBox1.DataSource = bs

      2.
      'FileInfoBindingSource.RemoveCurrent()

      3.
      'FileInfoBindingSource.RemoveAt(ListBox1.SelectedIndex)

      4.
      'Me.FileInfoBindingSource.RemoveCurrent()
      'Me.FileInfoBindingSource.Position = Me.FileInfoBindingSource.Find("Name", ListBox1.SelectedItem)


      5.
      'Dim m_index As Integer
      'm_index = ListBox1.SelectedIndex
      'FileInfoBindingSource.List.RemoveAt(m_index)
      In der Bindingsource rumzupfuschen ist in der Regel keine gute Idee, führe die Änderungen stattdessen direkt an den dahinterliegenden Daten durch. In diesem Fall sind diese Daten einfach nur SelectedDirectory.GetFiles() (siehe Form1.vb Zeile 4).
      Erst mal danke für die schnelle Antwort leider versteh ich nicht so ganz wie das das Löschen erreiche, könntest du mir da bitte einen Denkanstoß geben. Wie gesagt ich möchte einzelne Items aus der Listbox löschen und so wie ich das jetzt verstanden habe, ist es der flache Ansatz es über die Listbox zu versuchen sondern direkt an dem TreeView anzusetzen.
      Was in der Listbox erscheint ist lediglich eine Auflistung von FileInfo-Objekten, diese Liste kommt aus dem Aufruf in Zeile 4.
      Wenn du Einträge aus dieser Liste entfernen möchtest, muss du sie halt zwischenspeichern, anstatt sie einfach nur an die Bindingsource zu übergeben, damit du jederzeit darauf zugreifen kannst. Zu empfehlen wäre eine BindingList<T> oder eine ObservableCollection<T>, damit die Bindingsource ordnungsgemäß aktualisiert wird.
      Leider hab ich das Problem immer noch nicht lösen können trotz der Infos, Ich denke ich sollte erwähnen das ich noch nicht so fortgeschritten bin in dem ganzen Thema, ich würde mich freuen wenn ihr euch noch einmal zeit nehmen könntet.
      Danke mfg
      Geile Sache :D

      Wie kann man eigentlich die Ausnahme Fehler in der Anwendung umgehen ?
      Sprich wenn ich einen Vorgang abbreche ?

      Catch and Try oder wie kann man das machen ??

      Danke :D
      Bilder
      • Unbenannt.PNG

        71,47 kB, 899×638, 323 mal angesehen
      :D Ein Programm sollte nicht nur Hand und Fuß, sondern auch Herz und Hirn haben. (Michael Anton) :D

      MFG Jörg ;)

      Muss jeder vermeintliche Programmierer ne Signatur haben ??
      Ich habe im Beispiel Projekt eine Datei angeklickt - und dann den Vorgang abgebrochen
      Bilder
      • hg.PNG

        86,58 kB, 882×657, 355 mal angesehen
      • Unbenannt.PNG

        60,78 kB, 840×620, 328 mal angesehen
      :D Ein Programm sollte nicht nur Hand und Fuß, sondern auch Herz und Hirn haben. (Michael Anton) :D

      MFG Jörg ;)

      Muss jeder vermeintliche Programmierer ne Signatur haben ??