C#中如何使用定时器 [英] how to use Timer in C#

查看:33
本文介绍了C#中如何使用定时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 system.Timers.Timer 创建一个计时器.

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

send函数中的receiver是我在使用函数时需要设置的参数,但是当我在send函数中添加参数时,如:

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)

然后它抛出一个错误.我查了 MSDN 后说 ElapsedEventArgs 只适用于这些不会产生数据的函数.

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

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

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

推荐答案

您不能将额外的参数传递给事件处理程序回调,因为您不是调用它的人 -- 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
");
}

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

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

如果您想知道所有这些的开销,那是非常小的.Lambda 只是语法糖,是幕后的普通函数(为事件内容抛出一些自动委托包装).闭包是使用编译器生成的类实现的,但除非您确实拥有 的闭包,否则您不会注意到任何代码膨胀.

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.

正如评论中所指出的,您似乎正在访问 OnTimerElapsed 代码中的 UI 元素——因为您没有使用 Windows 窗体计时器,所以您很有可能会得到这样做是一个例外,因为代码将在计时器触发事件​​时碰巧运行的任何线程上运行——并且 Windows 中的 UI 控件必须被访问来自创建它们的线程.

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.

您可以使用 this.Invoke 手动修复它,但更容易让计时器通过 SynchronizingObject 属性:

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

这篇关于C#中如何使用定时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