简体   繁体   中英

how to use Timer in C#

I'm using system.Timers.Timer to create a timer.

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");
}

The receiver in send function is a parameter that I need to set when the function is used, but when I add a parameter in the send function, like:

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

Then it throws an error. After I checked the MSDN, it said ElapsedEventArgs is only available for these function which won't produce data.

How can I solve this problem? My program isn't the windows.Form, so I cannot use the System.Windows.Forms.Timer .

You can't pass extra parameters to the event handler callback, because you aren't the one calling it -- the Timer is; that's the whole point ;-)

But, you can easily accomplish the same effect with a closure:

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");
}

Now the Elapsed handler is the (timerSender, timerEvent) => lambda action, which closes over the receiver variable and calls send manually with the extra parameter whenever the lambda is triggered.

In your particular case you don't need the sender or arguments at all, so there's no need to forward them. The code becomes:

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");
}

If you're wondering about the overhead of all this, it's pretty minimal. Lambdas are just syntactic sugar and are plain functions behind the scenes (with some automatic delegate wrapping thrown in for the event stuff). Closures are implemented using compiler-generated classes, but you won't notice any code bloat unless you truly have a ton of them.

As pointed out in the comments, you seem to be accessing a UI element in the OnTimerElapsed code -- since you're not using a Windows Forms timer, there's a good chance you'll get an exception by doing this since the code will run on whatever thread the timer happens to be running in when it fires the event -- and UI controls in Windows must be accessed only from the thread that created them.

You could mess around with this.Invoke to fix it manually, but it's easier to have the timer marshall the event to the right thread for you via the SynchronizingObject property :

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;
}

Finally, prompted by another comment, here's another way you could store a reference to the closure so that you can unsubscribe from the event later:

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;
}

You can't pass extra parameters to an event handler like that.

Store your value in an object level variable so that it can be accessed in the event handler.

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");
}
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)
    {

    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM