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 :

Comment faire un Winform Custom Button avec Événement Custom en C# VS 2010


Sujet :

C#

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut Comment faire un Winform Custom Button avec Événement Custom en C# VS 2010
    Bonjour,

    J’ai besoin d’un bouton qui clignote donc dont le fond change de couleur alternativement et ce suite à la réception d’un événement custom généré par un contrôle timer. En effet je lis des données sur un port série et je veux que lorsque les données sont disponible (il y en a pas toujours) que le bouton change d’aspect, en ce moment j’écris les données dans un TextBox je pourrais faire un beep mais ça devient un peu fatiguant à la longue.

    J’ai bien trouvé l’article MSDN How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide) que j’ai adapté.

    Je veux aussi que ce nouveau bouton affiche le nouvel événement dans l’inspecteur de propriété section Events de l’IDE pour pouvoir ajouter du code comme pour les autres événements. Exemple : supposons que l’usager veuille ajouter un Beep() au scintillement (je ne pense pas c’est juste un exemple).

    J’ai réussi à faire quelque chose qui fonctionne mais c’est incomplet.

    Voici le code de la fiche je ne sais pas mais ça ne me semble pas correct.

    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
            
            // ------------------------------------------------------------------------------
            private void timer1_Tick(object sender, EventArgs e)
            {
                blinkEvent.Raise();                    // Class that publishes an event
            }
           // ------------------------------------------------------------------------------
            BlinkEvent blinkEvent = new BlinkEvent();  // Class that publishes an event
           
            // ------------------------------------------------------------------------------
            private void ToggleButton_Click(object sender, EventArgs e)
            {
                blinkButton1.SetPublisher(blinkEvent);      // Subscribers
                blinkButton2.SetPublisher(blinkEvent);
     
              
                timer1.Enabled = timer1.Enabled == false;
            }
      
    Voici le code du control custom largement inspiré de l’article MSDN mais ce ne me semble pas la bonne forme.

    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
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
     
    using System.Collections;
    using System.Windows.Forms;
    using System.ComponentModel;
    using System.Drawing;
     
    namespace Custom_Events
    {
        // De: http://msdn.microsoft.com/en-us/library/w369ty8x(v=vs.100).aspx
     
        // Define a class to hold custom event info
        public class CustomEventArgs : EventArgs
    {
            public CustomEventArgs(string s)
    {
                message = s;
            }
            private string message;
     
            public string Message
            {
                get { return message; }
                set { message = value; }
            }
        }
     
        // Class that publishes an event
        class BlinkEvent
    {
            // Declare the event using EventHandler<T>
            public event EventHandler<CustomEventArgs> RaiseCustomEvent;
     
            public void Raise()
    {
                // Write some code that does something useful here
                // then raise the event. You can also raise an event
                // before you execute a block of code.
                OnRaiseCustomEvent(new CustomEventArgs("Did something"));
            }
           
            // Wrap event invocations inside a protected virtual method
            // to allow derived classes to override the event invocation behavior
           protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
    {
                // 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.
                EventHandler<CustomEventArgs> handler = RaiseCustomEvent;
    
                // Event will be null if there are no subscribers
                if (handler != null)
                {
                    // Use the () operator to raise the event.
                    handler(this, e);
                }
            }
        }
       
        // ------------------------------------------------------------------------------
    class BlinkButton : Button
    {
            public void SetPublisher(BlinkEvent pub)
    {
                // Subscribe to the event using C# 2.0 syntax
                pub.RaiseCustomEvent += HandleCustomEvent;
            }
     
            // J'aimerais pouvoir voir le nouvel event dans la liste 
            [Category("Events")]
            [Description("Fires when the blinking event is raised")]
     
            // Define what actions to take when the event is raised.
            void HandleCustomEvent(object sender, CustomEventArgs e)
    {
                Text = e.Message;
     
                if (BackColor == Color.Yellow)
                {
                    BackColor = System.Drawing.SystemColors.Control;
                }
                else
                {
                    BackColor = Color.Yellow;
                }
            }
        }
    }

    Merci.

  2. #2
    Membre chevronné
    Avatar de PixelJuice
    Homme Profil pro
    Ingénieur .NET & Game Designer
    Inscrit en
    Janvier 2014
    Messages
    648
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Ingénieur .NET & Game Designer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2014
    Messages : 648
    Points : 2 170
    Points
    2 170
    Par défaut
    Bonjour,

    tu n'utilises pas un objet de type SerialPort pour lire les données dessus ? De cette façon tu as déjà un événement tout prêt qui fait exactement ce que tu veux : DataReceived , qui se déclenche dès que des données sont disponible sur le port.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut
    C'est exactement ce que je fais mais ce n'est pas le sujet de la discussion.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par PiPo123 Voir le message
    PixelJuice c'est exactement ce que je fais mais ce n'est pas le sujet de la discussion.
    Bonjour,

    Tu devrais vraiment suivre le conseil de Romain (ou PixelJuice, je préfère appeler les gens par leur vrai prénom quand celui-ci est affiché) car en effet tu es déjà dans un événement "DataReceived" et donc il est complètement inutile de lever un autre événement à ce moment-la. Donc c'est bien le sujet de la discussion. Tu te perds avec quelque-chose non nécessaire dans ce cas et ça va te faire perdre du temps.

    Ce qu'il faut bien souligner aussi est que l'événement "DataReceived" se déclenche sur un thread secondaire qui n'est pas celui de l'IHM. Du coup, si tu veux accéder à un élément d'IHM, il faut le faire dans un "BeginInvoke".
    Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void portDataReceived(object sender, SerialDataReceivedEventArgs e)
    {
         this.BeginInvoke((Action)MakeButtonBlink);
    }
     
    void MakeButtonBlink()
    {
         //Là tu met ce qu'il faut pour que ton bouton clignote...
    }
    où "portDataReceived" est le Handler de ton événement "DataReceived".
    Dernière modification par Invité ; 16/04/2014 à 15h56. Motif: Petite correction faute d'orthographe

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut
    Effectivement si j'ajoute ceci

    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
    // -------------------------------------------------------------------
    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
    string indata = serialPort1.ReadLine();    
    
    // Pour avoir un ThreadSafe
    this.BeginInvoke(new LineReceivedEvent(LineReceived), indata);
    }
    
    private delegate void LineReceivedEvent(string S);
    // -------------------------------------------------------------------
    private void LineReceived(string S)
    {
    ...
    
    if (button2.BackColor == SystemColors.Control)
    {
      button2.BackColor = Color.Yellow;
    }
    else
    {
      button2.BackColor = SystemColors.Control;
    }
    ...
    je vais avoir un changement de couleur mais c'est la fréquence d'entrée des données qui va gérer la changement de couleur on est loins de l'effet que je cherche. Ça prend un timer pour avoir un clignotement régulier.

    Désolé.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    Dans ta fonction "LineReceived", rien ne t'empêche d'implémenter un timer. Sinon tu peux toujours faire un thread qui déclenche le passage du bouton en jaune, qui attend 100 ms puis qui le remet comme avant.
    Exemple :
    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
     
    //Lancement
    MakeButtonBlink();
     
    ...
     
    //Définition de la fonction "MakeButtonBlink"
    void MakeButtonBlink()
    {
        Task.Run(()=>
       {
          _semBlink.Wait();
          try
          {
             BeginInvoke((Action)delegate() { button2.BackColor = Color.Yellow; });
             Thread.Sleep(100);
             BeginInvoke((Action)delegate() { button2.BackColor = SystemColors.Control; });
          }
          finally { _semBlink.Release(); }
       });
    }
     
    //Le sémaphore utilisé
    readonly SemaphoreSlim _semBlink = new SemaphoreSlim(1,1);
    Le sémaphore permettra d'indiquer que l'action "MakeButtonBlink" suivante ne se déclenchera pas tant que la précédente n'est pas finie.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut
    Ok.
    Ça pourrais fonctionner mais la on a pas accès à la fréquence de clignotement c'est à mon avis moins flexible.

    Pour tester mon BlinkButton j'utilise un boutton ordinaire dans une fiche ce qui est beaucoup plus facile que lire sur port série et attendre des données.

    J'ai modifié le code de la nouvelle classe BlinkButton et je peux maintenant accéder au nouvel événement Blink dans les propriétés et ajouter un autre gestionnaire comme les autres événements standard mais le code n'est pas appellé, il y quelque chose qui cloche.


    Code de la nouvelle classe BlinkButton
    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
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace BlinkButtonClass
    {
        // ---------------------------------------------------
        public class ValueChangedEventArgs : EventArgs
        {
            public int Value { get; set; }
    
            public ValueChangedEventArgs(int newValue)
            {
                Value = newValue;
            }
        }
    
        // Declare a delegate
        public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
    
        // ---------------------------------------------------
        // Class that publishes an event
        public class BlinkEvent  
        {
            public event EventHandler<ValueChangedEventArgs> EventHandler;
    
            public void Raise(int I)
            {
                OnValueChanged(new ValueChangedEventArgs(I));
            }
    
            // ---------------------------------------------------
            protected virtual void OnValueChanged(ValueChangedEventArgs e)
            {
                EventHandler<ValueChangedEventArgs> handler = EventHandler;
                if (handler != null)
                {
                    handler(this, e);
                }
            }
        }
    
        // ---------------------------------------------------
        // ---------------------------------------------------
        public partial class BlinkingButton : Button
        {
            public BlinkingButton()
            {
                InitializeComponent();
            }
            
            // ---------------------------------------------------
            public BlinkingButton(BlinkEvent e) : this()
            {
               e.EventHandler += HandleBlinkEvent;
            }
    
            // Declare an event
            [Category("Action")]
            [Description("Fires when the button must blink")]
            public  event ValueChangedEventHandler Blink;
            
            // ---------------------------------------------------
            public void HandleBlinkEvent(object sender, ValueChangedEventArgs e)
            {
                if (BackColor == SystemColors.Control)
                    BackColor = Color.Yellow;
                else BackColor = SystemColors.Control;
            }
        }
    }

    Dans ma fiche j'ai
    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
    public partial class Form1 : Form
        {
            BlinkEvent Blink_Event = new BlinkEvent();
    
          public Form1()
            {
                InitializeComponent();
    
                // J'ai plusieurs control blinkingButton pour tester l'événement
    
                Blink_Event.EventHandler += blinkingButton1.HandleBlinkEvent;
                Blink_Event.EventHandler += blinkingButton2.HandleBlinkEvent;
                Blink_Event.EventHandler += blinkingButton3.HandleBlinkEvent;
                Blink_Event.EventHandler += blinkingButton4.HandleBlinkEvent;
            }
    ...
    
    et plus loin
    
            // -------------------------------------------------------------------------
            private void StartBlinkingbutton_Click(object sender, EventArgs e)
            {
                timer1.Enabled = timer1.Enabled == false;
            }
    
            // -------------------------------------------------------------------------
            private void timer1_Tick(object sender, EventArgs e)
            {
                // Le parametre n'est pas utilisé dans la classe mais je voulais un EventArgs custom
                Blink_Event.Raise(1);
            }
    
            
            // Ce gestionnaire qui a été ajouté à partir de l'IDE dans Properties Windows section Events mais n'est pas appellé
            // -------------------------------------------------------------------------
            private void blinkingButton1_Blink(object sender, ValueChangedEventArgs e)
            {
                Console.Beep();
            }

  8. #8
    Invité
    Invité(e)
    Par défaut
    Avec ma solution, tu peux toujours influer sur le temps de latence de clignotement ainsi :

    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
     
    //Définition de la fonction "MakeButtonBlink"
    int _latency = 100; //Peut être modifié
    void MakeButtonBlink()
    {
        Task.Run(()=>
       {
          _semBlink.Wait();
          try
          {
             BeginInvoke((Action)delegate() { button2.BackColor = Color.Yellow; });
             Thread.Sleep(_latency);
             BeginInvoke((Action)delegate() { button2.BackColor = SystemColors.Control; });
          }
          finally { _semBlink.Release(); }
       });
    }
    [EDIT]
    Sinon, j'ai compris que tu voulais un bouton spécial qui comporte un événement de Blink.
    Voici comment procéder si tu veux vraiment :
    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
    99
    100
    101
    102
    103
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
     
    namespace TestsWinForms
    {
    	class BlinkButton : Button
    	{
    		private const string __DefaultColor = "Red";
    		private Color _blinkColor = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromString(__DefaultColor);
    		[DefaultValue(typeof(Color), __DefaultColor)]
    		public Color BlinkColor
    		{
    			get { return _blinkColor; }
    			set { _blinkColor = value; }
    		}
     
    		private const int __DefaultBlinkLatency = 100;
    		private int _blinkLatency = __DefaultBlinkLatency;
    		[DefaultValue(__DefaultBlinkLatency)]
    		public int BlinkLatency
    		{
    			get { return _blinkLatency; }
    			set { _blinkLatency = value; }
    		}
     
    		public event EventHandler<BlinkEventArgs> Blink;
    		protected virtual void OnBlink(BlinkEventArgs evt)
    		{
    			EventHandler<BlinkEventArgs> handler = this.Blink;
    			if (null != handler) handler(this, evt);
    		}
     
    		readonly SemaphoreSlim _semBlink = new SemaphoreSlim(1, 1);
    		public void MakeBlink()
    		{
                            //Fonction qui va déclencher le clignotement. Après un peu de recul, je ne l'aurais pas fait tout à fait comme ça
                            //mais ça devrait fonctionner correctement pour des cas simples normalement...                        
     
    			var currentHandle = this.Handle; //Cela va vérifier qu'on est sur le thread de l'IHM...
    			if (null == currentHandle) return;
     
    			while (!_semBlink.Wait(0))
                            {
                                //Pour ne pas risquer de bloquer l'IHM s'il y a un autre blink en cours...
                                Application.DoEvents();
                            }
    			Color currentColor = this.BackColor;
    			Color blinkColor = _blinkColor;
    			int blinkLatency = _blinkLatency;
     
    			Task.Factory.StartNew(() =>
    			{
    				try
    				{
    					this.BeginInvoke((Action)delegate() { this.BackColor = blinkColor; });
    					Thread.Sleep(blinkLatency);
    					this.BeginInvoke((Action)delegate() { this.BackColor = currentColor; });
    				}
    				finally
    				{
    					this.BeginInvoke((Action)delegate()
    					{
    						BlinkEventArgs evt = new BlinkEventArgs();
    						//Si tu as mis des propriétés dans BlinkEventArgs, tu peux éventuellemnt les initialiser
    						//soit dans le constructeur de BlinkEventArgs soit ici...
    						try { OnBlink(evt); }
    						finally { _semBlink.Release(); }
    					});
    				}
    			});
    		}
     
    		private void WaitForBlinkFinish()
    		{
    			while(!_semBlink.Wait(10)) Application.DoEvents();
    			_semBlink.Release();
    		}
     
    		protected override void DestroyHandle()
    		{
    			WaitForBlinkFinish();
    			base.DestroyHandle();
    		}
     
    		protected override void Dispose(bool disposing)
    		{
    			WaitForBlinkFinish();
    			base.Dispose(disposing);
    		}
    	}
     
    	class BlinkEventArgs : EventArgs
    	{
    		//Mets les propriétés que tu veux
    	}
    }
    Avec ce bouton, tu peux configurer:
    - Quelle couleur de Blink
    - Quel temps de latence.

    De plus, il y a le fameux événement "Blink" auquel tu peux t'abonner avec sonc déclenchement correspondant.
    Qu'en penses-tu?

    [EDIT2]
    Une version de la méthode "MakeBlink" pour le Framework 4.5 :
    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
    public async void MakeBlink()
    {
    	var currentHandle = this.Handle; //Cela va vérifier qu'on est sur le thread de l'IHM...
    	if (null == currentHandle) return;
     
    	await _semBlink.WaitAsync();
    	Debug.WriteLine("Sém pris!");
     
    	Color currentColor = this.BackColor;
    	Color blinkColor = _blinkColor;
    	int blinkLatency = _blinkLatency;
     
    	//C'est parti!
    	this.BackColor = blinkColor;
     
    	await Task.Delay(blinkLatency);
     
    	//Retour à la couleur d'avant!
    	this.BackColor = currentColor;
     
    	BlinkEventArgs evt = new BlinkEventArgs();
    	//Si tu as mis des propriétés dans BlinkEventArgs, tu peux éventuellemnt les initialiser
    	//soit dans le constructeur de BlinkEventArgs soit ici...
    	try { OnBlink(evt); }
    	finally { _semBlink.Release(); Debug.WriteLine("Sém libre!"); }
    }
    dans ce dernier cas, on peut encore alléger le code en enlevant ceci :
    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
    private void WaitForBlinkFinish()
    {
    	while(!_semBlink.Wait(10)) Application.DoEvents();
    	_semBlink.Release();
    }
     
    protected override void DestroyHandle()
    {
    	WaitForBlinkFinish();
    	base.DestroyHandle();
    }
     
    protected override void Dispose(bool disposing)
    {
    	WaitForBlinkFinish();
    	base.Dispose(disposing);
    }
    Dernière modification par Invité ; 18/04/2014 à 13h45.

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut
    Bon je viens d'essayer la solution proposé par Philippe pour un control custom avec gestion d'un événement custom qui est un bouton avec clignotement automatique et malheureusement ça ne fonctionne pas comme espéré. Je n’obtiens pas de clignotement synchrone sur plusieurs boutons et je dois cliquer sur un bouton avec le code associé ci-dessous pour provoquer un clignotement à chaque fois.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    // ---------------------------------------------------------
    private void Startbutton_Click(object sender, EventArgs e)
    {
    blinkButton1.MakeBlink();
    blinkButton2.MakeBlink();
    blinkButton3.MakeBlink();
    blinkButton4.MakeBlink();
    }
    Je ne sais pas si c'est moi qui fait quelque chose de pas correct ou si c'est ma version de VS 2010.

  10. #10
    Invité
    Invité(e)
    Par défaut
    Avec ma solution, tu as oublié de faire certaines choses :

    - Mets tes boutons "Blink" dans un tableau au début de ton formulaire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    BlinkButton[] _tableauBlinkButtons = new BlinkButton[] { blinkButton1, blinkButton2 }; //Tous les blinkButtons de ton formulaire
    - Fais-toi une petite fonction qui appelle en boucle les "MakeBlink" des boutons :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void MakeAllBlink()
    {
       foreach(BlinkButton bBtn in _tableauBlinkButtons)
       {
          bBtn.MakeBlink();
       }
    }
    Et appelle "MakeAllBlink()" dans ton Handler de message reçu :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        ...
       this.BeginInvoke((Action)MakeAllBlink);
       ...
    }
    Utilises de préférence la version "Framework 4.5" que je t'ai montré car effectivement l'autre version a de temps en temps des décalages.

    Alors je me suis amusé à faire une autre version "Framework 4" :
    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
    public void MakeBlink()
    		{
    			var currentHandle = this.Handle; //Cela va vérifier qu'on est sur le thread de l'IHM...
    			if (null == currentHandle) return;
     
    			Color currentColor = Color.Empty;
    			Color blinkColor = Color.Empty;
    			int blinkLatency = 0;
     
    			TaskScheduler syncScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    			_semBlink.WaitAsync()
    				.ContinueWith(tsk =>
    				{
    					currentColor = this.BackColor;
    					blinkColor = _blinkColor;
    					blinkLatency = _blinkLatency;
     
    					this.BackColor = blinkColor;
    				}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, syncScheduler)
    				.ContinueWith(tsk =>
    				{
    					Thread.Sleep(blinkLatency);
    				}, TaskContinuationOptions.OnlyOnRanToCompletion)
    				.ContinueWith(tsk =>
    				{
    					this.BackColor = currentColor;
    					BlinkEventArgs evt = new BlinkEventArgs();
    					//Si tu as mis des propriétés dans BlinkEventArgs, tu peux éventuellemnt les initialiser
    					//soit dans le constructeur de BlinkEventArgs soit ici...
    					try { OnBlink(evt); }
    					finally { _semBlink.Release(); }
    				}, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, syncScheduler);
    		}
    C'est quand même plus compliqué dans tous les cas que la version "Framework 4.5", non ?
    Dernière modification par Invité ; 21/04/2014 à 09h52.

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Août 2006
    Messages
    249
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Août 2006
    Messages : 249
    Points : 106
    Points
    106
    Par défaut
    Finalement c’est très simple d’ajouter un événement custom à une nouvelle classe.

    Faites attention à cet article qui peut créer de la confusion et peux vous faire perdre du temps.
    How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide)
    Au début je me suis obstiné à vouloir utiliser cet article ce qui n’est même pas pertinent pour mon cas de plus j’ai trouvé des articles qui y font référence pour expliquer le fonctionnement des événements en C#.

    Dans mon cas j’ai créé un bouton qui clignote nommé BlinkButton et qui réagi à un nouvel événement OnBlink. C’est pour une application qui reçoit des alertes sur le port série et je voulais associer un Bouton à chaque type d’alerte donc plusieurs boutons sur ma fiche.

    Je vous donne le code de cette nouvelle classe simple.
    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
     
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
     
    namespace BlinkButtonExternalTimerClass
    {
        // 1 - On déclare un delegate pour nos gestionnaires
        public delegate void BlinkEventHandler(object sender, BlinkEventArgs e);
     
        // 2- On crée un EventArgs custom
        // ---------------------------------------------------
        public class BlinkEventArgs : EventArgs
        {
            public List<int> ButtonIDList = new List<int>();
            public Color HIGHCOLOR;
            public bool State_HIGH;
     
            public BlinkEventArgs(List<int> BL, Color HIGH_Color, bool NewState)
            {
                ButtonIDList = BL;
                HIGHCOLOR = HIGH_Color;
                State_HIGH = NewState;
            }
        }
     
        // Voici notre nouvelle class
        // ----------------------------------------------------
        public partial class BlinkButton : Button
        {
            public BlinkButton()
            {
                InitializeComponent();
            }
     
            // On déclare une nouvelle propriété si nécessaire
            private const int _DefaultButtonID = 1;
            private int _ButtonID = _DefaultButtonID;
            [DefaultValue(_DefaultButtonID)]
            public int ButtonID
            {
                get { return _ButtonID; }
                set { _ButtonID = value; }
            }
     
            // *****************************************************
            // 3 - Maintenant on déclare notre nouvel événement
            [Category("Action")]
            [Description("Fires when the value is changed")]
            public event BlinkEventHandler Blink;   
     
            // 4 - On ajoute un gestionnaire par défaut
            // ---------------------------------------------------
            public void OnBlink(object sender, BlinkEventArgs e)
            {
                // Do any specific processing here.
                // Traitement par défaut
                if (e.ButtonIDList.Contains(ButtonID)) 
                {
                    if (e.State_HIGH)
                    {
                        BackColor = e.HIGHCOLOR;
                        //ForeColor = Color.White;
                    }
                    else
                    {
                        ForeColor = SystemColors.ControlText;
                        BackColor = SystemColors.Control;
                        UseVisualStyleBackColor = true;
                    } 
     
                    // 5 - Ici on appelle tous les gestionnaires attachés à l'extérieur de la class avec
     
                    // this.blinkButton1.Click += new System.EventHandler(this.blinkButton1_Click);
     
                    // Ce qui est fait automatiquement dans l'IDE si vous cliquez sur le nouvel
                    // événemnt dans la liste d'événements
                    if (Blink != null)
                    {
                        Blink(this, e);
                    }    
                }
            }
        }
    }
    Pour initialiser dans le constructeur de la fiche je fais

    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
     
        public partial class Form1 : Form
        {
           // On declare un nouveau BlinkEventHandler
            public event BlinkEventHandler BlinkEventChain;
     
           public Form1()
            {
                InitializeComponent();
     
           // On attache tous les gestionnaires. 
           // foreach très utile pour ne pas maintenir une liste, vous pouvez ajouter ou supprimer des boutons sans rien modifier  
                foreach (Control control in this.Controls)
                {
                    if (control.GetType() == typeof(BlinkButton))
                        BlinkEventChain += new BlinkEventHandler(((BlinkButtonExternalTimerClass.BlinkButton)(control)).OnBlink);
                }          
            }
    Pour lever le nouvel événement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
                if (BlinkEventChain != null)
                    BlinkEventChain(this, E);
    J'ai attaché un petit projet BlinkButton test pour ceux qui veulent un exemple simple.
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. Réponses: 4
    Dernier message: 28/07/2006, 13h10
  2. Réponses: 3
    Dernier message: 27/07/2006, 09h17
  3. TIBDataSet comment faire de la mise à jour avec jointure
    Par uluru dans le forum Connexion aux bases de données
    Réponses: 8
    Dernier message: 08/07/2006, 10h09
  4. Comment faire un jeu en réseau avec J2ME ?
    Par Yakurena dans le forum Java ME
    Réponses: 1
    Dernier message: 27/03/2006, 19h09
  5. Comment faire une division par 5 avec les decalages
    Par Zaion dans le forum Assembleur
    Réponses: 7
    Dernier message: 05/11/2004, 17h33

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