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

发布于 2024-11-06 02:27:45 字数 4189 浏览 0 评论 0原文

我有一个非常简单的表单,其中有一个按钮可以触发我创建的子程序,该子程序从 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

请注意 CodeFile.vb 中的 ExportFromAD Sub。这就是实际做的工作。在将数据添加到 Excel 的 For every 循环中,我放置了 MainForm.MyBackgroundWorker.ReportProgress(i * 10)

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

I have a really simple form with a button that fires a Sub I created which gathers data from ActiveDirectory and adds it to an Excel Sheet.

The problem is, when I click this button the whole form hangs. So I figured the operation that gathers the data and adding it to the Excel sheet should be run in it's own thread, so that the form won't hang. Possibly it would be great to add a progressbar as well.
The progressbar however is located at the Main userform that starts up once the projects is run.

What do I need to do in order to get this the way I want?

Edit: Added some of my code. I've got one MainForm.vb and one CodeFile.vb.
I want most of the code in the CodeFile.vb so it's tidier.

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

Notice the ExportFromAD Sub I've got in the CodeFile.vb. This is what is actually doing the work. In the For each loop that adds data to the Excel is where I've put the MainForm.MyBackgroundWorker.ReportProgress(i * 10).

Problem is, it doesn't actually update the label on the form. Which I find pretty weird because the form isn't really hanging or anything. Is it trying to access a different thread or something? Meaning, the form is run on it's own thread which can't be accessed from my second thread?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

拧巴小姐 2024-11-13 02:27:45

最好的选择是使用 BackgroundWorker 因为此类是专为这种精确的用例而设计的。

这还允许您回调表单以更新状态栏

Your best bet is to use a BackgroundWorker since this class is designed for this precise use-case.

This also allows you to call back to the form to update the status bar.

旧伤慢歌 2024-11-13 02:27:45

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

backgroundworker.ReportProgress(10)

The BackgroundWorker class is what you need to use. For passing data back to the form's progress bar you set the WorkerReportsProgress property to true and handle the ProgressChanged event to set the progress bar's value. From the long running method you can send progress like this:

backgroundworker.ReportProgress(10)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文