IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Forms Discussion :

Chamboulement, intégration Evenement & Thread


Sujet :

Windows Forms

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut Chamboulement, intégration Evenement & Thread
    Bonjour,

    J'ai encore du mal avec les événements... mais je me retrouve dans le cas de mon interface utilisateur de devoir mettre des threads sinon il faut que j'attende la fin de traitement (et comme il s'agit de la récupération d'information sur des fichiers via MediaInfo, ça prends un certain temps...)

    Afin de ne pas "pourrir" mon code, j'ai tenter de reproduire mon cas :
    une UI (winform) et via bouton des appels à des instances de classes (issu d'un notre projet à la solution (Dll)).

    Dans cette "externalisation de test"j'ai tenté de comprendre l'intégration "Evenements avec Thread".

    Par contre depuis que j'ai intégré le thread, je ne vois pas comment enlever le Handler, parce que si je le mets, et bien il est retiré avant la fin du thread.

    "RemoveHandler"

    J'ai un winform est des actions déclenchent des threads sur un autre projet (classes).

    Avec du code c'est plus simple :
    Merci d'avance.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
     
    Public Class formTest
     
        Public Delegate Sub SetFormEvt(sender As Object, e As GenerateTextEventArgs)
     
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
     
            Dim c As New Compte
     
            Dim t As New Threading.Thread(New Threading.ThreadStart(AddressOf c.Go))
            t.Name = "Tache1"
            t.IsBackground = True
     
            AddHandler c.OnTextChanged, AddressOf FormEvt
            'c.Go()
            t.Start()
     
    'RemoveHandler c.OnTextChanged, AddressOf FormEvt
     
        End Sub
     
        Private Sub FormEvt(sender As Object, e As GenerateTextEventArgs)
            If Label1.InvokeRequired Then
                Label1.Invoke(New SetFormEvt(AddressOf FormEvt), sender, e)
            Else
                Label1.Text = DirectCast(e, GenerateTextEventArgs).EventText '"CALL"
            End If
        End Sub
     
    End Class
     
     
    Public Class GenerateTextEventArgs
        Inherits EventArgs
        Private myEventText As String = Nothing
        Public Sub New(ByVal theEventText As String)
            If theEventText Is Nothing Then
                Throw New NullReferenceException()
            End If
            myEventText = theEventText
        End Sub
        Public ReadOnly Property EventText As String
            Get
                Return Me.myEventText
            End Get
        End Property
    End Class
     
    Public Class Compte
        Public Delegate Sub TextGeneratedEventHandler(ByVal sender As Object, ByVal e As GenerateTextEventArgs)
        Public Event OnTextChanged As TextGeneratedEventHandler
     
        Public Sub Go()
     
            Dim updateCounterDelegate As New MethodInvoker(AddressOf UpdateCout)
            Dim nb = 100
     
            For i As Integer = 0 To nb
                Dim e As GenerateTextEventArgs = New GenerateTextEventArgs("Compteur = " & i.ToString())
                'TODO : Call Event
                Threading.Thread.Sleep(100)
                RaiseEvent OnTextChanged(Me, e)
            Next
     
        End Sub
     
        Private Sub UpdateCout()
            '  Label1.
        End Sub
     
    End Class
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    je ne comprends pas ce code (c'est pas bon signe ^^)

    tu peux utiliser le backgroundworker, qui a des chances d'être plus simple pour un débutant
    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    private withevents _bgw as new backgroundworker

    quand tu veux démarrer le traitement tu fais .runquelquechose

    tu t'abonnes à l'event dowork (avec handles plutot que addhandler, addhandler est surtout utile pour des controles créés dynamiquement)
    dans dowork, c'est le thread séparé, donc là tu peux faire ton traitement long ; ca arrive ici après l'appel à run
    à la fin tu peux mettre dans e (.result de mémoire) ce que tu veux (réellement)

    tu t'abonnes à l'event completed, à la sortie de la sub du dowork tu arriveras ici, et dans e(.result surement donc) tu retrouveras ce que tu y a mis dans dowork
    l'avantage de passer par là, c'est que l'event dowork est sur un autre thread, mais l'event completed est sur le thread où tu as fais .run, donc sur le thread principal et tu peux modifier l'interface graphique

    si tu as plusieurs choses à passer, tu peux faire une classe, dont tu mettras une instance dans e.result (un directcast sera nécessaire dans l'event completed)


    le bgw permet aussi de gérer une annulation, mais c'est à coder soit même, c'est juste précablé (détails si nécessaire)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Pour le code, j'ai pris un peu de partout ... tester, modifié entre différents forums avec chacun leur "technique"

    J'essai de reproduire "mes conditions" qui font suite au clic sur un bouton dans mon Winform.
    Actuellement celui-ci instancie une classe qui dont fais un traitement sur des répertoires via réseau. puisque ma classe se débrouille toute seule et que vraiment c'est un peu le grand écart pour moi entre les webforms (postback) et les winforms, je galère un "peu" pour la partie "UI"

    1) Le but étant d'avoir les différentes informations remontés par événements.
    Exemple : Phase 1.. en cours etc ... (% si la phase le permet) et également de retourner par exemple : x fichiers trouvés puis dans les phase suivantes d'indiquer x médias (regroupement des fichiers) x erreurs (genre mauvais nommage, car le nom du fichier doit commencer pareil que le nom du répertoire)

    2) d'avoir l'interface non bloquée ce qui m'a amené à essayé de me dépatouiller avec les threads... et me casser les dents

    Je crois que je vais donc suivre ton conseil sur le backworker mais il faut que j'y aille étape par étape, parce que les évents comme les threads un peu "le saute mouton" (lui appel lui qui appel lui...)
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    les events c'est censé être simple
    par exemple l'event click de la classe button fait que lors du click, toutes les méthodes déclarées abonnées à cet event sont appelées
    sender contient l'instance de l'appelant (le bouton dans ce cas) et e les éventuels paramètres de l'event (par exemple les coordonnées pour l'event mousemove)
    ceci est fait tout de suite et en local, un peu comme le ferais du javascript en web
    un modification de l'interface (comme le changement d'un texte sur un bouton) c'est exécuté tout de suite aussi et l'interface se redessine
    il y a des tas d'event sur chaque type de controle (comme textchanged sur textbox qui est levé à chaque modification ne serait-ce que d'un caractère)

    dans l'event dowork tu peux instancier ta classe qui fait le traitement, lui dire de le faire, et attendre qu'elle ait fini
    tu places le résultat si c'est une fonction longue qui te le retourne (ou ton instance de cette classe si elle contient les résultats sous forme de propriétés) dans e.Result et c'est tout
    dans l'event completed tu peux modifier les controles de l'interface
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Je viens de faire ceci, ça fonctionne.

    une question :
    Tu m'as dis :
    avec handles plutot que addhandler, addhandler est surtout utile pour des controles créés dynamiquement)
    Je ne vois pas comment remplacer mes addHandler ici...

    Code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
     
     
    Imports System.ComponentModel
     
    Public Class formTest
     
        Public Delegate Sub SetFormEvt(sender As Object, e As GenerateTextEventArgs)
     
        Private WithEvents bgwCode As BackgroundWorker
     
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
     
            Button1.Enabled = False
     
            bgwCode = New BackgroundWorker
     
            bgwCode.WorkerReportsProgress = True
            bgwCode.WorkerSupportsCancellation = True
     
            Dim c As New Compte
     
            AddHandler bgwCode.DoWork, AddressOf c.Go
            AddHandler bgwCode.RunWorkerCompleted, AddressOf Fini
            AddHandler c.OnTextChanged, AddressOf FormEvt
     
            bgwCode.RunWorkerAsync()
     
        End Sub
     
        Private Sub FormEvt(sender As Object, e As GenerateTextEventArgs)
            If Label1.InvokeRequired Then
                Label1.Invoke(New SetFormEvt(AddressOf FormEvt), sender, e)
            Else
                Label1.Text = DirectCast(e, GenerateTextEventArgs).EventText '"CALL"
            End If
        End Sub
     
        Private Sub Fini()
            Button1.Enabled = True
        End Sub
    End Class
     
     
    Public Class GenerateTextEventArgs
        Inherits EventArgs
        Private myEventText As String = Nothing
        Public Sub New(ByVal theEventText As String)
            If theEventText Is Nothing Then
                Throw New NullReferenceException()
            End If
            myEventText = theEventText
        End Sub
        Public ReadOnly Property EventText As String
            Get
                Return Me.myEventText
            End Get
        End Property
    End Class
     
    Public Class Compte
        Public Delegate Sub TextGeneratedEventHandler(ByVal sender As Object, ByVal e As GenerateTextEventArgs)
        Public Event OnTextChanged As TextGeneratedEventHandler
     
        Public Sub Go()
     
            Dim nb = 100
     
            For i As Integer = 0 To nb
                Dim e As GenerateTextEventArgs = New GenerateTextEventArgs("Compteur = " & i.ToString())
                'TODO : Call Event
                Threading.Thread.Sleep(100)
                RaiseEvent OnTextChanged(Me, e)
            Next
        End Sub
     
    End Class
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
     
       bgw = new backgroundworker
       bgw.run...
     
    End Sub
     
    private sub StartTraitement (sender as object, e as je sais plus quoi) Handles bgw.DoWork
      dim c as new compte
      c.go
    end sub

    ta sub completed doit être sur le form aussi pour avoir le handles


    après dans les faits ton addhandler ici fonctionnerait, mais ce n'est pas conseillé dans ce cas
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    les events c'est censé être simple
    par exemple l'event click de la classe button fait que lors du click, toutes les méthodes déclarées abonnées à cet event sont appelées
    sender contient l'instance de l'appelant (le bouton dans ce cas) et e les éventuels paramètres de l'event (par exemple les coordonnées pour l'event mousemove)
    ceci est fait tout de suite et en local, un peu comme le ferais du javascript en web
    ça ok, c'est comme en web, j'ai l'habitude de faire des raiseevents / public event dans mes usercontrols

    La partie events, ou je commence comme je dis à faire le "saute mouton" ce sont les délégués, même si je comprends le principe, c'est comme un pointage de référence pour une variable sauf que c'est une groupe d'instruction rassemblé sous forme de fonction que l'on attache.

    Citation Envoyé par Pol63 Voir le message
    dans l'event dowork tu peux instancier ta classe qui fait le traitement, lui dire de le faire, et attendre qu'elle ait fini
    tu places le résultat si c'est une fonction longue qui te le retourne (ou ton instance de cette classe si elle contient les résultats sous forme de propriétés) dans e.Result et c'est tout
    dans l'event completed tu peux modifier les controles de l'interface
    Je comprends bien pour le retour de l'event "DoWork".

    Je vais voir si je devrais utiliser le ProgressChanged ensuite car dans mon appli j'ai un listview en virtual mode qui justement liste des fichiers (mais ici je vais devoir ne lister qu'une fois que les fichiers sont en cours de regroupement en "media", ma phase 2, ma 1ère phase de EnumerateFiles en linq est rapide pour créer mes objets de fichier

    ---
    Résultat fonctionnel après les modifications suivante.
    il faut que je pense "WithEvents va de paire avec Handles, comme ça c'est plus facile ;-)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    Public Class formTest
     
        Public Delegate Sub SetFormEvt(sender As Object, e As GenerateTextEventArgs)
     
        Private WithEvents bgwCode As BackgroundWorker
     
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
     
            Button1.Enabled = False
     
            bgwCode = New BackgroundWorker
            bgwCode.WorkerReportsProgress = True
            bgwCode.WorkerSupportsCancellation = True
            bgwCode.RunWorkerAsync()
     
        End Sub
     
        Private Sub StartCompte(sender As Object, e As EventArgs) Handles bgwCode.DoWork
            Dim c As New Compte
            AddHandler c.OnTextChanged, AddressOf FormEvt
            c.Go()
        End Sub
     
        Private Sub FormEvt(sender As Object, e As GenerateTextEventArgs)
            If Label1.InvokeRequired Then
                Label1.Invoke(New SetFormEvt(AddressOf FormEvt), sender, e)
            Else
                Label1.Text = DirectCast(e, GenerateTextEventArgs).EventText '"CALL"
            End If
        End Sub
     
        Private Sub Fini(sender As Object, e As EventArgs) Handles bgwCode.RunWorkerCompleted
            Button1.Enabled = True
        End Sub
    End Class
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    pour avoir le droit d'écrire handles il faut que la variable soit déclarée withevents
    après c'est à la compilation que le code change pour faire les addhandler et removehandler qui vont avec de manière intelligente (gestion de changement de référence)
    c'est donc bien pratique

    un délégué est en effet un pointeur vers une méthode
    ce qui peut etre utile utile si tu as besoin d'une variable de ce type là
    c'est aussi la chose nécessaire quand on veut demander au thread principal d'exécuter quelque chose alors qu'on est sur un autre thread, il lui faut un pointeur pour savoir quoi exécuter
    avec le bgw ceci est géré nativement, donc en théorie tu ne devrais pas avoir besoin de délégué comme avec le cas d'un thread géré manuellement
    de nos jours le mot clé delegate n'est plus utilisé, il y a des classes pour faire des pointeurs plus lisibles comme action/func


    pour le progresschanged, c'est à toi dans le code attaché dowork de faire reportprogress, ce qui lèvera l'event progresschanged sur le thread principal (donc pas besoin de délégué non plus)
    et dans e on peut passer ce qu'on veut (un pourcentage, des instances de classes ...) ce qui permet soit d'animer une barre de progression soit d'ajouter des éléments obtenus (partie de toute une liste de fichier par exemple)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    pour le progresschanged, c'est à toi dans le code attaché dowork de faire reportprogress, ce qui lèvera l'event progresschanged sur le thread principal (donc pas besoin de délégué non plus)
    et dans e on peut passer ce qu'on veut (un pourcentage, des instances de classes ...) ce qui permet soit d'animer une barre de progression soit d'ajouter des éléments obtenus (partie de toute une liste de fichier par exemple)
    Ce que tu veux dire donc c'est que je n'ai plus besoin de remonter mes events via le seul addHandler qu'il me reste là ?

    mais par contre mon raiseEvent dans la méthode "Go" doit bien toujours être présente à moins que ce soit la classe GenerateTextEventsArgs qui doit remonter à la progression, mais je pensais que celle-ci aurait été générique pour d'autres traitement par exemple issu d'un autre bouton...

    Dans ma tête le progressChanged était plus sur l'ensemble du traitement (ici StartCompte par exemple dans lequel on pourrait mettre d'autres appel à chaîner)
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  10. #10
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    pas compris (c'est toujours pas bon signe ^^)

    mais si tu as le code suivant

    ligne 1
    ligne 2
    ligne 3

    et que ligne 2 c'est le truc long de ta classe compte, alors tu n'arrives sur ligne 3 qu'après le temps d'exécution de ligne 2
    un event sert à être averti de quelque chose, ici tu n'as pas besoin d'être averti de la fin de ton traitement si celui ci est synchrone
    tu as juste à utiliser les events du bgw

    il est rare d'avoir des events dans des classes non graphiques n'ayant pas de thread interne


    et progresschanged on est d'accord qu'on parle de l'event du bgw ?
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  11. #11
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour


    Le but étant d'avoir les différentes informations remontés par événements.
    Exemple : Phase 1.. en cours etc ... (% si la phase le permet) et également de retourner par exemple : x fichiers trouvés puis dans les phase suivantes d'indiquer x médias (regroupement des fichiers) x erreurs (genre mauvais nommage, car le nom du fichier doit commencer pareil que le nom du répertoire)
    Plus comlexe que cela te parait car il faut implémenter un class dérivé de Component (un composant) suivant le modèle ou patron "modèle asynchrone basé sur des événements " décrit dans la rubrique MSDN FR Help intitulé
    "Comment : implémenter un composant qui prend en charge le modèle asynchrone basé sur des événements" (exemple)...
    lien
    https://www.google.fr/url?sa=t&rct=j...39782543,d.bGg

    Cet exemple decrit pas à pas les étapes ....
    bon code...

  12. #12
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Bonjour,

    Merci Mabrouki !

    Je viens à l'instant d'intégrer la partie asynchrone dans mon projet après être passé par différentes étapes :
    • Lecture de l'ensemble de la rubrique
    • saisie de l'exemple (debug : ben oui des fautes dans ma saisie )
    • puis j'ai refais l'exemple avec juste des labels et boutons et sans la partie "composant" directement avec un formulaire via le designer et une classe (pour me rapprocher au mieux de mon projet)
    • Puis j'ai modifié cette exemple pour tenter de remonter des choses différente dans l'événement ProgressChanged (mais je ne sais pas si c'est correct)
    • Puis je viens donc de finir l'intégration dans mon projet avec juste la partie completed et la 1ère progression de remonté.


    J'ai donc une question :

    Ma classe de progression remonte pour le moment 3 éléments :
    • l'étape en cours du traitement (pour le moment un integer mais sans dout plus tard un enum)
    • le pourcentage (ici 0 : je ferais surement un ratio par rapport aux nombre d'Etape et celle en cours
    • et mon objet "asyncOp"


    Mon worker :
    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
      Public Sub getMediaWorker(asyncOp As ComponentModel.AsyncOperation)
     
            Dim exc As Exception = Nothing
     
            If Not Me.TaskCanceled(asyncOp.UserSuppliedState) Then
                Try
                    'event Phase : "Phase 1 commencé "
                    Dim e As ComponentModel.ProgressChangedEventArgs = Nothing
                    e = New MediaListProgressChangedEventArgs(1, 0, asyncOp.UserSuppliedState)
                    asyncOp.Post(Me.OnProgressDelegate, e)
                    Thread.Sleep(0)
     
                    Dim videoFiles As List(Of videoFile3) = GetVideoFiles()
     
                    e = New MediaListProgressChangedEventArgs(2, 0, asyncOp.UserSuppliedState)
                    asyncOp.Post(Me.OnProgressDelegate, e)
                    Thread.Sleep(0)
     
                Catch mle As exceptions.MediaListException
                    exc = mle
                Catch ex As Exception
                    exc = ex
                End Try
            End If
     
            'Traitement terminé : appel fin de tache et remonter infos
            Me.CompletionMethod(exc, TaskCanceled(asyncOp.UserSuppliedState), asyncOp)
     
        End Sub

    Mais je voudrais également avoir d'autre type de progression.
    Mon étape 1 consiste à scanner les fichiers (donc à la fin de l'étape 1 je voudrais sur le formulaire pouvoir remonter le nombre de fichiers trouvés : "videoFile.count")

    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    Public Function GetVideoFiles() As List(Of videoFile3)
     
            Dim exts = AutorizedExtension.ToArray
            Dim videoFiles As List(Of videoFile3) = Nothing
     
            Try
     
                Dim f = From fichier In Directory.EnumerateFiles("*", SearchOption.AllDirectories)
                        Where exts.Contains(fichier.Extension.ToLower)
                        Order By fichier.FullName Ascending
     
                videoFiles = (From element In f
                              Select New videoFile3(element)).ToList
     
            Catch DirNotFound As DirectoryNotFoundException
                Throw New Exceptions.MediaListException(DirNotFound.Message)
            Catch UnAuthDir As UnauthorizedAccessException
                Throw New Exceptions.MediaListException(UnAuthDir.Message)
            Catch LongPath As PathTooLongException
                Throw New Exceptions.MediaListException(LongPath.Message)
            Catch ex As Exception
                Throw New Exceptions.MediaListException(ex.Message)
            End Try
     
            Return videoFiles
     
        End Function

    L'étape 2 consiste à répartir dans des groupes les fichiers (si ce sont des séries>Saisons>Episode>x fichier(s))
    je voudrais donc dans la méthode de l'étape 2 remonter l'avancement du traitement de la répartition.
    exemple (dans le cas de ce que j'appelle "média saisonnier") :
    2000 fichiers trouvés.
    Répartition en cours : 30 / 2000 | 2 séries, 2 saisons pour un total de 28 épisodes.

    l'étape 3 est encore différentes, j'analyse le contenu de chaque fichier via MediaInfo, donc un certain temps par fichier et j'indiquerais combien de fichiers sont traité/terminé

    Donc ma question est dois-je modifier ma classe de progression et y ajouter d'autre membres même si non utilisés dans certains cas ? et du coup d'autre constructeur en fonction des paramètres
    Ou une autre classe finalement, une par étape ?

    Ma classe pour la progression
    Code vb.net : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    Imports System.ComponentModel
     
    Public Class MediaListProgressChangedEventArgs
        Inherits ProgressChangedEventArgs
     
        Private _etape As Integer
     
        Public ReadOnly Property Etape() As Integer
            Get
                Return _etape
            End Get
        End Property
     
        Public Sub New(progressPercentage As Integer, userState As Object)
            MyBase.New(progressPercentage, userState)
        End Sub
     
        Public Sub New(numEtape As Integer, progressPercentage As Integer, userState As Object)
            Me.New(progressPercentage, userState)
            _etape = numEtape
        End Sub
     
    End Class

    Merci de ton aide !

    Citation Envoyé par MABROUKI Voir le message
    bonjour



    Plus comlexe que cela te parait car il faut implémenter un class dérivé de Component (un composant) suivant le modèle ou patron "modèle asynchrone basé sur des événements " décrit dans la rubrique MSDN FR Help intitulé
    "Comment : implémenter un composant qui prend en charge le modèle asynchrone basé sur des événements" (exemple)...
    lien
    https://www.google.fr/url?sa=t&rct=j...39782543,d.bGg

    Cet exemple decrit pas à pas les étapes ....
    bon code...
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  13. #13
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Du fait que les traitements des étape sont différents un Class par traitement s'impose à l'évidence ...
    De plus les étapes 2 et 3 ne peuvent lancés qu'à la fin de l'étape 1 (les fichiers à traiter sont disponibles à la fin de l'étape 1)...

    Donc un 1er thread pour l'étape 1 à partir de Main.....
    2eme et 3eme Thread pour étape 2 et 3 mais lancés simultanément à partir de Main.


    Bon code ....

  14. #14
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Ok, mais petite précision quand même.

    Quand tu dis une classe par traitement, tu veux dire une classe "MediaList_Etape1ProgressChangedEventArgs" puis une autre "MediaList_Etape2ProgressChangedEventArgs"

    ou tu veux dire une classe différente "au global" ?

    Parce que depuis mon winform au clic, je crée une instance et j'appelle ma classe "MediaList" qui appel :
    - getMediaAsync(taskId As Object) > mon Worker dans lequel j'ai une méthode appelé par étape

    ou, ce que tu veux dire dans ma classe MediaList ...>mon worker(main) et dans celui ci 1 instance de classe par étape ?

    encore merci.

    Citation Envoyé par MABROUKI Voir le message
    bonjour

    Du fait que les traitements des étape sont différents un Class par traitement s'impose à l'évidence ...
    De plus les étapes 2 et 3 ne peuvent lancés qu'à la fin de l'étape 1 (les fichiers à traiter sont disponibles à la fin de l'étape 1)...

    Donc un 1er thread pour l'étape 1 à partir de Main.....
    2eme et 3eme Thread pour étape 2 et 3 mais lancés simultanément à partir de Main.


    Bon code ....
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  15. #15
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    Re

    Tu peux faire un seul Class global chargé des 3 traitements donc :
    1/etape1
    - son Delegate
    - son class MediaList_Step1ProgressChangedEventArgs
    - NB:il manque un class MediaListCompletedEventArgs

    2/etape2 et etape3 idem.

    Ce que je veux dire c'est que le List(Of videoFile3) est disponible à l'etape1
    Donc il faut :
    - instancier le class Global à nouveau avec le List(Of videoFile3) susmentionnée
    et appeler sa method2
    - instancier le class Global à nouveau avec le List(Of videoFile3) susmentionné
    et appeler sa method3



    voici un code fonctionnel à adapter et compléter :
    code .vb pour les class Args et Class Global
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    Imports System.ComponentModel
    Public Class MediaListProgressChangedEventArgs
        Inherits ProgressChangedEventArgs
        Private _etape As Integer
        Public ReadOnly Property Etape() As Integer
            Get
                Return _etape
            End Get
        End Property
        Public Sub New(ByVal numEtape As Integer,
                       ByVal progressPercentage As Integer,
                       ByVal userState As Object)
            MyBase.New(progressPercentage, userState)
            _etape = numEtape
        End Sub
    End Class
    Public Class MediaListCompletedEventArgs
        Inherits AsyncCompletedEventArgs
        Private _countFile As Integer
     
        Public ReadOnly Property CountFile() As Integer
            Get
                Return _countFile
            End Get
        End Property
        Private _videofiles As List(Of VideoFile)
     
        Public ReadOnly Property VideoFiles() As List(Of VideoFile)
            Get
                Return _videofiles
            End Get
        End Property
        Public Sub New(ByVal count As Integer, ByVal vids As List(Of VideoFile), ByVal ex As Exception, ByVal canceled As Boolean, ByVal userState As Object)
            MyBase.New(ex, canceled, userState)
            _countFile = count
            _videofiles = vids
        End Sub
     
    End Class
    '*************************************************************
    ' TODO
    'les autres Class à rajouter à l'avenant 
    '+les  delegates   +les methodes de traitement  appropries
    Public Class MediaListProgress2ChangedEventArgs
        Inherits ProgressChangedEventArgs
     
    End Class
    Public Class MediaListCompleted2EventArgs
        Inherits AsyncCompletedEventArgs
     
    End Class
    Public Class MediaListProgress3ChangedEventArgs
        Inherits ProgressChangedEventArgs
     
    End Class
    Public Class MediaListCompleted3EventArgs
        Inherits AsyncCompletedEventArgs
     
    End Class
    code .vb pour Class Global

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
     
     
    '***********CLASS GLOBAL****************************
     
    Imports System.Threading
    Imports System.Collections.Specialized
    Imports System.ComponentModel
    Imports System.IO
    Public Delegate Sub Method1CompletedEventHandler(ByVal sender As Object, ByVal e As MediaListCompletedEventArgs)
    Public Delegate Sub ProgressChangedEventHandler(ByVal e As MediaListProgressChangedEventArgs)
     
    Public Class MediaListStep
     
        'delegate Worker asynchronous
        Private Delegate Sub WorkerEventHandler(ByVal message As String, ByVal asyncOp As AsyncOperation)
     
        'delegate  posts 
        Private onCompletedDelegate As SendOrPostCallback
        Private onProgressReportDelegate As SendOrPostCallback
     
        'Events for the main thread.
        Public Event Method1Completed As Method1CompletedEventHandler
        Public Event ProgressChanged As ProgressChangedEventHandler
        Public Sub New()
            InitializeDelegates()
        End Sub
        Protected Overridable Sub InitializeDelegates()
            onProgressReportDelegate =
                New SendOrPostCallback(AddressOf ReportProgressFunc)
            onCompletedDelegate =
                New SendOrPostCallback(AddressOf CompletedDelegateFunc)
        End Sub
        ' function  called by SendOrPostCallback to raise Method1Completed Event
        Private Sub CompletedDelegateFunc(ByVal state As Object)
            Dim e As MediaListCompletedEventArgs = state
            OnCompleted(e)
        End Sub
        Protected Sub OnCompleted(ByVal state As Object)
            Dim e As MediaListCompletedEventArgs = state
            RaiseEvent Method1Completed(Me, e)
     
        End Sub
        ' function  called by SendOrPostCallback to raise ProgressChanged Event
        Private Sub ReportProgressFunc(ByVal state As Object)
            Dim e As ProgressChangedEventArgs = state
            OnProgressChanged(e)
     
        End Sub
        Protected Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)
            RaiseEvent ProgressChanged(e)
        End Sub
        'Synchrnous version of the method
        Public Sub Method1(ByVal message As String)
            For i As Integer = 1 To 100000
                'Do some time consuming process
            Next
     
        End Sub
        'Asynchoronous version of the method
        Public Sub Method1Async(ByVal message As String, ByVal userState As Object)
            Dim asyncOp As AsyncOperation = AsyncOperationManager.CreateOperation(userState)
     
            Dim worker As WorkerEventHandler = New WorkerEventHandler(AddressOf Method1Worker)
     
            'Execute process Asynchronously
            worker.BeginInvoke(message, asyncOp, Nothing, Nothing)
        End Sub
     
        'This method does the actual work
        Private Sub Method1Worker(ByVal message As String, ByVal asyncOp As AsyncOperation)
            Dim progressArgs As MediaListProgressChangedEventArgs = Nothing
     
            Dim dir As DirectoryInfo = New DirectoryInfo("C:\Users\OUNIS\Desktop")
            Dim files As IEnumerable(Of FileInfo) = Dir.EnumerateFiles()
            Dim N As Integer = 0
            Dim VideoFiles = New List(Of VideoFile)
            For Each file In files
                'Do some time consuming process
                VideoFiles.Add(New VideoFile(file.Name, file.Length))
                progressArgs = New MediaListProgressChangedEventArgs(N,
                                              CSng(N / VideoFiles.Count) * 100, asyncOp.UserSuppliedState)
                asyncOp.Post(onProgressReportDelegate, progressArgs)
     
                N += 1
                ' Yield the rest of this time slice.
                Thread.Sleep(0)
     
            Next
            Dim completArgs As MediaListCompletedEventArgs = New MediaListCompletedEventArgs(
                                                   VideoFiles.Count, VideoFiles,
                                                   Nothing, False, asyncOp.UserSuppliedState)
     
     
            asyncOp.PostOperationCompleted(onCompletedDelegate, completArgs)
        End Sub
     
    End Class
    code .vb du Form user :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    Public Class Form1
        Private WithEvents demo As MediaListStep
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            lblAsync1.Text = ""
            lblAsync2.Text = ""
            lblSynchronous.Text = ""
            demo = New MediaListStep()
            demo.Method1Async("Async 1", "Async1")
        End Sub
     
        Private Sub demo_Method1Completed(ByVal sender As Object, ByVal e As MediaListCompletedEventArgs) Handles demo.Method1Completed
            lblAsync2.Text = e.CountFile.ToString
            lblSynchronous.Text = e.UserState.ToString() + " completed."
     
            ListBox1.DataSource = e.VideoFiles
            ListBox1.DisplayMember = "Name"
        End Sub
     
        Private Sub demo_ProgressChanged(ByVal e As MediaListProgressChangedEventArgs) Handles demo.ProgressChanged
            If e.UserState.ToString = "Async1" Then
                lblAsync1.Text = e.UserState.ToString + " : " + e.ProgressPercentage.ToString
     
            End If
     
        End Sub
    End Class
    bon code....

  16. #16
    Membre du Club
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    128
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Bâtiment

    Informations forums :
    Inscription : Juillet 2006
    Messages : 128
    Points : 61
    Points
    61
    Par défaut
    Bonsoir,

    le "MediaListCompletedEventArgs", je l'avais fais, mais ne l'avais pas mis dans le Post volontairement.

    Sinon j' étais parti comme ceci :

    1 Class pour le completed (general)
    1 Class pour la progression de l'étape1
    1 Class pour la progression de l'étape2
    1 Class pour la progression de l'étape3

    Une question quand même, c'est peut-être bête...
    Tu me dis de ré-instancier un nouvelle fois la classe global, quel intérêt ?
    sachant que videoFile est présent à la fin de l'étape 1, il est présent dans la classe
    en variable de la classe.
    L'étape 2 travaillant ensuite avec, celle-ci étant appelé à la fin du traitement de l'étape1
    idem pour l'étape 3, ce dernier générant un autre objet englobant des videoFile "groupé" :

    exemple : MediaSaisonnier >Serie >Saison >Episode >List(Of VideoFile)

    J'ai 2 classes principales (MediaClassique & MediaSaisonnier, héritants de Media en MustInherits)


    L’événement completed (donc global), permettra de donner accès à d'autre boutons dans l'interface

    Nota par curiosité: La partie "Method1" non asynchrone, doit elle forcément reprendre le même code (copier/coller) que dans la version Asynchrone, sans les retours spécifique, il n'y a pas moyen de "mettre du code en commun ?

    Merci beaucoup Mabrouki pour ton aide et ta patience, j'ai appris beaucoup et j'espère que ce sera utile également à d'autres.
    -----------------------------------------
    à l'origine PHP/Mysql. Pro : Asp.net/Vb/SQL/Webform siteweb

  17. #17
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    rebonjour


    Une question quand même, c'est peut-être bête...
    Tu me dis de ré-instancier un nouvelle fois la classe global, quel intérêt ?
    Afin de d'initialiser une copie du List(of VideoFile3) pour les 2 Méthods 2 et 3 car il va y avoir un problème d'accès concurrentiel si les 2 méthode reçoivent une simple référence sur ce List...


    La partie "Method1" non asynchrone, doit elle forcément reprendre le même code (copier/coller) que dans la version Asynchrone, sans les
    Même code mais pour des traitements moins long c'est tout bête....!!!

Discussions similaires

  1. [Integration] Lancer un thread depuis Spring intégration après insertion message en base
    Par jamesleouf dans le forum Spring
    Réponses: 1
    Dernier message: 10/01/2014, 07h18
  2. [Débutant] Aide intégration threads
    Par marcm89 dans le forum C#
    Réponses: 2
    Dernier message: 08/10/2013, 21h47
  3. Soucis intégration Thread/Swing
    Par Balbuzard dans le forum Débuter
    Réponses: 2
    Dernier message: 19/08/2008, 10h54
  4. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  5. [Kylix] Pb de Thread !!
    Par Anonymous dans le forum EDI
    Réponses: 1
    Dernier message: 25/04/2002, 13h53

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo