Overblog Suivre ce blog
Editer l'article Administration Créer mon blog
19 novembre 2007 1 19 /11 /novembre /2007 16:39

Le BackGroundWorker est un composant très performant qui permet de créer des Thread très simplement. Grâce au BackGroundWorker, vous pouvez rendre votre application très "fluide" et garder une interface toujours disponible pour l'utilisateur.

Dans l'exemple suivant, nous allons utiliser un BackGroundWorker pour accomplir une tâche simple d'incrémentation d'un compteur avec une pause entre chaque incrémentation.

Nous allons également utiliser un Delegate pour appeler une fonction qui se trouve en dehors du Thread.

Voici les différents éléments que nous allons utiliser pour cet exemple.

 

Les controls de notre WinForm :

  • TextBox : tbCompteur
  • TextBox : tbPause
  • ProgressBar : pbBar
  • Button : btnStart
  • Label : lblCompte

 

Les classes :

  • bgwArguments : permet de passer des paramètres au Thread
  • bgwProgress : permet de passer des paramètres sur l'état de la progression du Thread

 

Les méthodes :

  • startBgwCompte : Initialise et démarre le Thread
  • bgwCompte_DoWork : Gère l'événement DoWork du BackGroundWorker. Cette méthode contient le code exécuté pendant le Thread.
  • bgwCompte_RunWorkerCompleted : Gére l'événement RunWorkerCompleted du BackGroundWorker qui indique la fin du Thread.
  • bgwCompte_ProgressChanged : Gère l'évènement ProgressChanged du BackGroundWorker. Cet événement se produit à chaque fois que l'on veut indiquer le changement d'état de la progression.
  • Increment : Fonction qui incrémente le compteur
  • btnStart_Click : Gère l'évènement Click du bouton btnStart
  • OnBgwTermine : Gère l'event bgwTermine

 

Pour commencer, nous devons faire un "imports" des classes d'objets nécessaires :

 

Code :

Imports System.ComponentModel
Imports System.Threading

 

Nous allons ensuite déclarer notre BackGroundWorker, un Delegate qui nous permettra d'appeller notre fonction Increment à l'intérieur du Thread et un Event que nous lèverons à la fin du Thread.

 

Code :

Private WithEvents bgwCompte As BackgroundWorker
Private Delegate Function dIncrement(ByVal nbr As Integer) As Integer
Private Event bgwTermine(ByVal nbr As Integer)

 

Voici la méthode qui permet de lancer le Thread . On passe à l'aide de l'objet bgwArguments les 2 paramètres des TextBox qui représentent respectivement le total du compteur et le temps de pause du Thread.

 

Code :

Private Sub startBgwCompte(Optional ByVal nbr As Integer = 1)
        ' On remet la ProgressBarre à zéro
        With Me.pbBar
            .Minimum = 0
            .Maximum = 100
            .Value = 0
        End With

        bgwCompte = New BackgroundWorker

        ' le BackGroundWorker doit indiquer sa progression et accepter une possible annulation
        bgwCompte.WorkerReportsProgress = True
        bgwCompte.WorkerSupportsCancellation = True

       ' on utilise l'objet bgwArgument pour passer des paramètres au Thread

       bgwCompte.RunWorkerAsync(New bgwArguments(CInt(Me.tbCompteur.Text), CInt(Me.tbPause.Text)))
End Sub

 

 

C'est dans la méthode DoWork que ce trouve le code qui sera exécuté en arrière plan.

 

Code :

Private Sub bgwCompte_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgwCompte.DoWork
        ' on récupère les arguments
        Dim nbr As Integer = CType(e.Argument, bgwArguments).nbr
        Dim pause As Integer = CType(e.Argument, bgwArguments).pause

        Dim compteur As Integer = 0

        ' on utilise un Delegate pour faire appel à notre fonction Increment
        Dim delegateIncrement As dIncrement = AddressOf Increment

        Do
            ' on appelle notre Fonction à travers le Delegate
            compteur = delegateIncrement(compteur)

            ' on indique l'état de la progression
            bgwCompte.ReportProgress((compteur * 100) / nbr, New bgwProgress("Le compteur est à " & compteur.ToString))

            ' on vérifie si une demande d'annulation a été faite par l'utilisateur, si oui on sort de la boucle
            If Me.bgwCompte.CancellationPending = True Then
                e.Result = compteur
                Exit Do
            End If

           'on met le Thread en pause
            Thread.Sleep(pause)

        Loop Until compteur = nbr

        e.Result = compteur

    End Sub

 

Lorsque que le code de la méthode DoWork est terminé, l'évènement RunWorkerCompleted est géré par cette méthode.

 

Code :

