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 :

Suppression d'un évènement lors de la suppression de l'objet qui y a souscrit ?


Sujet :

C#

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut Suppression d'un évènement lors de la suppression de l'objet qui y a souscrit ?
    Salut !

    Petite question par rapport aux évènements :

    Si je crée un objet et lui associe un évènement, est-ce que, si je supprime cet objet, l'évènement est supprimé aussi ? Ca paraît bête comme question mais je voudrais être vraiment sur !

    Donc, dans le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
    myTimer.Tick += new EventHandler(cptrebours);
    Merci !

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    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 177
    Points : 25 125
    Points
    25 125
    Par défaut
    mettre à null ne supprime pas un objet, ca sert souvent à rien d'ailleurs
    les objets sont supprimés quand il ne sont plus référencés par aucun objet "vivant"

    et se lier par un évènement créé un lien donc tant que ton objet s'étant abonné est vivant le timer restera vivant

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut
    Okay ! Bon, je vais y réfléchir... (Et d'ailleurs, quelle est la bonne pratique pour "supprimer" un objet alors ?)
    Mais je vais aller plus loin dans mon problème. J'ai un bouton qui lance un countdown. J'utilise un eventhandler pour cela. Je me suis basé sur du code issu de la doc Microsoft...

    Voici le code (dont 2 méthodes):

    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
     
    private bool flagevent;
    private Timer myTimer;
     
    private void button9_Click(object sender, EventArgs e)
            {
                label18.Text = "";
                label19.Text = "";
                label20.Text = "";
                label21.Text = "";
                label22.Hide();
                flagevent = false;
                this.ActiveControl = textBox3;            
                Regex myRegex = new Regex("^([0-9]{2}:[0-9]{2}|[0-9]{2}:[0-9]{2}:[0-9]{2})$");
                DateTime datechoisieform1 = monthCalendar1.SelectionRange.Start;
                DateTime heurechoisieform1;
                bool isv = DateTime.TryParse(textBox3.Text, out heurechoisieform1);
                if (isv && myRegex.IsMatch(textBox3.Text))
                {
                    textBox3.Text = heurechoisieform1.ToString("HH:mm:ss");
                    DateTime datefinale = new DateTime(datechoisieform1.Year, datechoisieform1.Month, datechoisieform1.Day, heurechoisieform1.Hour, heurechoisieform1.Minute, heurechoisieform1.Second);
                    TimeSpan diff = datefinale.Subtract(DateTime.Now);
                    if (diff.TotalSeconds > 0)
                    {
                        myTimer = new Timer();                    
                        EventHandler func = (sender2, e2) => cptrebours(sender2, e2, datefinale, ref flagevent);
                        myTimer.Tick += func;
                        myTimer.Interval = 1000;
                        myTimer.Start();
                        while (!flagevent) Application.DoEvents();
                        myTimer.Tick -= func;
                        myTimer = null; 
                    }
                    else
                    {
                        textBox3.Text = "";
                        MessageBox.Show("Le couple \"date-heure\" que vous avez choisi est antérieur aux date et heure actuelles", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
                else
                {
                    textBox3.Text = "";
                    MessageBox.Show("Heure non-valide ! Veuillez recommencer...", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }
            }
    - Comme vous pouvez le voir, j'utilise "Application.DoEvents". J'ai par après pu lire que ce n'était pas recommandé car dangereux. Bon, mais alors, qu'utiliser pour "bloquer l'application" et reprendre le code une fois que "flagevent" est true ?
    - En fait, avec ce code là, tout se passe bien si le chrono va au bout.
    - Mais par contre, quand je reclique sur le "bouton 9" une seconde fois (avant qu'il ne soit au bout), comment faire pour réaliser un Unsubscribe du 1er event avant que le code ne crée un nouvel event ? Car oui, si je ne le fais pas, le 1er event continue, mais se met "en pause" le temps de continuer le code et de créer le 2nd event. Ca devient chinois, vous ne trouvez pas ?

    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 cptrebours(object sender, EventArgs e, DateTime datefinale, ref bool flag)
            {
                TimeSpan diff = datefinale.Subtract(DateTime.Now);
                if (diff.TotalMilliseconds <= 0)
                {
                    myTimer.Stop();
                    label22.Show();
                    flag = true;
                }
                else if (diff.TotalMilliseconds > 0)
                {
                    label18.Text = diff.Days.ToString();
                    label19.Text = diff.Hours.ToString();
                    label20.Text = diff.Minutes.ToString();
                    label21.Text = diff.Seconds.ToString();
                }
            }
    Merci si vous prenez le temps de m'aider quelque peu !

  4. #4
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    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 177
    Points : 25 125
    Points
    25 125
    Par défaut
    les objets se suppriment tout seul de la mémoire, .net a un mécanisme pour ca (nommé garbage collector)
    si tu créés une variable dans une méthode, à la fin de la méthode elle n'est plus pointée vers personne, elle sera supprimée (on ne sait pas quand mais ca se débrouille)
    pour une variable de classe c'est quand l'instance de la classe n'est plus référencée par aucune variable vivante

    doevents est en effet à proscrire, il servait à faire en sorte de ne pas bloquer l'interface utilisateur pendant l'exécution d'un code long en boucle
    pour un code long (en boucle ou non) on préfère utiliser un thread secondaire, avec par exemple une task, ou plus anciennement mais parfois plus simplement un backgroundworker
    en général on grise le bouton avant de démarrer le traitement, qui peut être annulé via un bouton annuler si le backgroundworker (ou autre) vérifie (via notre code) qu'il faut s'arrêter (via un booléen ou autre)

    (il y a plein d'autres moyens de faire ca)

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut
    Merci pour ta réponse !

    Citation Envoyé par Pol63 Voir le message
    les objets se suppriment tout seul de la mémoire, .net a un mécanisme pour ca (nommé garbage collector)
    si tu créés une variable dans une méthode, à la fin de la méthode elle n'est plus pointée vers personne, elle sera supprimée (on ne sait pas quand mais ca se débrouille)
    pour une variable de classe c'est quand l'instance de la classe n'est plus référencée par aucune variable vivante
    Tout cela, je le savais déjà ! (heureusement d'ailleurs ). Non, ma question était de savoir si on pouvait forcer une suppression plutôt que de laisser .net s'en charger.

    Citation Envoyé par Pol63 Voir le message
    doevents est en effet à proscrire, il servait à faire en sorte de ne pas bloquer l'interface utilisateur pendant l'exécution d'un code long en boucle
    pour un code long (en boucle ou non) on préfère utiliser un thread secondaire, avec par exemple une task, ou plus anciennement mais parfois plus simplement un backgroundworker
    en général on grise le bouton avant de démarrer le traitement, qui peut être annulé via un bouton annuler si le backgroundworker (ou autre) vérifie (via notre code) qu'il faut s'arrêter (via un booléen ou autre)
    (il y a plein d'autres moyens de faire ca)
    J'ai effectivement pu voir le principe du backgroundworker à travers mes lectures sur le net.
    En fait, ici, je dois laisser la possibilité à l'utilisateur de pouvoir cliquer autant qu'il veut sur le bouton 9 (il peut changer les données selon nécessité).

    Je vais m'intéresser de plus près à ce fameux backgroundworker.

  6. #6
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Points : 10 543
    Points
    10 543
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    mettre à null ne supprime pas un objet, ca sert souvent à rien d'ailleurs
    les objets sont supprimés quand il ne sont plus référencés par aucun objet "vivant"
    Mettre à null permet justement de dire que l'on n'a plus besoin de l'objet, et que c'est donc un candidat potentiel pour une collecte (s'il n'est référencé nul part ailleurs).

    Citation Envoyé par Pol63 Voir le message
    et se lier par un évènement créé un lien donc tant que ton objet s'étant abonné est vivant le timer restera vivant
    Oui et non. Reprenons le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myTimer.Tick += new EventHandler(cptrebours);
    Ici, cptrebours est référencé par myTimer, mais myTimer n'est pas référencé par cptrebours.

    Autrement dis : l'émetteur référence le destinataire, mais le destinataire ne référence pas l'émetteur.

    Donc si myTimer n'est référencé nul part, il sera collecté par le ramasse-miettes lors de la prochaine collecte. C'est un piège classique avec les timer, qui doivent impérativement être référencé quelque pars tant que l'on a besoin d'eux.

    Sinon, il n'existe aucun mécanisme pour forcer la suppression d'un objet particulier. Tout au plus, quand il impémente l'interface IDisposable, on peut appeler la méthode Dispose pour libérer les ressources autres que la mémoire (la mémoire sera libérée par le ramasse-miettes).

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut
    Merci François pour ces explications !

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut
    Bon, j'ai incorporé le backgroundworker dans mon code; globalement, ça se passe bien, à un point près :

    Voici le 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
    private void button9_Click(object sender, EventArgs e)
            {
                if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
                label18.Text = "";
                label19.Text = "";
                label20.Text = "";
                label21.Text = "";
                label22.Hide();            
                Regex myRegex = new Regex("^([0-9]{2}:[0-9]{2}|[0-9]{2}:[0-9]{2}:[0-9]{2})$");
                DateTime datechoisieform1 = monthCalendar1.SelectionRange.Start;
                DateTime heurechoisieform1;
                bool isv = DateTime.TryParse(textBox3.Text, out heurechoisieform1);
                if (isv && myRegex.IsMatch(textBox3.Text))
                {
                    textBox3.Text = heurechoisieform1.ToString("HH:mm:ss");
                    DateTime dhchoisies = new DateTime(datechoisieform1.Year, datechoisieform1.Month, datechoisieform1.Day, heurechoisieform1.Hour, heurechoisieform1.Minute, heurechoisieform1.Second);
                    TimeSpan diff = dhchoisies.Subtract(DateTime.Now);
                    if (diff.TotalSeconds > 0)
                    {                    
                        backgroundWorker1.RunWorkerAsync(dhchoisies);
                    }
                    else
                    {
                        textBox3.Text = "";
                        MessageBox.Show("Le couple \"date-heure\" que vous avez choisi est antérieur aux date et heure actuelles", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
                else
                {
                    textBox3.Text = "";
                    MessageBox.Show("Heure non-valide ! Veuillez recommencer...", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }            
            }
     
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                DateTime dhch = (DateTime)e.Argument;
                TimeSpan dif = dhch.Subtract(DateTime.Now);
                int tpstotal = (int)dif.TotalSeconds;
                while (!backgroundWorker1.CancellationPending && dif.TotalMilliseconds > 0)
                {
                    dif = dhch.Subtract(DateTime.Now);
                    backgroundWorker1.ReportProgress(((tpstotal - ((int)dif.TotalSeconds)) / tpstotal) * 100, dif);
                    Thread.Sleep(1000);
                }
                if (backgroundWorker1.CancellationPending)
                {
                    e.Cancel = true;                
                }
            }
     
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                TimeSpan ts = (TimeSpan)e.UserState;
                label18.Text = ts.Days.ToString();
                label19.Text = ts.Hours.ToString();
                label20.Text = ts.Minutes.ToString();
                label21.Text = ts.Seconds.ToString();
            }
     
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (!e.Cancelled) label22.Show();            
            }
    En fait, le bug apparaît lorsque je reclique sur le bouton 9 une seconde fois. Voici l'erreur de Visual Studio :

    System.InvalidOperationException*: 'BackgroundWorker est actuellement occupé et ne peut pas exécuter plusieurs tâches simultanément.'
    Je pense que l'annulation de la tâche du bgw prend "trop de temps" et qu'il y a conflit !
    Comment s'en sortir ?

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    464
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Décembre 2003
    Messages : 464
    Points : 114
    Points
    114
    Par défaut
    J'ai un peu modifié le code et maintenant, ça roule !!

    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
    private void button9_Click(object sender, EventArgs e)
            {             
                label18.Text = "";
                label19.Text = "";
                label20.Text = "";
                label21.Text = "";
                label22.Hide();            
                Regex myRegex = new Regex("^([0-9]{2}:[0-9]{2}|[0-9]{2}:[0-9]{2}:[0-9]{2})$");
                DateTime datechoisieform1 = monthCalendar1.SelectionRange.Start;
                DateTime heurechoisieform1;
                bool isv = DateTime.TryParse(textBox3.Text, out heurechoisieform1);
                if (isv && myRegex.IsMatch(textBox3.Text))
                {
                    textBox3.Text = heurechoisieform1.ToString("HH:mm:ss");
                    dhchoisies = new DateTime(datechoisieform1.Year, datechoisieform1.Month, datechoisieform1.Day, heurechoisieform1.Hour, heurechoisieform1.Minute, heurechoisieform1.Second);
                    TimeSpan diff = dhchoisies.Subtract(DateTime.Now);
                    if (diff.TotalSeconds > 0)
                    {
                        if (!backgroundWorker1.IsBusy) backgroundWorker1.RunWorkerAsync(dhchoisies);
                        else
                        {
                            restartbgw = true;
                            backgroundWorker1.CancelAsync();                        
                        }
                    }
                    else
                    {
                        textBox3.Text = "";
                        MessageBox.Show("Le couple \"date-heure\" que vous avez choisi est antérieur aux date et heure actuelles", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    }
                }
                else
                {
                    textBox3.Text = "";
                    MessageBox.Show("Heure non-valide ! Veuillez recommencer...", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                }            
            }
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                DateTime dhch = (DateTime)e.Argument;
                TimeSpan dif = dhch.Subtract(DateTime.Now);
                int tpstotal = (int)dif.TotalSeconds;
                while (!backgroundWorker1.CancellationPending && dif.TotalMilliseconds > 0)
                {
                    dif = dhch.Subtract(DateTime.Now);
                    backgroundWorker1.ReportProgress(((tpstotal - ((int)dif.TotalSeconds)) / tpstotal) * 100, dif);
                    Thread.Sleep(1000);
                }
                if (backgroundWorker1.CancellationPending)
                {
                    e.Cancel = true;                
                }
            }
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                TimeSpan ts = (TimeSpan)e.UserState;
                label18.Text = ts.Days.ToString();
                label19.Text = ts.Hours.ToString();
                label20.Text = ts.Minutes.ToString();
                label21.Text = ts.Seconds.ToString();
            }
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (!e.Cancelled) label22.Show();
                if (restartbgw == true)
                {
                    restartbgw = false;
                    backgroundWorker1.RunWorkerAsync(dhchoisies);
                }
            }

Discussions similaires

  1. Réponses: 2
    Dernier message: 12/09/2013, 11h23
  2. Réponses: 4
    Dernier message: 12/08/2008, 15h40
  3. suppression dans une table qui contient une clé etrangère
    Par zana74 dans le forum Décisions SGBD
    Réponses: 13
    Dernier message: 08/08/2006, 10h58
  4. événement lors du défilement d'une listebox ???
    Par OutOfRange dans le forum Composants VCL
    Réponses: 4
    Dernier message: 28/11/2005, 21h43
  5. Gestion des évènements lors d'un clique sur une image.
    Par yoghisan dans le forum Débuter
    Réponses: 7
    Dernier message: 23/06/2005, 19h04

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