VB.NET - выполнение работы в отдельном потоке, чтобы форма не зависала - PullRequest
2 голосов
/ 09 мая 2011

У меня действительно простая форма с кнопкой, которая запускает созданную мной подпрограмму, которая собирает данные из 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.Это то, что на самом деле делает работу.В цикле «Для каждого», который добавляет данные в Excel, я поместил MainForm.MyBackgroundWorker.ReportProgress(i * 10).

Проблема в том, что он не обновляет метку в форме.Что я нахожу довольно странным, потому что форма на самом деле не висит или что-то еще.Это пытается получить доступ к другому потоку или что-то?То есть форма запускается в своем собственном потоке, к которому нет доступа из моего второго потока?

Ответы [ 2 ]

3 голосов
/ 09 мая 2011

Лучше всего использовать BackgroundWorker, поскольку этот класс предназначен для этого точного варианта использования.

Это также позволяет перезвонить на форму для обновления строки состояния .

2 голосов
/ 09 мая 2011

Класс BackgroundWorker - это то, что вам нужно использовать.Для передачи данных обратно в индикатор выполнения формы вы устанавливаете для свойства WorkerReportsProgress значение true и обрабатываете событие ProgressChanged, чтобы установить значение индикатора выполнения.Из метода длительного запуска вы можете отправить прогресс следующим образом:

backgroundworker.ReportProgress(10)
...