问题
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
来源:https://stackoverflow.com/questions/51058730/detecting-when-a-treeview-loads-nodes