Thread et maj de control dans un form [Résolu]

Signaler
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020
-
Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
-
Bonjour,
J'essaye de faire un thread en vb.net, mais la je bloque. Pourtant j'ai pas mal cherché sur internet.
Je voudrais que ce thread tourne en arrière plan en mettant des labels à jour sur le form. Apparemment impossible.
A aussi, dans un autre, il doit mettre un webbrowser à jour (pas encore testé).

De plus (en enlevant la question des labels pour test) quand je fais une boucle FOR x=0 to y, je n'ai pas la main sur les contrôles du form tant que la boucle n'est pas finie.
Voici mes test :

   ' Déclaration
    Private tTask1 As System.Threading.Thread
    Private mreTask1 As System.Threading.ManualResetEvent
    Private Delegate Sub dTask1()
    Private leStop As Boolean = False
    Private lelien(6) As String

    ' Initialisation
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        mreTask1 = New System.Threading.ManualResetEvent(False)
        lelien(0) = "https://www.francetvinfo.fr/titres.rss"
        lelien(1) = "https://news.google.com/news/rss/headlines/section/topic/WORLD?ned=fr&gl=FR&hl=fr"
        lelien(2) = "https://news.google.com/news/rss/headlines/section/q/lci/lci?ned=fr&hl=fr&gl=FR"

        lelien(3) = "https://forum.pcastuces.com/forum.xml"
        lelien(4) = "https://www.extreme-down.video/rss.xml"
        lelien(5) = "http://www.huffingtonpost.fr/feeds/index.xml"

    End Sub


   ' Premier test thread
    Private Sub Task1()
        Me.BeginInvoke(New dTask1(AddressOf sTask1))
        System.Threading.Thread.Sleep(1500)
        Do While leStop = False
            System.Threading.Thread.Sleep(100)
        Loop 'Until ProgressBar1.Value >= ProgressBar1.Maximum
    End Sub

    'Second test Thread
    Private Sub Task1()
        Do While leStop = False
            Me.BeginInvoke(New dTask1(AddressOf sTask1))
            System.Threading.Thread.Sleep(100)
        Loop 'Until ProgressBar1.Value >= ProgressBar1.Maximum
    End Sub

    'Sous tache Premier test (j'ai fait 2 boucles pour voir)
    Private Sub sTask1()
        Dim element As XmlNodeList
        Dim noeud As XmlNode
        Dim noeudEnf As XmlNode

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        Dim XmlDoc As XmlDocument = New XmlDocument()

        For iii As Integer = 0 To 2
            Label3.Text = lelien(iii)
            Label3.Refresh()
            Label4.Text = iii
            Label4.Refresh()
            Console.WriteLine("iii : " & iii & " ==> " & lelien(iii))
            Console.WriteLine("==============================================")
            XmlDoc.Load(lelien(iii))

            element = XmlDoc.DocumentElement.GetElementsByTagName("item")

            For Each noeud In element
                For Each noeudEnf In noeud.ChildNodes
                    If (noeudEnf.LocalName = "title") Then
                        'Console.WriteLine(noeudEnf.InnerText)
                    End If
                Next
            Next
        Next

        For iii As Integer = 3 To 5
            Label3.Text = iii
            Label3.Refresh()
            Label4.Text = lelien(iii)
            Label4.Refresh()
            Console.WriteLine("iii : " & iii & " ==> " & lelien(iii))
            Console.WriteLine("================================================")
            XmlDoc.Load(lelien(iii))

            element = XmlDoc.DocumentElement.GetElementsByTagName("item")

            For Each noeud In element
                For Each noeudEnf In noeud.ChildNodes
                    If (noeudEnf.LocalName = "title") Then
                        'Console.WriteLine(noeudEnf.InnerText)
                    End If
                Next
            Next
        Next

        leStop = True
    End Sub

    'Sous tache Second test
    Private Sub sTask1()
        Dim element As XmlNodeList
        Dim noeud As XmlNode
        Dim noeudEnf As XmlNode

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        Dim XmlDoc As XmlDocument = New XmlDocument()

        Parallel.For(0,
             5,
             Sub(iii)
                 Try
                     Label3.Text = lelien(iii)
                     Label3.Refresh()
                     Label4.Text = iii
                     Label4.Refresh()
                 Catch ex As Exception

                 End Try
                 Console.WriteLine("iii : " & iii & " ==> " & lelien(iii))
                 Console.WriteLine("===============================================")
                 XmlDoc.Load(lelien(iii))

                 element = XmlDoc.DocumentElement.GetElementsByTagName("item")
                 For Each noeud In element
                     For Each noeudEnf In noeud.ChildNodes
                         If (noeudEnf.LocalName = "title") Then
                             'Console.WriteLine(noeudEnf.InnerText)
                         End If
                     Next
                 Next

             End Sub)

        leStop = True

    End Sub

    'Bouton appelant
    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
        leStop = False
        tTask1 = New System.Threading.Thread(AddressOf Task1)
        tTask1.IsBackground = True
        tTask1.Start()
    End Sub


