我写了一个程序,它在启动时从Active Directory加载计算机列表。这大约需要10秒钟。如果用户已使用特定主机作为参数启动程序,则应立即使用该程序。 因此,不要中断用户我想在另一个线程中加载计算机列表。问题是它写入一个也在主线程中使用的变量(计算机列表)。 你可能会想,我可以简单地使用一个临时变量,当它完成时会覆盖主变量。但我必须保留主要变量的现有数据。
'hosts list
Private Shared hosts As New SortedDictionary(Of String, HostEntry)
'Get all computers in Active Directory
'Will run in a extra thread
Private Delegate Sub GetADcomputersDelegate()
Private Sub GetADcomputers()
If Me.InvokeRequired Then
Me.Invoke(New GetADcomputersDelegate(AddressOf GetADcomputers), Nothing)
Else
lblStatusAD.Text = "Getting Computers..."
Try
Dim search As New DirectorySearcher(ActiveDirectory.Domain.GetCurrentDomain().GetDirectoryEntry(), "(objectClass=computer)")
For Each host As SearchResult In search.FindAll()
'AddHost creates a new HostEntry object and adds it to my "global" hosts variable
'It also checks if a host is already present in the list and only updates it.
AddHost(host.GetDirectoryEntry().Properties("cn").Value.ToLower(), host.GetDirectoryEntry().Properties("description").Value)
Next
Catch ex As Exception
Debug.WriteLine("GetADcomputers() Exception: " & ex.Message)
End Try
ThreadPool.SetMaxThreads(hosts.Count, hosts.Count)
Dim ah As String = activehost
'Fill my ListBox with the computers
lstHosts.DataSource = New BindingSource(hosts, Nothing)
'Select the computer that was selected before
UseHost(ah)
lblStatusAD.Text = ""
End If
End Sub
因此当GetADcomputers()
在自己的线程中运行时,主线程也会被阻塞。我猜是因为auf是hosts
变量。
那么我可以改变什么来让线程完成它的工作,之后应用更新的计算机列表而不会丢失旧hosts
列表中条目的数据?所有这一切都以快速有效的方式进行。
答案 0 :(得分:1)
那段代码非常错误。如果在辅助线程上调用该方法,则它会立即将调用回调到UI线程并在UI线程上执行所有操作。您应该做的是在辅助线程上执行所有后台工作,然后仅编组到UI线程以更新UI。
摆脱那个If...Else
块,然后让方法的整个主体在Else
块中成为当前的。接下来,识别与UI特定交互的所有行,并将每个行移除到他们自己的方法中。然后,为每个方法添加If...Else
块,以便只在UI线程上执行实际触摸UI的代码。
这是一个开始:
Private Sub GetADcomputers()
UpdateStatusADLabel("Getting Computers...")
Try
Dim search As New DirectorySearcher(ActiveDirectory.Domain.GetCurrentDomain().GetDirectoryEntry(), "(objectClass=computer)")
For Each host As SearchResult In search.FindAll()
'AddHost creates a new HostEntry object and adds it to my "global" hosts variable
'It also checks if a host is already present in the list and only updates it.
AddHost(host.GetDirectoryEntry().Properties("cn").Value.ToLower(), host.GetDirectoryEntry().Properties("description").Value)
Next
Catch ex As Exception
Debug.WriteLine("GetADcomputers() Exception: " & ex.Message)
End Try
ThreadPool.SetMaxThreads(hosts.Count, hosts.Count)
Dim ah As String = activehost
'Fill my ListBox with the computers
lstHosts.DataSource = New BindingSource(hosts, Nothing)
'Select the computer that was selected before
UseHost(ah)
lblStatusAD.Text = ""
End Sub
Private Sub UpdateStatusADLabel(text As String)
If lblStatusAD.InvokeRequired Then
lblStatusAD.Invoke(New Action(Of String)(AddressOf UpdateStatusADLabel), text)
Else
lblStatusAD.Text = text
End If
End Sub