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

VB.NET Discussion :

Invoke Delegate - plus souple


Sujet :

VB.NET

  1. #1
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut Invoke Delegate - plus souple
    Bonjour à tous,


    J'aimerais savoir s'il y a un moyen de crée une méthode plus générique pour changer un objet graphique depuis un autre thread.

    Actuellement je crée une méthode par objet à modifier, par exemple pour changer un label:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Private Delegate Sub Changetext(ByVal txt As String)
     
    Public Sub ChangeLabel(ByVal txt As String)
            If Me.InvokeRequired Then
                Me.Invoke(New Changetext(AddressOf ChangeLabel), txt)
            Else
                lblMonLabel.Text =  txt
            End If
        End Sub
    Du coup cela peux me faire par mal de méthode qui se ressemble pour chaque objet a modifier.

    Je pensais à quelque chose comme récupérer dans l'autre thread les caractéristique de l'objet, le modifier puis le renvoyer, mais je vois pas trop comment faire.

    Merci de votre aide

  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
    ca peut se condenser de plusieurs manières
    sur vs 2010 depuis la méthode qui exécutée depuis un autre thread ca donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lblMonLabel.invoke(new action() sub() lblMonLabel.Text =  "valeur")
    ca permet donc de manipuler les variables en cours d'utilisation


    sub permet de créer une sub anonymes, on peut aussi faire des sub de plusieurs lignes de la sorte

    avant vs 2010 on peut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    .invoke(new action(of string)(addressof laméthode), "valeur")
     
    private sub laméthode (txt as string)
      lelabel.text = txt
    end sub
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Merci pour l'info.

    Toutefois je vois pas trop comment la mettre en oeuvre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    lblMonLabel.invoke(new action() sub() lblMonLabel.Text =  "valeur")
    Apparemment vous me dites que cela s’exécute a partir de mon autre thread. Mais mon autre thread ne connait pas "lblMonLabel"


    Sa serait éventuellement (j'ai pas testé):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    frmMain.lblMonLabel.invoke(new action() sub() lblMonLabel.Text =  "valeur")
    ou frmMain serait déclaré dans un module:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public frmMain as formMain
    J'ai pas testé pour le moment mais j'essaie de comprendre.

  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
    Citation Envoyé par megamario Voir le message
    Mais mon autre thread ne connait pas "lblMonLabel"
    si tu veux dire par là que le label est sur un autre thread, certes, mais ca ne limite en rien
    une variable n'est pas visible que depuis un thread mais depuis tous, c'est juste une question de portée après
    ce qui est autre chose que le fait qu'un controle ne soit pas modifiable depuis un autre thread ; il reste accessible

    si tu veux dire par là que depuis la sub qui est threadée tu n'as pas accès la lblMonLabel alors le code que nous as donné en exemple n'as aucune raison de fonctionner non plus ...


    si le code de ton thread est au même endroit que le code behind du form, il n'y a pas de soucis

    si le code ton thread est dans une autre classe il faut que cette classe connaisse le form ou le label (donc lui passer une référence, par exemple à la création)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    si tu veux dire par là que le label est sur un autre thread, certes, mais ca ne limite en rien
    une variable n'est pas visible que depuis un thread mais depuis tous, c'est juste une question de portée après
    ce qui est autre chose que le fait qu'un controle ne soit pas modifiable depuis un autre thread ; il reste accessible

    si tu veux dire par là que depuis la sub qui est threadée tu n'as pas accès la lblMonLabel alors le code que nous as donné en exemple n'as aucune raison de fonctionner non plus ...


    si le code de ton thread est au même endroit que le code behind du form, il n'y a pas de soucis

    si le code ton thread est dans une autre classe il faut que cette classe connaisse le form ou le label (donc lui passer une référence, par exemple à la création)
    Merci déjà de t’intéresser a mon petit souci.


    Explication :

    En fait j'essaie de tout séparer, dans la form il n'y a que ce qu'il y a dans la form, donc gestion des évènement du à l'interface IHM, éventuellement des timers.

    Ensuite j'ai des classes ou l'algo de fonctionnement se retrouve.

    L'une d'entre elle me sert de communication avec le port COM. La boucle qui tourne pour lire le port COM est lancé par un autre thread.
    Donc tout ce qui découle de la lecture de mon Port COM se retrouve dans ce thread.
    L’analyse des trames par exemple. Dans l'une des trames se trouve la vitesse de COM final, car je dois la changer pour le client final, suivant sont application.

    Lorsque je trouve cette trame je la décortique et j'envoie l'information sur mon formulaire, le label, pour indiquer la vitesse de COM final entre autre car du coup je change aussi ma vitesse de COM.


    C'est une explication de l'une de mes applications en cours. Mais j'ai d'autre thread (pour telnet par exemple) etc...

    Plusieurs données à transmettre d'un thread à un autre pour l'affichage dans le formulaire.


    En ce qui concerne mon code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Private Delegate Sub Changetext(ByVal txt As String)
     
    Public Sub ChangeLabel(ByVal txt As String)
            If Me.InvokeRequired Then
                Me.Invoke(New Changetext(AddressOf ChangeLabel), txt)
            Else
                lblMonLabel.Text =  txt
            End If
        End Sub
    Sa il se trouve dans le formulaire appelé : formMain

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    j'ai dans module
     
    public frmMain as formMain
     
    sub Main()
        frmMain = new formMain
        frmMain.showdialogue()  'Je l'écrit de tête
    end sub
    Depuis mon thread je fait (en simplifiant):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    frmMain.ChangeLabel("Nouveau baudrate = 115200")
    et sa cela fonctionne bien.
    Lorsque le thread appel la fonction il passe par le:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      If Me.InvokeRequired Then
                Me.Invoke(New Changetext(AddressOf ChangeLabel), txt)
    Puis sort et l'appli lance bien cette même fonction (lorsqu'elle est libre si j'ai bien compris) et modifie mon label.

  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
    Citation Envoyé par megamario Voir le message
    En fait j'essaie de tout séparer, dans la form il n'y a que ce qu'il y a dans la form, donc gestion des évènement du à l'interface IHM, éventuellement des timers.
    ca c'est un bon point

    Citation Envoyé par megamario Voir le message
    Lorsque je trouve cette trame je la décortique et j'envoie l'information sur mon formulaire, le label, pour indiquer la vitesse de COM final entre autre car du coup je change aussi ma vitesse de COM.
    ca c'est moins bien
    une classe de traitement ne doit pas dialoguer avec un form, il faut une classe de données intermédiaire
    j'y reviens plus bas

    Citation Envoyé par megamario Voir le message
    j'ai dans module
    public frmMain as formMain
    (...)
    Depuis mon thread je fait (en simplifiant):
    frmMain.ChangeLabel("Nouveau baudrate = 115200")
    donc dans ce cas tu vois comment adapter ce que je t'ai dis
    si tu fais frmMain.ChangeLabel, tu dois pouvoir faire frmMain.Invoke (...) frmMain.lbl.text = "valeur

    Citation Envoyé par megamario Voir le message
    (lorsqu'elle est libre si j'ai bien compris)
    en fait tout ce que doit faire le thread principal est mis sur une pile, quand la pile n'est pas vide chaque élément est traité chacun son tour
    cliquer sur un bouton met les subs liés à cet évènement sur la pile
    faire invoke met aussi sur la pile donc c'est bien quand le thread est dispo qu'il le fera (enfin souvent c'est quelques nanosecondes)


    donc je disais qu'il faut une classe intermédiaire

    si ton thread va lire une info sur le port com, il faut que ton thread stocke cette info dans une propriété
    et dans ton interface tu n'as qu'à lire cette propriété

    si ton port com te sers à lire plusieuers infos relatives à une même chose tu fais une classe [meme chose] avec en propriétés les différentes infos

    et du coup ca simplifie le travail, si la ou les instances de données sont sur un module, le thread peut écrire dedans, et l'interface peut lire dedans
    là ou c'est plus simple c'est que tu peux rendre ca asynchrone si ca ne pose pas de problèmes sur le traitement
    à savoir un timer sur le form qui toutes les x millisecondes va faire labelmachin.text = instance.propriété
    le timer étant exécuté sur le thread principal il n'y a pas besoin de délégué
    le thread lui a le droit de modifier une propriété qui n'est pas sur un control directement aussi

    attention, pour les collections, si un thread fait un for each pendant qu'un autre fait .add ca plante, il y a alors besoin de mettre des mécanismes de verrouillages
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Merci beaucoup pour toutes ces explications, je ne suis pas au boulot a cette heure donc j'ai pas sa devant moi mais merci.

    Je pense avoir compris ce que vous vouliez dire.

    En ce qui concerne les protections des données j'utilise des sémaphores.

    Par contre je m'éloigne un peu du sujet de base, mais je comprend toujours pas l'utilité de déclarer des sémaphores avec plusieurs prise (je sais plus le nom) possible.

    par exemple ce que je fait:
    private semLabel1 as new semaphore(1,1);

    mais on peut faire
    private semLabel1 as new semaphore(2,1);

    lorsque j'ai besoin de lire ou écrire dans la donnée protégé:

    semLabel1.Waitone()
    ..........
    ..........
    selLabel1.Release()

    Je vois pas l’intérêt que 2 instance puisse accéder à la donnée protégée.

    D'ailleurs WaitOne n'est pas proposé directement par VisualStudio, il doit surement y avoir une autre méthode. Mais bon je sort du sujet la.


    Pour revenir au sujet j'ai une petite idée par rapport a mon souci et faire ce que je souhaitait c'est à dire appeler l'objet et non l'objet.text. Pour éviter d'avoir une méthode à chaque modification que l'on souhaite faire. text, visible, enabled, etc...

    En prenant votre principe il suffit je pense que je crée une méthode avec des déclaration d'objet, image des objets du formulaire. Je pense que c'est faisable

    Dans le Module

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public Monlabel1 as Label
    Dans le thread je modifie cet objet suivant ce que j'ai besoin avec les protections nécessaire.

    Dans le formulaire j'initialise au démarrage le MonLabel1 par exemple dans l’évènement load avec

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Monlabel1 = new Label
    Monlabel1 = lblLabel1
    lblLabel1 étant mon label sur la form
    Avec les protections nécessaire si besoin suivant l'ordre des instanciations des classes.

    Puis dans un timer, avec les protections, je fait l'inverse, je copie le Monlabel1 dans lblLabel1.

    Est-ce possible? cela risque pas de faire scintiller les objets?

  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
    Citation Envoyé par megamario Voir le message
    En ce qui concerne les protections des données j'utilise des sémaphores.

    Par contre je m'éloigne un peu du sujet de base, mais je comprend toujours pas l'utilité de déclarer des sémaphores avec plusieurs prise (je sais plus le nom) possible.
    je n'ai jamais utilisé les semaphores, mais au vue de ce qu'msdn en dit ca ne sert pas réellement à verrouiller, vu qu'on peut laisser plusieurs threads s'exécuter
    pour limiter à un thread il y a synclock
    pour plus de performances il y a le readerwriterlock ; dans mon exemple d'une collection à protéger, plusieurs personnes peuvent itérer la collection sans problème, par contre pour ajouter un élément il faut être seul à utiliser la collection, là le readerwriterlock sera plus performant que le synclock

    Citation Envoyé par megamario Voir le message
    Dans le Module

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public Monlabel1 as Label
    je n'ai pas dit ca du tout, ca laisse le même problème et c'est encore plus moche !

    il faut penser objet
    imaginons que ton port com te sert à récupérer la vitesse de moteurs

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class moteur
      public property id as integer
      public property nom as string
     
      public property numeroEscalveCOM as string
     
      public property connectionok as boolean
      public property vitesse as integer?
    end class
    sur un module :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public moteurs as new list(of moteur)
    sur ton thread de com :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for each m as moteur in moteurs
      'envoi trame en se servant de m.numeroEscalveCOM (si besoin, sur cetaines com on peut avoir plusieurs choses en série)
      'si pas de réponse : m.connectionok = false : m.vitesse = nothing
      'si réponse : m.connectionok = ok: m.vitesse = valeur_lue
    next
    sur ton form
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private _moteursLabels as new dictionary(of moteur, label)
     
    sub timer.tick
      for each m as moteur
         if m.connectionok then
           moteursLabels(m).text = m.vitesse
         else
           moteursLabels(m).text = "pas de réponse"
         end if
      next
    end sub
    il reste à coder le remplissage de la collection (base de données ?) et du dictionnaire (sur le sub new du form)

    mais là le code est simple, lisible, et il n'y a pas d'invoke
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Merci encore pour toutes ces informations.

    J'avoue qu'hier je comprenais pas tout .

    Ce matin cela va mieux, à part quelques style d’écriture que je ne connaissais pas, (of moteur) par exemple.

    Je prend note. Part contre cela oblige a avoir une méthode (dans le formulaire) par modification text, visible, enable etc..

Discussions similaires

  1. Réponses: 5
    Dernier message: 01/12/2010, 10h03
  2. [WD-2003] Formulaire : comment rendre la mise en page plus souple ?
    Par Lucie_ dans le forum Word
    Réponses: 3
    Dernier message: 16/11/2010, 17h02
  3. Conversion Invoke Delegate C# en VB.net
    Par megamario dans le forum Visual Studio
    Réponses: 0
    Dernier message: 08/04/2010, 10h47
  4. [C#][Thread][Invoke] petit problème de delegate
    Par clinic dans le forum Général Dotnet
    Réponses: 3
    Dernier message: 22/06/2007, 11h38
  5. [P/Invoke/Delegates] Finesse d'un wrapper P/Invoke
    Par DeusXL dans le forum C++/CLI
    Réponses: 3
    Dernier message: 12/09/2006, 12h48

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