La je ne trouve plus.

22 réponses

Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
Bonjour

Le problème de poser 3 questions dans un seul fil, c’est le risque que machin réponde à une, bidule à une autre et truc à la 3eme, et qu’ensuite tout ce petit monde parle de son sujet ou pas et c’est vite le bazar.

C’est pour ça qu’une des règles de ce forum est un fil = une question.

On va donc sur ce fil répondre à la question comment mettre à jour l’IHM à partir d’un thread.

Option 1
Utiliser un backgroundworker et ses événements threadsafe dédiés

Option 2
Utiliser les méthodes Invoke des contrôles (selon ton Framework-

Option 3
Utiliser un dispatcher

Et les autres façons de faire ne me reviennent pas
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Oui, je sais, suis pas très bon, je débute. Ce sont des tests que j'ai fait dans un programme qui me permettra de finir un autre pgm. J'ai mis 3 question, car tout est dans un seul pour test. Je vais chercher. Suis désolé.

Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
J'ai pas dit que tu n'es pas bon..... juste qu'il y a 3 problématiques, et que pour bien les résoudre, il faut le faire séparément.

Je ne t'oblige pas à creuser comme un fou non plus, je peux te faire un exemple vite fait, mais je n'allais pas choisir à ta place quelle façon utiliser.

Comme tu débutes, et si tu n'as pas besoin d'un thread hyper performant et que tu n'as pas envie de trop t'embêter à gérer les opérations interthread, alors le backgroundworker est fait pour toi
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Mon pgm source lit une centaine de flux RSS et les mets dans bdd Acces. Quand la maj des flux ce fait, ça bloque bien sur mon form, faut attendre. Si par exemple je déroule le datagridview qui affiche les flux pendant le téléchargement, marche pas.

Un autre télécharge des pages web Québécoise que je met en forme pour des Québécois justement, la il y en a plusieurs sur le site, idem, j'attend que ça finisse je ne touche pas.
Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
A ce stade, ça n'a pas d'importance pour moi....
Si tu mets la charrue avant les boeufs, tu ne laboureras pas.

Donc, commençons par le commencement, un exemple de backgroundworker
    Private Sub ExempleBGW()
        Dim bgw As New BackgroundWorker()

        bgw.WorkerReportsProgress = True 'necessaire pour envoyer l'avancement du calcul

        AddHandler bgw.ProgressChanged, AddressOf Bgw_ProgressChanged

        AddHandler bgw.DoWork, AddressOf Bgw_DoWork 'abonne le BGW à la méthode qui fera le travail de fond.

        AddHandler bgw.RunWorkerCompleted, AddressOf Bgw_RunWorkerCompleted 'abonne le BGW à la méthode qui sera éxécutée quand le travail sera finit

        bgw.RunWorkerAsync(1000000000.0) 'Démarre le travail de fond avec un paramètre
    End Sub

    Private Sub Bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim max As Integer = Convert.ToInt32(e.Argument)

        'un grand tableau de char qu'on va utiliser par la suite
        Dim caracteres() As Char = {"A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c, "a"c, "b"c, "c"c, "d"c, "e"c, "f"c, "g"c, "h"c, "i"c, "j"c, "k"c, "l"c, "m"c, "n"c, "o"c, "p"c, "q"c, "r"c, "s"c, "t"c, "u"c, "v"c, "w"c, "x"c, "y"c, "z"c, "A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c, "a"c, "b"c, "c"c, "d"c, "e"c, "f"c, "g"c, "h"c, "i"c, "j"c, "k"c, "l"c, "m"c, "n"c, "o"c, "p"c, "q"c, "r"c, "s"c, "t"c, "u"c, "v"c, "w"c, "x"c, "y"c, "z"c}


        For i As Integer = 0 To max - 1 'compte de zéro à la valeur passée en argument


            Dim j As Double = i * 100.0 / max
            If Math.Floor(i * 100.0 / max) = j Then
                'on déclenche un évènement avec les informations de progression et de travail (en l'état un char)
                CType(sender, BackgroundWorker).ReportProgress(CInt(Convert.ToInt32(j)), caracteres(CInt(Convert.ToInt32(j)))) 'quand on avance d'un %, envoie l'information d'avancement et une information personnelle
            End If
        Next i

        e.Result = "C'est fini!" 'définit un résultat
    End Sub

    Private Sub Bgw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
        ProgressBar1.Value = e.ProgressPercentage 'affiche le pourcentage dans une progressbar
        ListBox1.Items.Add(e.UserState) 'ajoute une ligne dans une listbox
    End Sub

    Private Sub Bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
        MessageBox.Show(CStr(e.Result)) 'on affiche un messagebox qui montre le résultat
    End Sub





