VB.NET-在单独的线程中工作以防止模板挂起

VB.NET-在单独的线程中工作以防止模板挂起,.net,vb.net,multithreading,backgroundworker,.net,Vb.net,Multithreading,Backgroundworker,我有一个非常简单的表单,它有一个按钮,可以触发我创建的一个Sub,该Sub从ActiveDirectory收集数据并将其添加到Excel工作表中 问题是,当我点击这个按钮时,整个表单都挂起了。所以我认为收集数据并将其添加到Excel工作表的操作应该在它自己的线程中运行,这样表单就不会挂起。也许添加一个progressbar也会很好。 然而,progressbar位于项目运行后启动的主用户窗体上 我需要做什么才能得到我想要的 编辑:添加了一些我的代码。我有一个MainForm.vb和一个CodeF

我有一个非常简单的表单,它有一个按钮,可以触发我创建的一个Sub,该Sub从ActiveDirectory收集数据并将其添加到Excel工作表中

问题是,当我点击这个按钮时,整个表单都挂起了。所以我认为收集数据并将其添加到Excel工作表的操作应该在它自己的线程中运行,这样表单就不会挂起。也许添加一个progressbar也会很好。 然而,progressbar位于项目运行后启动的主用户窗体上

我需要做什么才能得到我想要的

编辑:添加了一些我的代码。我有一个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
导入用户\u edit.code文件
导入System.ComponentModel
公共类主窗体
私有子btnImportData_Click(ByVal发送方作为System.Object,ByVal e作为System.EventArgs)处理btnImportData。单击
如果MyBackgroundWorker.IsBusy为True,则
MyBackgroundWorker.RunWorkerAsync()
如果结束
端接头
私有子BackgroundWorker_DoWork(ByVal sender作为System.Object,ByVal e作为System.ComponentModel.DoWorkEventTargets)处理MyBackgroundWorker.DoWork
ExportADUsers()
端接头
Private Sub BackgroundWorker_ProgressChanged(ByVal sender作为System.Object,ByVal e作为System.ComponentModel.ProgressChangedEventArgs)处理MyBackgroundWorker.ProgressChanged
statusBarLabel.Text=(e.ProgressPercentage.ToString)
端接头
私有子BackgroundWorker_RunWorkerCompleted(ByVal发送方作为System.Object,ByVal e作为System.ComponentModel.RunWorkerCompletedEventArgs)处理MyBackgroundWorker.RunWorkerCompleted
statusBarLabel.Text=“已完成”
端接头
末级
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
导入System.DirectoryServices
导入System.ComponentModel
导入系统线程
模块代码文件
公共子出口用户()
MainForm.MyBackgroundWorker.WorkerReportsProgress=True
MainForm.MyBackgroundWorker.WorkersSupportsScanCellation=True
作为整数的Dim i
昏暗的物体,沙漏,沙漏,沙漏,沙漏,沙漏,沙漏
objRootDSE=GetObject(“LDAP://RootDSE”)
stroot=objRootDSE.GET(“DefaultNamingContext”)
strfilter=“(&(objectCategory=Person)(objectClass=User))”
strAttributes=“邮件、用户主名称、givenName、序列号,&”_
“姓名首字母、显示名称、physicalDeliveryOfficeName,”&_
“电话号码、邮件、wWWHomePage、配置文件路径,&”_
“脚本路径、homeDirectory、homeDrive、标题、部门,”_
“公司、经理、家庭电话、寻呼机、手机”_
“传真机、ipphone、信息”_
街道地址,邮政信箱,左,街,邮政编码,c
'搜索范围。如果您不想搜索子OU,请更改为“onelevel”
MainForm.statusBarLabel.Text=“收集数据”
strScope=“子树”
尺寸cn、cmd、rs
cn=CreateObject(“ADODB.Connection”)
cmd=CreateObject(“ADODB.Command”)
cn.open(“Provider=ADsDSOObject;”)
cmd.ActiveConnection=cn
cmd.commandtext=“;”&strfilter&“;”&_
strAttributes&“;”和strScope
rs=cmd.EXECUTE
Dim objExcel、objWB、objSheet
objExcel=CreateObject(“Excel.Application”)
objWB=objExcel.Workbooks.Add
objSheet=objWB.工作表(1)
对于i=0到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
下一个
Dim strExportFile
strExportFile=“C:\users\vsando\desktop\export.xls”
对象表范围(“A2”).CopyFromRecordset(rs)
objSheet.SaveAs(strExportFile)
“清理
rs.Close()
cn.Close()
objSheet=无
objWB=无
objExcel.Quit()
objExcel=无
端接头
注意我在
CodeFile.vb
中得到的
ExportFromAD
子文件。这才是真正的工作。在向Excel添加数据的For-each循环中,我将
MainForm.MyBackgroundWorker.ReportProgress(I*10)
放在这里

问题是,它实际上并没有更新表单上的标签。我觉得这很奇怪,因为表格不是真的挂着的。它是在尝试访问不同的线程还是什么?也就是说,表单是在它自己的线程上运行的,无法从我的第二个线程访问它?

您最好的选择是使用,因为这个类是为这个精确的用例设计的

这也允许您使用。

该类是您需要使用的。要将数据传回表单的进度条,请将
WorkerReportsProgress
属性设置为true,并处理
ProgressChanged
事件以设置进度条的值。通过长时间运行的方法,您可以如下方式发送进度:

backgroundworker.ReportProgress(10)

您已经在一个标签中找到了答案:最简单的方法是使用
BackgroundWorker
组件。这已经非常好了。从示例代码中:
如果(worker.CancellationPending=True),那么
…糟糕!他们又让一个实习生写了一个例子。@Konrad:哎呀,我同意。但更可能的是,他们这样做是徒劳地试图“澄清”代码。请参阅更新的主题。我已尝试添加后台工作人员。我认为这是可行的,但我无法让进度条或状态条标签真正更新。我尝试添加一个断点,以便在运行时查看标签的实际值。事实上,这是既定的。它只是不显示。这就是为什么我认为它试图显示标签是在一个不同的位置