Imports System.IO

<ToolboxBitmap(GetType(FolderTree), "FolderTree.bmp")> _
Public Class FolderTree
    Inherits System.Windows.Forms.UserControl

#Region " Windows フォーム デザイナで生成されたコード "

    Public Sub New()
        MyBase.New()

        ' この呼び出しは Windows フォーム デザイナで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後に初期化を追加します。
        SetInitialValue()

    End Sub

    ' UserControl1 は、コンポーネント一覧に後処理を実行するために dispose をオーバーライドします。
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    ' Windows フォーム デザイナで必要です。
    Private components As System.ComponentModel.IContainer

    ' メモ : 以下のプロシージャは、Windows フォーム デザイナで必要です。
    'Windows フォーム デザイナを使って変更してください。  
    ' コード エディタを使って変更しないでください。
    Friend WithEvents TreeView1 As System.Windows.Forms.TreeView
    Friend WithEvents ImageList1 As System.Windows.Forms.ImageList
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(FolderTree))
        Me.TreeView1 = New System.Windows.Forms.TreeView
        Me.ImageList1 = New System.Windows.Forms.ImageList(Me.components)
        Me.SuspendLayout()
        '
        'TreeView1
        '
        Me.TreeView1.ImageList = Me.ImageList1
        Me.TreeView1.Location = New System.Drawing.Point(8, 8)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.SelectedImageIndex = 1
        Me.TreeView1.TabIndex = 0
        '
        'ImageList1
        '
        Me.ImageList1.ImageSize = New System.Drawing.Size(16, 16)
        Me.ImageList1.ImageStream = CType(resources.GetObject("ImageList1.ImageStream"), System.Windows.Forms.ImageListStreamer)
        Me.ImageList1.TransparentColor = System.Drawing.Color.Transparent
        '
        'FolderTree
        '
        Me.Controls.Add(Me.TreeView1)
        Me.Name = "FolderTree"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private mRootPath As String
    Private mCurrentPath As String

    '表示するルートパスをあらわすプロパティ
    Public Property RootPath() As String
        Get
            Return mRootPath
        End Get
        Set(ByVal Value As String)
            mRootPath = Value
            'TreeViewのノードを作成
            SetTreeViewNodes(mRootPath)
        End Set
    End Property

    '現在選択されているパスの取得専用プロパティ
    Public ReadOnly Property CurrentPath() As String
        Get
            Return mCurrentPath
        End Get
    End Property

    'AfterSelectイベントを定義するデリゲートを宣言
    Public Delegate Sub AfterSelectEventHandler _
        (ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs)

    'AfterSelectイベントの宣言
    Public Event AfterSelect As AfterSelectEventHandler

    Protected Sub SetInitialValue()

        SetTreeViewPos()

    End Sub

    'TreeViewへルートノードを作成
    Private Sub SetTreeViewNodes(ByVal RootNode As String)

        With TreeView1

            'ノードをすべて削除
            .Nodes.Clear()

            'ルートパスから TreeNodeオブジェクトを作成
            Dim tnParent As TreeNode _
                        = New TreeNode(RootNode)

            'ルートノードを作成
            .Nodes.Add(tnParent)

            'ディレクトリを検索し、ノードを作成
            CreateNodes(tnParent)

            'オブジェクト変数を初期化
            tnParent = Nothing

        End With

    End Sub

    'ディレクトリを列挙しTreeViewへノードとして表示
    Private Sub CreateNodes(ByVal node As TreeNode)


        Try
            'ディレクトリを列挙するDirectoryInfoクラスの
            'インスタンスを作成
            Dim dInfo As DirectoryInfo _
                    = New DirectoryInfo(GetPath(node))

            '再描画を禁止し、高速化を図る
            TreeView1.BeginUpdate()

            'DirectoryInfoクラスのGetDirectoriesメソッドで
            'ディレクトリを列挙
            For Each di As DirectoryInfo In dInfo.GetDirectories

                'TreeViewへノードを作成
                Dim newNode As TreeNode = _
                            node.Nodes.Add(di.Name)

                'サブディレクトリが存在する場合は
                'ダミーノードを作成
                If IsSubDir(newNode) Then _
                        newNode.Nodes.Add("Dummy")

                'オブジェクト変数を初期化
                newNode = Nothing

            Next di

            '再描画禁止を解除
            TreeView1.EndUpdate()

            'オブジェクト変数を初期化
            dInfo = Nothing

        Catch ex As Exception

            '例外がI/Oエラーの場合
            If TypeOf ex Is IOException Then
                'MessageBox.Show(ex.Message.ToString)
            End If

        End Try

    End Sub

    '子ディレクトリが存在するか否かを返す
    Private Function IsSubDir(ByVal node As TreeNode) As Boolean

        Try
            'ディレクトリを列挙
            Dim dInfo As DirectoryInfo _
                    = New DirectoryInfo(GetPath(node))

            '存在する場合はTrueを返す
            If dInfo.GetDirectories.Length Then Return True

        Catch ex As Exception
        End Try

    End Function

    '指定されたノードのパスを返す
    Private Function GetPath(ByVal node As TreeNode) As String

        '親ノードが存在しない場合は、そのまま返す
        If node.Parent Is Nothing Then Return node.Text

        '親ノードが存在する場合は、再帰してルートまで辿り
        'パスを結合して返す
        Return Path.Combine(GetPath(node.Parent), node.Text)

    End Function

    'TreeViewの位置と大きさを変更
    Private Sub SetTreeViewPos()

        With TreeView1
            .Location = New System.Drawing.Point(0, 0)
            .Size = Size
        End With

    End Sub

    Private Sub FolderTree_Resize(ByVal sender As Object, _
            ByVal e As System.EventArgs) Handles MyBase.Resize

        SetTreeViewPos()

    End Sub

    Private Sub TreeView1_BeforeExpand(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) _
            Handles TreeView1.BeforeExpand

        'ノードをクリア
        e.Node.Nodes.Clear()

        'ディレクトリを検索し、ノードを作成
        CreateNodes(e.Node)

    End Sub

    'AfterSelectイベントを処理するイベントハンドラ
    Private Sub TreeView1_AfterSelect(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.TreeViewEventArgs) _
            Handles TreeView1.AfterSelect

        'CurrentPathプロパティの値を変更
        mCurrentPath = GetPath(e.Node)

        'イベントを発生させる
        RaiseEvent AfterSelect(Me, e)

    End Sub

End Class