Si ça ne te convient pas, on verra une autre façon de faire
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

C'est fait, ca marche.

Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Je teste avec mon bazar de flux rss ? Si oui, je te tient au courant.
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Je bloque ici, je met quoi ? Moi c'est du texte et integer.

        For i As Integer = 0 To 5
            CType(sender, BackgroundWorker).ReportProgress(lelien(i))
        Next

Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Bon, j'ai mis ceci, ca marche, mais pas la main sur un autre contrôle, j'ai rajouté un bouton 2 et quand je click pendant le chargement, pas la main sauf à la fin de la boucle.

    
Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)

        ListBox1.Items.Add(e.UserState) 'ajoute une ligne dans une listbox

        Dim element As XmlNodeList
        Dim noeud As XmlNode
        Dim noeudEnf As XmlNode

         ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        Dim XmlDoc As XmlDocument = New XmlDocument()
        XmlDoc.Load(lelien(e.ProgressPercentage))

        element = XmlDoc.DocumentElement.GetElementsByTagName("item")

        For Each noeud In element
            For Each noeudEnf In noeud.ChildNodes
                If (noeudEnf.LocalName = "title") Then
                    Console.WriteLine(noeudEnf.InnerText)
                End If
            Next
        Next

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        x = x + 1
        Label1.Text = "Ok : " & x
    End Sub


Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
forcément tu fais une boucle imbriquée en dehors du thread...

        For Each noeud In element
            For Each noeudEnf In noeud.ChildNodes
                If (noeudEnf.LocalName = "title") Then
                    Console.WriteLine(noeudEnf.InnerText)
                End If
            Next
        Next
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

La c'est mieux :
    Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim max As Integer = Convert.ToInt32(e.Argument)

        Dim element As XmlNodeList
        Dim noeud As XmlNode
        Dim noeudEnf As XmlNode

        Dim XmlDoc As XmlDocument = New XmlDocument()

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        For i As Integer = 0 To 5
            XmlDoc.Load(lelien(i))
            element = XmlDoc.DocumentElement.GetElementsByTagName("item")
            For Each noeud In element
                For Each noeudEnf In noeud.ChildNodes
                    If (noeudEnf.LocalName = "title") Then
                        Console.WriteLine(noeudEnf.InnerText)
                        CType(sender, BackgroundWorker).ReportProgress(CInt(Convert.ToInt32(i)), noeudEnf.InnerText) 
                    End If
                Next
            Next
        Next

        e.Result = "C'est fini!" 'définit un résultat
    End Sub

    Private Sub bgw_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)

        ListBox1.Items.Add(e.UserState) 'ajoute une ligne dans une listbox

       '
       ' ICI MA MIXTURE POUR LE RESTE, que je testerais
      '
    End Sub


Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Peut on passer plusieurs paramétres dans :

