Detecting when a treeview loads nodes?

2019-06-09 14:36发布

问题:

My application uses a treeview to load a directory of files from a folder. But depending on the folder, it may take a while for the treeview to load so my program appears to freeze and the treeview is blank for some time but that is not the case. It just takes a longer time to load for larger folders. But I want to show a picturebox with an animated GIF in it to let the user know that everything is ok and they just need to wait. The problem is, I can't seem to find the event for this to happen. I have tried everything I can and even searched on Google for the answer to no success. Any help would be appreciated. Thank you.

Code:

 Private Sub PopulateTreeView(ByVal dir As String, ByVal parentNode As TreeNode)

  picturebox3.visible = true 

        Dim folder As String = String.Empty
        Try
            'Add folders to treeview
            Dim folders() As String = IO.Directory.GetDirectories(dir)
            If folders.Length <> 0 Then
                Dim folderNode As TreeNode = Nothing
                Dim folderName As String = String.Empty
                For Each folder In folders
                    folderName = IO.Path.GetFileName(folder)
                    folderNode = parentNode.Nodes.Add(folderName)
                    folderNode.Tag = "folder"
                    folderNode.Name = "folder"
                    PopulateTreeView(folder, folderNode)
                Next
            End If

            'Add the files to treeview
            Dim files() As String = IO.Directory.GetFiles(dir)
            TreeView1.Nodes(0).Tag = "folder"
            TreeView1.Nodes(0).Name = "folder"
            If files.Length <> 0 Then
                Dim fileNode As TreeNode = Nothing
                For Each file As String In files
                    fileNode = parentNode.Nodes.Add(IO.Path.GetFileName(file))
                    fileNode.Tag = "file"
                    If file.Contains(".html") Or file.Contains(".htm") Or file.Contains(".HTML") Or file.Contains(".HTM") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(1)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(1)
                        fileNode.Name = "html"
                    ElseIf file.Contains(".css") Or file.Contains(".CSS") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(2)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(2)
                        fileNode.Name = "css"
                    ElseIf file.Contains(".js") Or file.Contains(".JS") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(3)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(3)
                        fileNode.Name = "js"
                    ElseIf file.Contains(".php") Or file.Contains(".PHP") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(4)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(4)
                        fileNode.Name = "php"
                    ElseIf file.Contains(".png") Or file.Contains(".PNG") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(5)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(5)
                        fileNode.Name = "png"
                    ElseIf file.Contains(".bmp") Or file.Contains(".BMP") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(6)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(6)
                        fileNode.Name = "bmp"
                    ElseIf file.Contains(".gif") Or file.Contains(".GIF") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(7)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(7)
                        fileNode.Name = "gif"
                    ElseIf file.Contains(".jpg") Or file.Contains(".jpeg") Or file.Contains(".JPG") Or file.Contains(".JPEG") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(8)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(8)
                        fileNode.Name = "jpg"
                    ElseIf file.Contains(".txt") Or file.Contains(".TXT") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(9)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(9)
                        fileNode.Name = "txt"
                    ElseIf file.Contains(".ttf") Or file.Contains(".TTF") Or file.Contains(".otf") Or file.Contains(".OTF") Then
                        fileNode.ImageKey = ImageList1.Images.Keys(10)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(10)
                        fileNode.Name = "font"
                    Else
                        fileNode.ImageKey = ImageList1.Images.Keys(11)
                        fileNode.SelectedImageKey = ImageList1.Images.Keys(11)
                        fileNode.Name = "other"
                    End If
                Next
            End If

        Catch ex As UnauthorizedAccessException
            parentNode.Nodes.Add("Access Denied")
        End Try

回答1:

first Don't use background worker try task, thread or async

I upgrade abit and add onExpand event so you don't need load all hardrive at one run. each root after expand

there is also sample of Threat, when you update via threat you need use Invoke if not cross threat will shows up. Is not save in 100%. You have base

