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

时间:2011-05-09 11:27:26

标签: .net vb.net multithreading backgroundworker

我有一个非常简单的表单,其中包含一个触发我创建的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)的位置。

问题是,它实际上并没有更新表单上的标签。我觉得很奇怪,因为表格并不是真的悬挂或任何东西。它试图访问不同的线程或什么?意思是,表单是在自己的线程上运行的,无法从我的第二个线程访问它?

2 个答案:

答案 0 :(得分:3)

您最好的选择是使用BackgroundWorker,因为此课程专为此精确用例而设计。

这也允许您call back to the form to update the status bar

答案 1 :(得分:2)

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

backgroundworker.ReportProgress(10)