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

C# Discussion :

Modification formulaire à chaque Elapsed d'un Timer


Sujet :

C#

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    351
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 351
    Points : 321
    Points
    321
    Par défaut Modification formulaire à chaque Elapsed d'un Timer
    Bonjour,

    J'ai un problème que je tente de résoudre depuis deux jours sans succès en C#, framework 4 et WinForms

    Cela se présente sous deux parties :
    -Une librairie de classes contenant un formulaire : celui-ci se contente d'afficher une notification (comme outlook ou messenger) avec une petite animation (changement de l'Opacity et changement de la Location de la Form). L'animation est gérée avec un System.Timers.Timer afin d'incrémenter à chaque évènement Elapsed (Tick) les valeurs de l'Opacity et la Location

    -Un projet WF contenant un Formulaire : celui-ci permet de renseigner les paramètres à la DLL (le formulaire de notification) et d'afficher cette notification. Ce formulaire contient également un System.Timers.Timer qui va, toutes les 30 secondes, afficher une notification.

    Mon problème est qu'une erreur se produit lors du changement des valeurs de la fenêtre de notification (dans la DLL) Opacity et Location
    Cross-thread operation not valid: Control 'NotificationForm' accessed from a thread other than the thread it was created on.
    Je tiens à préciser que si on n'utilise pas de Timer dans le formulaire appelant, les notifications s'affichent correctement.

    Est-ce que quelqu'un aurait une suggestion? idée? solution?

    Si besoin de précisions, n'hésitez pas

    Merci beaucoup

  2. #2
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 082
    Points
    8 082
    Par défaut
    Le callback du timer est executé sur un thread autre que le thread de l'interface. Or, les élements de l'interface ne peuvent être manipulés que par le thread de l'interface.
    Il faut donc que ton traitement dans le callback rappelle le thread de l'UI. En WPF ca se fait avec le dispatcher, en winform je ne suis pas sur. Le problème à été moult fois abordé sur ce forum

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Utilise Control.Invoke pour exécuter le code sur le thread de l'UI. Ou alors, plus simplement, utilise un timer WinForms (System.Windows.Forms.Timer), qui exécute l'évènement Tick sur le thread de l'UI.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    351
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 351
    Points : 321
    Points
    321
    Par défaut
    Merci de vos réponses.

    Effectivement, en n'utilisant QUE des System.Windows.Forms.Timer ça fonctionne nickel.

    Et, imaginons que je veuille, depuis un System.Timers.Timer, changer un élément de l'UI quelconque. Etant donné que le Timer se retrouve dans un Thread à part du UI Thread, comment faut-il faire d'un côté et de l'autre dans une application WinForms standard?

    Petite aparté, on ne peut pas faire de Control.Invoke depuis notre formulaire car il n'y a aucun contrôle dans le formulaire. La raison est qu'on utilise le framework eXpress Application Framework de Devexpress, et qu'il utilise un Design Pattern orienté données. Si vous connaissez pas, c'est ce qu'essaie de reproduire LightSwitch. Les controls étant générés dynamiquement.

    Merci

    P.S : Désolé je suis pas fortiche en ce qui concerne le Threading

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par marcusien Voir le message
    Et, imaginons que je veuille, depuis un System.Timers.Timer, changer un élément de l'UI quelconque. Etant donné que le Timer se retrouve dans un Thread à part du UI Thread, comment faut-il faire d'un côté et de l'autre dans une application WinForms standard?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void ElapsedEventHandler(object sender, ElapsedEventArgs e)
    {
        // Ne fonctionne pas :
        // this.Opacity = 0.5
     
        // Fonctionne :
        this.Invoke(new Action(() => this.Opacity = 0.5));
    }
    (tu peux aussi utiliser une méthode normale au lieu d'une méthode anonyme)

    Citation Envoyé par marcusien Voir le message
    Petite aparté, on ne peut pas faire de Control.Invoke depuis notre formulaire car il n'y a aucun contrôle dans le formulaire. La raison est qu'on utilise le framework eXpress Application Framework de Devexpress, et qu'il utilise un Design Pattern orienté données. Si vous connaissez pas, c'est ce qu'essaie de reproduire LightSwitch. Les controls étant générés dynamiquement.
    Là je sais pas trop... le formulaire lui-même hérite quand même de Form, non ? Dans ce cas tu peux appeler Invoke sur le formulaire.

  6. #6
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 082
    Points
    8 082
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void ElapsedEventHandler(object sender, ElapsedEventArgs e)
    {
        // Ne fonctionne pas :
        // this.Opacity = 0.5
     
        // Fonctionne :
        this.Invoke(new Action(() => this.Opacity = 0.5));
    }
    (tu peux aussi utiliser une méthode normale au lieu d'une méthode anonyme)



    Là je sais pas trop... le formulaire lui-même hérite quand même de Form, non ? Dans ce cas tu peux appeler Invoke sur le formulaire.
    Tu peux peut-être enregistrer le thread de l'ui dans un singleton. Y'a un truc un peu analogue qui était fait dans le MVVM Light Toolkit pour WPF/Silverlight.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    351
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Côte d'Or (Bourgogne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 351
    Points : 321
    Points
    321
    Par défaut
    Merci pour le délégué anonyme. J'essaierai plus tard de faire comme ça.
    Citation Envoyé par tomlev Voir le message
    Là je sais pas trop... le formulaire lui-même hérite quand même de Form, non ? Dans ce cas tu peux appeler Invoke sur le formulaire.
    Le formulaire hérite de WinApplication (classe générant des formulaire Windows) qui hérite lui même de XafApplication, qui hérite lui même de [Component, IDisposable, INotifyPropertyChanged, ISupportInitialize].

    On a un objet virtual de type Form dans WinApplication, mais je sais pas comment il le gère derrière. C'est un des problèmes de travailler sur une surcouche de .net


    La solution du singleton peut être bonne, pour l'instant je peux pas me pencher dessus, je me renseigne un peu en parallèle à mes taches.

    Merci à vous en tout cas

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par PitMaverick78 Voir le message
    Tu peux peut-être enregistrer le thread de l'ui dans un singleton.
    Ben oui mais tu vas en faire quoi de ce thread ? Il faut un mécanisme spécifique pour faire exécuter un code arbitraire sur un thread qui est déjà en cours d'exécution (Control.Invoke en Winforms, Dispatcher.Invoke en WPF...)

    Sinon il y a une abstraction de ce mécanisme : la classe SynchronizationContext. En principe chaque framework UI fournit sa propre implémentation, accessible via SynchronizationContext.Current. Tu peux enregistrer ce SynchronizationContext, et l'utiliser pour exécuter le code voulu via les méthodes Send (équivalent à Invoke) et Post (équivalent à BeginInvoke)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 01/02/2008, 21h33
  2. [Formulaire]Lancement de requêtes sur timer
    Par GIPPE dans le forum IHM
    Réponses: 2
    Dernier message: 12/04/2007, 20h57
  3. Modification formulaire pointage
    Par JC2704 dans le forum IHM
    Réponses: 2
    Dernier message: 15/03/2007, 20h28
  4. Réponses: 3
    Dernier message: 09/06/2006, 08h29
  5. modification formulaire + validation date
    Par cari dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 20/01/2006, 09h43

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