2 votes

VB.NET - Effectuer le travail dans un thread séparé pour éviter que le formulaire ne soit suspendu

J'ai un formulaire très simple avec un bouton qui déclenche un sous-programme que j'ai créé et qui recueille les données d'ActiveDirectory et les ajoute à une feuille Excel.

Le problème est que, lorsque je clique sur ce bouton, tout le formulaire se bloque. J'ai donc pensé que l'opération qui rassemble les données et les ajoute à la feuille Excel devrait être exécutée dans son propre thread, afin que le formulaire ne se bloque pas. Il serait peut-être bon d'ajouter également une barre de progression. Cependant, la barre de progression se trouve dans le formulaire principal qui s'ouvre une fois le projet lancé.

Que dois-je faire pour que tout se passe comme je le souhaite ?

Edit : J'ai ajouté une partie de mon code. J'ai un MainForm.vb et un CodeFile.vb. Je veux que la plupart du code soit dans le CodeFile.vb pour que ce soit plus ordonné.

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

Remarquez le ExportFromAD Le sous-marin que j'ai dans le CodeFile.vb . C'est ce qui fait réellement le travail. Dans la boucle "For each" qui ajoute les données à Excel, j'ai placé la balise MainForm.MyBackgroundWorker.ReportProgress(i * 10) .

Le problème est que cela ne met pas réellement à jour l'étiquette sur le formulaire. Ce que je trouve assez bizarre car le formulaire n'est pas vraiment suspendu ou autre. Est-ce qu'il essaie d'accéder à un autre thread ou quelque chose comme ça ? En d'autres termes, le formulaire est exécuté sur son propre thread qui n'est pas accessible depuis mon second thread ?

3voto

Konrad Rudolph Points 231505

Votre meilleure chance est d'utiliser un BackgroundWorker puisque cette classe est conçue pour ce cas d'utilisation précis.

Cela vous permet également de rappel au formulaire pour mettre à jour la barre d'état .

2voto

Michael Minton Points 2107

En Travailleur d'arrière-plan est ce que vous devez utiliser. Pour renvoyer des données à la barre de progression du formulaire, vous définissez l'attribut WorkerReportsProgress à true et traiter le ProgressChanged pour définir la valeur de la barre de progression. Depuis la méthode d'exécution longue, vous pouvez envoyer la progression comme ceci :

backgroundworker.ReportProgress(10)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X