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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Nord (Nord Pas de Calais)

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 130
    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

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    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 confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Nord (Nord Pas de Calais)

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 130
    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...)

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    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 confirmé
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juillet 2006
    Messages
    130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Nord (Nord Pas de Calais)

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 130
    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

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    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

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

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 130
    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

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    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

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