web-dev-qa-db-fra.com

comment utiliser Timer en C #

J'utilise system.Timers.Timer pour créer une minuterie.

public System.Timers.Timer timer = new System.Timers.Timer(200);
private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Enabled = true;
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send);
    timer.AutoReset = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Le récepteur dans la fonction d'envoi est un paramètre que je dois définir lorsque la fonction est utilisée, mais lorsque j'ajoute un paramètre dans la fonction d'envoi, comme:

public void send(object source, System.Timers.ElapsedEventArgs e,string receiver)

Ensuite, il lance une erreur. Après avoir vérifié le MSDN, il a déclaré que ElapsedEventArgs n'est disponible que pour ces fonctions qui ne produiront pas de données.

Comment puis-je résoudre ce problème? Mon programme n'est pas Windows.Form, donc je ne peux pas utiliser le System.Windows.Forms.Timer.

16
psyche

Vous ne pouvez pas passer de paramètres supplémentaires au rappel du gestionnaire d'événements, car vous n'êtes pas celui qui l'appelle - le Timer est; exactement ;-)

Mais, vous pouvez facilement obtenir le même effet avec une fermeture:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Elapsed += (timerSender, timerEvent) => send(timerSender, timerEvent, receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e, string receiver)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Le gestionnaire Elapsed est maintenant le (timerSender, timerEvent) => action lambda, qui ferme la variable receiver et appelle send manuellement avec le paramètre supplémentaire chaque fois que le lambda est déclenché.

Dans votre cas particulier, vous n'avez pas du tout besoin de l'expéditeur ou des arguments, il n'est donc pas nécessaire de les transmettre. Le code devient:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

private void OnTimerElapsed(string receiver)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}

Si vous vous interrogez sur les frais généraux de tout cela, c'est assez minime. Les lambdas ne sont que du sucre syntaxique et sont de simples fonctions en arrière-plan (avec un habillage automatique des délégués pour les événements). Les fermetures sont implémentées à l'aide de classes générées par le compilateur, mais vous ne remarquerez aucun gonflement de code sauf si vous en avez vraiment une tonne .

Comme indiqué dans les commentaires, vous semblez accéder à un élément d'interface utilisateur dans le code OnTimerElapsed - puisque vous n'utilisez pas un minuteur Windows Forms, il y a de fortes chances que vous obteniez une exception en faisant cela car le code s'exécutera sur n'importe quel thread dans lequel le minuteur se trouve en cours d'exécution lorsqu'il déclenche l'événement - et les contrôles d'interface utilisateur dans Windows doivent être accessibles uniquement à partir du thread qui les a créés.

Vous pourriez jouer avec this.Invoke pour le corriger manuellement, mais il est plus facile de faire en sorte que le temporisateur organise l'événement pour le bon thread via la SynchronizingObject propriété :

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.SynchronizingObject = this;    // Assumes `this` implements ISynchronizeInvoke
    timer.Elapsed += (s_, e_) => OnTimerElapsed(receiver);
    timer.AutoReset = true;
    timer.Enabled = true;
}

Enfin, invité par un autre commentaire, voici une autre façon de stocker une référence à la fermeture afin de pouvoir vous désinscrire de l'événement plus tard:

private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.SynchronizingObject = this;    // Assumes `this` implements ISynchronizeInvoke
    ElapsedEventHandler onElapsed;
    onElapsed = (s_, e_) => {
        timer.Elapsed -= onElapsed;    // Clean up after firing
        OnTimerElapsed(receiver);
    };
    timer.Elapsed += onElapsed;
    timer.AutoReset = true;
    timer.Enabled = true;
}
21
Cameron

Vous ne pouvez pas transmettre de paramètres supplémentaires à un gestionnaire d'événements comme celui-ci.

Stockez votre valeur dans une variable de niveau objet afin qu'elle soit accessible dans le gestionnaire d'événements.

private string receiver;

public System.Timers.Timer timer = new System.Timers.Timer(200);
private void btnAutoSend_Click(object sender, EventArgs e)
{
    timer.Enabled = true;
    receiver = 'your val';
    timer.Elapsed += new System.Timers.ElapsedEventHandler(send);
    timer.AutoReset = true;
}

public void send(object source, System.Timers.ElapsedEventArgs e)
{
    this.rtbMsg.AppendText("psyche-->" + receiver + ": hello\n");
}
3
nunespascal
public partial class Form2 : Form
{
    Timer timer = new Timer();
    public Form2()
    {
        InitializeComponent();
        timer.Tick += new EventHandler(timer_Tick); // Every time timer ticks, timer_Tick will be called
        timer.Interval = (10) * (1000);             // Timer will tick every 10 seconds
        timer.Start();                              // Start the timer
    }
    void timer_Tick(object sender, EventArgs e)
    {
        //MessageBox.Show("Tick");                    // Alert the user
        var time = DateTime.Now;
        label1.Text = $"{time.Hour} : {time.Minute} : {time.Seconds} : {time.Milliseconds}";
    }
    private void Form2_Load(object sender, EventArgs e)
    {

    }
}
2
SATTHESH TG