Private Sub TreeView1_BeforeExpand(sender As Object, e As TreeViewCancelEventArgs) Handles TreeView1.BeforeExpand
    Dim tr = New Threading.Thread(AddressOf ExpandNode)
    tr.Start(e.Node)
End Sub
Sub UpNode(e As TreeNode, onNod As TreeNode())
    e.Nodes.Clear()
    e.Nodes.AddRange(onNod)
End Sub
Public Sub ExpandNode(e As TreeNode)
    Dim l = PopulateTreeView(e.Tag)
    Me.Invoke(Sub() UpNode(e, l))
End Sub

Private Function PopulateTreeView(ByVal dir As String) As TreeNode()
    Dim Li As New List(Of TreeNode)
    Dim folder As String = String.Empty
    Try
        'Add folders to treeview
        Dim folders() As String = IO.Directory.GetDirectories(dir)
        If folders.Length <> 0 Then
            For Each folder In folders
                Dim Ndir = New TreeNode
                Ndir.Tag = folder
                Ndir.Text = System.IO.Path.GetFileName(folder)
                Ndir.Nodes.Add(".")
                Li.Add(Ndir)
            Next
        End If

        'Add the files to treeview
        Dim files() As String = IO.Directory.GetFiles(dir)
        If files.Length <> 0 Then
            Dim fileNode As TreeNode = New TreeNode
            For Each file As String In files
                fileNode.Tag = file
                fileNode.Text = System.IO.Path.GetFileName(file)
                If file.Contains(".html") Or file.Contains(".htm") Or file.Contains(".HTML") Or file.Contains(".HTM") Then
                    fileNode.Name = "html"
                ElseIf file.Contains(".css") Or file.Contains(".CSS") Then
                    fileNode.Name = "css"
                ElseIf file.Contains(".js") Or file.Contains(".JS") Then
                    fileNode.Name = "js"
                ElseIf file.Contains(".php") Or file.Contains(".PHP") Then
                    fileNode.Name = "php"
                ElseIf file.Contains(".png") Or file.Contains(".PNG") Then
                    fileNode.Name = "png"
                ElseIf file.Contains(".bmp") Or file.Contains(".BMP") Then
                    fileNode.Name = "bmp"
                ElseIf file.Contains(".gif") Or file.Contains(".GIF") Then
                    fileNode.Name = "gif"
                ElseIf file.Contains(".jpg") Or file.Contains(".jpeg") Or file.Contains(".JPG") Or file.Contains(".JPEG") Then
                    fileNode.Name = "jpg"
                ElseIf file.Contains(".txt") Or file.Contains(".TXT") Then
                    fileNode.Name = "txt"
                ElseIf file.Contains(".ttf") Or file.Contains(".TTF") Or file.Contains(".otf") Or file.Contains(".OTF") Then
                    fileNode.Name = "font"
                Else
                    fileNode.Name = "other"
                End If
            Next
            Li.Add(fileNode)
        End If

    Catch ex As UnauthorizedAccessException
        Li.Add(New TreeNode With {.Tag = Nothing, .Name = "Access Denied"})
    End Try
    Return Li.ToArray
End Function

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim Node = New TreeNode
    Node.Tag = "C:\"
    Node.Text = "C:"
    Node.Nodes.Add(".")
    TreeView1.Nodes.Add(Node)
End Sub


回答2:

You can use Async / Await pattern to load data at a different thread without freezing UI and then add data to tree.

Also when adding nodes to tree, use AddRange or if you add one by one, call BeginUpdate before first node, and EndUpdate after last node. For example you can see how I added two nodes by making a 5 seconds dummy delay in a different thread without freezing UI:

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Await AddNodes()
End Sub

Private Async Function AddNodes() As Task
    PictureBox1.Show()
    PictureBox1.Update()
    Await Task.Delay(5000)
    Dim Nodes = New List(Of TreeNode)() From {New TreeNode("1"), New TreeNode("2")}
    TreeView1.Nodes.AddRange(Nodes.ToArray())
    PictureBox1.Hide
End Function