CType(sender, BackgroundWorker).ReportProgress(CInt(Convert.ToInt32(i)), noeudEnf.InnerText)

Moi j'ai ceci quand j'appelle ma proc :

Public Sub Maj_Flux_Rss_Tous(ByVal Le_Url As String, ByVal Titre_Url As String, ByVal Noeud_Titre As String, ByVal Le_Temps As Integer, ByVal Je_Suspend As Boolean)
Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

La rien compris, ça parle du DoWork, mais pas du ProgressChanged ou je récupère les variables.
Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
Ben c'est pareil, tu passes un tableau en paramètre et tu cast l'objet à l'arrivée
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Bon ben voila :
    Public Class ArgumentType
        Public _Le_Url As String
        Public _Le_Titre As String
        ' etc ......
    End Class

    Private args(6) As ArgumentType '= New ArgumentType

    Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        lelien(0) = "https://www.francetvinfo.fr/titres.rss"
        lelien(1) = "https://news.google.com/news/rss/headlines/section/topic/WORLD?ned=fr&gl=FR&hl=fr"
        lelien(2) = "https://news.google.com/news/rss/headlines/section/q/lci/lci?ned=fr&hl=fr&gl=FR"

        lelien(3) = "https://forum.pcastuces.com/forum.xml"
        lelien(4) = "https://www.extreme-down.video/rss.xml"
        lelien(5) = "http://www.huffingtonpost.fr/feeds/index.xml" 
    
      ' Je mettrais le reste dans une boucle
       args(0) = New ArgumentType
       args(0)._Le_Url = "https://www.francetvinfo.fr/titres.rss"
       args(0)._Le_Titre = "France TV"
       'etc .....
    End Sub

   Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        'Dim max As Integer = Convert.ToInt32(e.Argument)

       ' ICI JE RECUPERE
      '  ?args1(0)._Le_Url
       ' "https://www.francetvinfo.fr/titres.rss"
       ' ?args1(0)._Le_Titre
       ' "France TV"
        Dim args1() As ArgumentType = e.Argument

        Dim element As XmlNodeList
        Dim noeud As XmlNode
        Dim noeudEnf As XmlNode

        Dim XmlDoc As XmlDocument = New XmlDocument()

        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

        For i As Integer = 0 To 5
            XmlDoc.Load(lelien(i))
            element = XmlDoc.DocumentElement.GetElementsByTagName("item")
            For Each noeud In element
                For Each noeudEnf In noeud.ChildNodes
                    If (noeudEnf.LocalName = "title") Then
                        Console.WriteLine(noeudEnf.InnerText)
                        CType(sender, BackgroundWorker).ReportProgress(CInt(Convert.ToInt32(i)), noeudEnf.InnerText) 
                    End If
                Next
            Next
        Next

        e.Result = "C'est fini!" 'définit un résultat
    End Sub

' et je démarre par  bgw.RunWorkerAsync(args)



Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
Si ça répond à ton besoin, pense à marquer le sujet résolu
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Je test avec tout mon bazar demain et je dirais et mettrais résolu si ok.
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

En tous les cas, un TRES GRAND MERCI POUR TON AIDE.
Messages postés
14717
Date d'inscription
mardi 11 mars 2003
Statut
Contributeur
Dernière intervention
3 septembre 2020
430
De rien
Messages postés
44
Date d'inscription
lundi 25 février 2019
Statut
Membre
Dernière intervention
3 septembre 2020

Demain, je pense mettre résolu, suis encore dans simulation de mon pgm. Jusqu'ici tout va bien.