我有一个非常简单的表单,其中包含一个触发我创建的Sub的按钮,该按钮从ActiveDirectory收集数据并将其添加到Excel工作表中。
问题是,当我点击此按钮时,整个表单都会挂起。所以我认为收集数据并将其添加到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
子信息。这就是实际做的工作。在For each循环中,将数据添加到Excel是我放置MainForm.MyBackgroundWorker.ReportProgress(i * 10)
的位置。
问题是,它实际上并没有更新表单上的标签。我觉得很奇怪,因为表格并不是真的悬挂或任何东西。它试图访问不同的线程或什么?意思是,表单是在自己的线程上运行的,无法从我的第二个线程访问它?
答案 0 :(得分:3)
您最好的选择是使用BackgroundWorker
,因为此课程专为此精确用例而设计。
答案 1 :(得分:2)
BackgroundWorker类是你需要使用的。要将数据传递回表单的进度条,您可以将WorkerReportsProgress
属性设置为true并处理ProgressChanged
事件以设置进度条的值。从长时间运行的方法,您可以发送如下进度:
backgroundworker.ReportProgress(10)