我有一個非常簡單的形式與一個按鈕,激發我創建的一個從ActiveDirectory收集數據並將其添加到Excel工作表。VB.NET - 在單獨的線程中工作,以防止掛起形式
問題是,當我點擊這個按鈕時,整個表單都會掛起。所以我認爲收集數據並將其添加到Excel工作表的操作應該在它自己的線程中運行,以便表單不會掛起。可能還會增加一個進度條。 但是,進度條位於運行項目後啓動的主用戶窗體中。
爲了按照我想要的方式獲得此功能,我需要做些什麼?
編輯:添加了一些我的代碼。我有一個MainForm.vb和一個CodeFile.vb。 我希望CodeFile.vb中的大部分代碼更整潔。
MainForm.vb
Imports User_edit.CodeFile
Imports System.ComponentModel
Public Class MainForm
Private Sub btnImportData_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnImportData.Click
If MyBackgroundWorker.IsBusy <> True Then
MyBackgroundWorker.RunWorkerAsync()
End If
End Sub
Private Sub BackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles MyBackgroundWorker.DoWork
ExportADUsers()
End Sub
Private Sub BackgroundWorker_ProgressChanged(ByVal sender As System.Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles MyBackgroundWorker.ProgressChanged
statusBarLabel.Text = (e.ProgressPercentage.ToString)
End Sub
Private Sub BackgroundWorker_RunWorkerCompleted(ByVal sender As System.Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles MyBackgroundWorker.RunWorkerCompleted
statusBarLabel.Text = "Finished"
End Sub
End Class
CodeFile.vb
Imports System.DirectoryServices
Imports System.ComponentModel
Imports System.Threading
Module CodeFile
Public Sub ExportADUsers()
MainForm.MyBackgroundWorker.WorkerReportsProgress = True
MainForm.MyBackgroundWorker.WorkerSupportsCancellation = True
Dim i As Integer
Dim objRootDSE, strRoot, strfilter, strAttributes, strScope
objRootDSE = GetObject("LDAP://RootDSE")
strRoot = objRootDSE.GET("DefaultNamingContext")
strfilter = "(&(objectCategory=Person)(objectClass=User))"
strAttributes = "mail,userPrincipalName,givenName,sn," & _
"initials,displayName,physicalDeliveryOfficeName," & _
"telephoneNumber,mail,wWWHomePage,profilePath," & _
"scriptPath,homeDirectory,homeDrive,title,department," & _
"company,manager,homePhone,pager,mobile," & _
"facsimileTelephoneNumber,ipphone,info," & _
"streetAddress,postOfficeBox,l,st,postalCode,c"
'Scope of the search. Change to "onelevel" if you didn't want to search child OU's
MainForm.statusBarLabel.Text = "Collecting data"
strScope = "subtree"
Dim cn, cmd, rs
cn = CreateObject("ADODB.Connection")
cmd = CreateObject("ADODB.Command")
cn.open("Provider=ADsDSOObject;")
cmd.ActiveConnection = cn
cmd.commandtext = "<LDAP://" & strRoot & ">;" & strfilter & ";" & _
strAttributes & ";" & strScope
rs = cmd.EXECUTE
Dim objExcel, objWB, objSheet
objExcel = CreateObject("Excel.Application")
objWB = objExcel.Workbooks.Add
objSheet = objWB.Worksheets(1)
For i = 0 To rs.Fields.Count - 1
MainForm.MyBackgroundWorker.ReportProgress(i * 10)
objSheet.Cells(1, i + 1).Value = rs.Fields(i).Name
objSheet.Cells(1, i + 1).Font.Bold = True
Next
Dim strExportFile
strExportFile = "C:\users\vsando\desktop\export.xls"
objSheet.Range("A2").CopyFromRecordset(rs)
objSheet.SaveAs(strExportFile)
'Clean up
rs.Close()
cn.Close()
objSheet = Nothing
objWB = Nothing
objExcel.Quit()
objExcel = Nothing
End Sub
通知的ExportFromAD
子,我在CodeFile.vb
了。這是實際上正在做的工作。在每個將數據添加到Excel的循環中,我已經放置了MainForm.MyBackgroundWorker.ReportProgress(i * 10)
。
問題是,它實際上並沒有更新表單上的標籤。我發現這很奇怪,因爲表單並沒有真正懸掛或任何東西。它試圖訪問一個不同的線程或東西?意思是,表單是在它自己的線程上運行的,無法從我的第二個線程訪問它?
你已經在你的標籤中得到了答案:最簡單的方法是使用'BackgroundWorker'組件。 [MSDN上的示例實現](http://msdn.microsoft.com/zh-cn/library/system.componentmodel.backgroundworker.aspx)已經非常好。 – 2011-05-09 11:31:44
從示例代碼:'If(worker.CancellationPending = True)Then' ... yuck!然而,他們再次讓實習生寫下榜樣。 – 2011-05-09 11:33:28
@Konrad:Yuck,我同意。但更有可能的是,他們妄圖「澄清」代碼。 – 2011-05-09 11:49:48