如何在C#中使用Timer

我正在使用system.Timers.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"); } 

发送函数中的接收器是我在使用函数时需要设置的参数,但是当我在发送函数中添加参数时,如:

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

然后它会抛出一个错误。 在我检查了MSDN之后,它说ElapsedEventArgs仅适用于这些不会产生数据的函数。

我怎么解决这个问题? 我的程序不是windows.Form,所以我不能使用System.Windows.Forms.Timer

您不能将额外的参数传递给事件处理程序回调,因为您不是调用它的人 – Timer是; 这就是重点;-)

但是,您可以通过闭包轻松实现相同的效果:

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

现在,Elapsed处理程序是(timerSender, timerEvent) => lambda动作,它关闭receiver变量,并在每次触发lambda时使用extra参数手动调用send

在您的特定情况下,您根本不需要发件人或参数,因此无需转发它们。 代码变成:

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

如果你想知道所有这些的开销,它是非常小的。 Lambdas只是语法糖,并且是幕后的简单函数(为事件提供了一些自动委托包装)。 闭包是使用编译器生成的类实现的,但你不会注意到任何代码膨胀,除非你真的有很多。

正如评论中指出的那样,您似乎正在访问OnTimerElapsed代码中的UI元素 – 因为您没有使用Windows窗体计时器,所以您很可能会因为代码运行而得到exception在触发事件时计时器碰巧运行的任何线程上 – 并且必须 仅从创建它们的线程访问Windows中的UI控件。

你可以搞砸这个。 this.Invoke手动修复它,但是让定时器通过SynchronizingObject属性将事件编组到正确的线程更容易:

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

最后,在另一条评论的提示下,这是另一种可以存储对闭包的引用的方法,以便您以后可以取消订阅该事件:

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

您不能将额外的参数传递给类似的事件处理程序。

将值存储在对象级变量中,以便可以在事件处理程序中访问它。

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