Private Sub bgwCompte_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgwCompte.RunWorkerCompleted

        ' on lève l'événement bgwTermine qui retourne la valeur du compteur
        RaiseEvent bgwTermine(CInt(e.Result))
End Sub

 

 

La méthode suivante gère le ReportProgress que l'on appelle dans la boucle de la méthode DoWork. Elle met à jour la valeur de la ProgressBar et le text du Label pour indiquer l'état de la progression.

 

Code :

Private Sub bgwCompte_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgwCompte.ProgressChanged
        If e.ProgressPercentage <= 100 Then
            Me.pbBar.Value = e.ProgressPercentage
        Else
            Me.pbBar.Value = 100
        End If

        Me.lblCompte.Text = CType(e.UserState, bgwProgress).text
End Sub

 

La fonction suivante permet d'incrémenter le compteur. Biensur, le code de cette fonction aurait pu être mis directement dans la méthode DoWork, mais elle permet d'illustrer le faite que l'on peut appeller une méthode qui est en dehors du Thread en utilisant un Delegate.

Code :

Public Function Increment(ByVal nbr As Integer) As Integer
        nbr += 1
        Return nbr
End Function

 

L'événement Click du bouton btnStart est géré par cette méthode :

Code :

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
        If Me.btnStart.Text = "Stop" Then
           ' On vérifie que le Thread est bien en cours avant d'essayer de l'annuler
            If Me.bgwCompte.IsBusy Then
                Me.bgwCompte.CancelAsync()
            End If
            Me.btnStart.Text = "Start"
        Else
            If IsNumeric(Me.tbCompteur.Text) And IsNumeric(Me.tbPause.Text) Then
                'on vérifie que ce Thread n'est pas déjà en cours
                Me.startBgwCompte(CInt(Me.tbCompteur.Text))
                Me.btnStart.Text = "Stop"
            Else
                MsgBox("Les données saisies ne sont pas correctes.", MsgBoxStyle.Information)
        End If

        End If
    End Sub

 

Cette méthode gère l'évènement bgwTermine qui est levé à la fin du Thread :

Code :

Private Sub OnBgwTermine(ByVal compteur As Integer) Handles Me.bgwTermine
        MsgBox("Le compteur c'est arrêté à " & compteur)
        Me.pbBar.Value = 0
        Me.lblCompte.Text = "Compteur arrêté"
End Sub

 

Cette classe permet de passer plusieurs paramètres au BackGroundWorker. Etant donné que vous pouvez passer n'importe quel objet en paramètre à un BackGroundWorker, les possibilités sont quasis illimitées !

Code :

Public Class bgwArguments
    Private _nbr As Integer
    Private _pause As Integer

    Public Sub New(ByVal nbrCompteur As Integer, ByVal pauseCompteur As Integer)
        _nbr = nbrCompteur
        _pause = pauseCompteur
    End Sub

    Public Property nbr() As Integer
        Get
            Return _nbr
        End Get
        Set(ByVal value As Integer)
            _nbr = value
        End Set
    End Property

    Public Property pause() As Integer
        Get
            Return _pause
        End Get
        Set(ByVal value As Integer)
            _pause = value
        End Set
    End Property
End Class

 

Cette classe permet de passer des paramètres sur l'état de la progression. Là aussi, n'importe quel objet peut être utilisé pour indiquer l'état de la progression.

Code :

Public Class bgwProgress
    Private _text As String

    Public Sub New(ByVal txt As String)
        _text = txt
    End Sub

    Public Property text() As String
        Get
            Return _text
        End Get
        Set(ByVal value As String)
            _text = value
        End Set
    End Property

End Class

 

Testons maintenant notre application. Dans le tbCompteur saisissez le chiffre 60 et dans le tbPause le chiffre 1000 (le temps de pause est en millisecondes) . Cliquez sur le bouton btnStart. Le texte du bouton va passer de "Start" à "Stop" et vous allez commencer à voir votre ProgressBar afficher la progression pendant que votre lblCompte vous indique la valeur du Compteur. Vous remarquerez que vous pouvez toujours agir sur les controls de votre WinForm et sur la fenêtre elle même. Lorsque vous cliquez sur "Stop", le thread s'arrête, et un message vous indique la valeur du compteur au moment de l'annulation du Thread.

Les règles à se rappeler sont les suivantes :

  • Ne jamais faire appelle à une méthode directement dans le Thread. Utiliser un Delegate.
  • Ne jamais agir sur l'interface de l'utilisateur depuis unThread. Par exemple, ne pas mettre dans le DoWork un tbMonText.Text="Hello".

Partager cet article

Repost 0
Published by Cyril - dans VB.NET
commenter cet article

commentaires

"'ffff 14/06/2017 13:35

comment peut on faire si on a besion d'un traitement dans une boucle while