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

Dotnet Discussion :

L'évènement semble être déclenché dans un thread séparé


Sujet :

Dotnet

  1. #1
    Rédacteur/Modérateur
    Avatar de Skalp
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 694
    Points : 2 927
    Points
    2 927
    Par défaut L'évènement semble être déclenché dans un thread séparé
    Bonjour,

    Je me suis fait un objet (TemporayString) qui gère une chaine de caractères qui s'efface automatiquement au bout d'un temps défini (à l'aide d'un Timer).
    J'ai donc :
    - une méthode AddChar(char value) qui me permet d'ajouter un caractère à la chaîne temporaire. Cette méthode déclenche l'évènement CharAdded.
    - un évènement TemporaryStringReset qui est déclenché lorque le Timer est écoulé.

    Dans ma form qui utilise une instance de l'objet, je m'abonne aux évènements CharAdded et TemporaryStringReset pour mettre à jour un label.
    - Lorsque j'appelle la méthode Addchar, l'évènement CharAdded est déclenché et mon label est bien mis à jour.
    - Mais lorsque le Timer est écoulé, l'évènement TemporaryStringReset est déclenché mais il est réceptionné par la form dans un thread séparé !
    Je dois donc faire un invoke de mon label pour pouvoir le mettre à jour.

    Sauriez-vous d'où cela peut provenir ? Est-ce normal ? Puis-je modifier la conception de l'objet pour récupérer l'évènement dans le même thread ?

    Code de la classe TemporaryString :
    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
    /// <summary>
    /// A temporary string
    /// </summary>
    public class TemporaryString
    {
        #region Fields
        // Default interval :
        private const double _DEFAULTINTERVAL = 1000;
        // Timer instance :
        private Timer _Timer;
        // String value :
        private string _Value;
     
        public event EventHandler TemporaryStringReset;
     
        public event EventHandler CharAdded;
     
        /// <summary>
        /// String value
        /// </summary>
        public string Value
        {
            get { return _Value; }
        }
        #endregion
     
        #region Constructors
        /// <summary>
        /// Initializes a new instance of TemporaryString, using the default interval, which is 1 second
        /// </summary>
        public TemporaryString()
            : this(_DEFAULTINTERVAL)
        { }
     
        /// <summary>
        /// Initializes a new instance of TemporaryString, using the given interval
        /// </summary>
        /// <param name="interval">Time period</param>
        public TemporaryString(double interval)
        {
            this._Timer = new Timer(interval);
            this._Value = string.Empty;
            this._Timer.Elapsed += new ElapsedEventHandler(this._Timer_Elapsed);
            this._Timer.Enabled = true;
            this._Timer.AutoReset = false;
        }
        #endregion
     
        #region Methods
        /// <summary>
        /// Adds a char to the string value
        /// </summary>
        /// <param name="value">Char to add to the string value</param>
        public void AddChar(char value)
        {
            this._Value += value.ToString();
            // Reset the timer :
            this._Timer.Stop();
            this._Timer.Start();
     
            // Fire CharAdded event :
            EventHandler handler = CharAdded;
            // NOTE : Make a temporary copy of the event to avoid possibility of a race condition 
            // if the last subscriber unsubscribes immediately after the null check and before the event is raised.
            if (handler != null)
                handler(this, new EventArgs());
        }
     
        /// <summary>
        /// Elapsed timer event
        /// </summary>
        /// <param name="sender">Source object</param>
        /// <param name="e">Elapsed event arguments</param>
        private void _Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this._Value = string.Empty;
            // Stop the timer :
            this._Timer.Stop();
     
            // Fire the TemporaryStringReset event :
            EventHandler handler = TemporaryStringReset;
            // NOTE : Make a temporary copy of the event to avoid possibility of a race condition 
            // if the last subscriber unsubscribes immediately after the null check and before the event is raised.
            if (handler != null)
                handler(this, new EventArgs());
        }
        #endregion
    }
    Utilisation de l'objet dans la form :
    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
    public partial class Form1 : Form
    {
        TemporaryString ts;
        delegate void SetTextCallback(string text);
     
        public Form1()
        {
            InitializeComponent();
     
            ts = new TemporaryString(2000);
            ts.TemporaryStringReset += new EventHandler(ts_TemporaryStringReset);
            ts.CharAdded += new EventHandler(ts_CharAdded);
        }
     
        private void SetText(string text)
        {
            if (label1.InvokeRequired)
            {
                label1.Invoke(new SetTextCallback(SetText), new object[] { text });
            }
            else
            {
                if (string.IsNullOrEmpty(text))
                {
                    label1.Text = string.Empty;
                }
                else
                {
                    label1.Text = text;
                }
            }
        }
     
        void ts_CharAdded(object sender, EventArgs e)
        {
            SetText(ts.Value);
        }
     
        void ts_TemporaryStringReset(object sender, EventArgs e)
        {
            SetText("vide");
        }
     
        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            ts.AddChar(Convert.ToChar(e.KeyValue));
        }
    }
    Merci de votre aide

  2. #2
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Points : 6 334
    Points
    6 334
    Par défaut
    Le timer s'exécute dans un thread séparé. Qu'est ce qui ne fonctionne pas ?
    Normalement, ça devrait fonctionner avec le Invoke...

  3. #3
    Rédacteur/Modérateur
    Avatar de Skalp
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 694
    Points : 2 927
    Points
    2 927
    Par défaut
    Citation Envoyé par SaumonAgile Voir le message
    Qu'est ce qui ne fonctionne pas ?
    Normalement, ça devrait fonctionner avec le Invoke...
    Ca fonctionne avec le Invoke, je voulais seulement savoir pourquoi l'évènement était déclenché dans un thread séparé.

    Et j'ai eu ma première réponse, merci :
    Citation Envoyé par SaumonAgile Voir le message
    Le timer s'exécute dans un thread séparé.
    Je ne savais pas !


    Toujours est-il qu'au niveau de l'utilisation de l'objet TemporaryString, cela m'embête un peu, car le développeur n'est pas censé savoir qu'il y a un Timer sous-jacent. Je vais essayer alors de faire l'invoke au niveau de la méthode _Timer_Elapsed, qu'en penses-tu ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        private void _Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            this._Value = string.Empty;
            // Stop the timer :
            this._Timer.Stop();
     
            // Fire the TemporaryStringReset event :
            EventHandler handler = TemporaryStringReset;
            if (handler != null)
                handler.Invoke(...)
                //handler(this, new EventArgs());
        }
    Merci !

  4. #4
    Rédacteur/Modérateur
    Avatar de Skalp
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2006
    Messages
    1 694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 694
    Points : 2 927
    Points
    2 927
    Par défaut
    J'ai finalement trouvé la solution en utilisant la propriété SynchronizingObject de l'objet Timer que j'ai encapsulé dans l'objet TemporaryString :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public ISynchronizeInvoke SynchronizingObject
    {
        get { return this._Timer.SynchronizingObject; }
        set { this._Timer.SynchronizingObject = value; }
    }
    Lorsque le timer est expiré, je peux faire un invoke pour déclencher l'évènement :
    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
    private void _Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        this._Value = string.Empty;
        // Stop the timer :
        this._Timer.Stop();
     
        // Fire the TemporaryStringReset event :
        EventHandler handler = TemporaryStringReset;
        // NOTE : Make a temporary copy of the event to avoid possibility of a race condition 
        // if the last subscriber unsubscribes immediately after the null check and before the event is raised.
        if (handler != null)
        {
            if ((this._Timer.SynchronizingObject != null) && this._Timer.SynchronizingObject.InvokeRequired)
            {
                this._Timer.SynchronizingObject.BeginInvoke(handler, new object[] { this, new EventArgs() });
            }
            else
            {
                handler(this, new EventArgs());
            }
        }
    }
    Maintenant, dans ma Form1, je dois relier l'objet au contrôle graphique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        public Form1()
        {
            InitializeComponent();
     
            ts = new TemporaryString(2000);
            ts.TemporaryStringReset += new EventHandler(ts_TemporaryStringReset);
            ts.CharAdded += new EventHandler(ts_CharAdded);
            // Synchroniser TemporaryString avec le contrôle graphique :
            ts.SynchronizingObject = this.Control1;
        }
    Le contrôle doit implémenter l'interface ISynchronizeInvoke.

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 08/03/2013, 14h03
  2. événement dans un thread
    Par butch dans le forum Langage
    Réponses: 8
    Dernier message: 16/08/2010, 11h52
  3. [JFileChooser] plantage aléatoire dans un Thread séparé
    Par RR instinct dans le forum Agents de placement/Fenêtres
    Réponses: 3
    Dernier message: 24/07/2009, 13h53
  4. Gestion des évènements dans un thread
    Par kashikai dans le forum SDL
    Réponses: 0
    Dernier message: 25/05/2009, 14h32
  5. Comment lancer Word dans un thread séparé
    Par Tony49 dans le forum C++Builder
    Réponses: 3
    Dernier message: 22/03/2009, 12h43

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