C# 如何在C语言中使用定时器#

C# 如何在C语言中使用定时器#,c#,timer,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);

我正在使用
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

您不能向事件处理程序回调传递额外的参数,因为调用它的不是您——计时器是;这就是重点;-)

但是,使用闭包可以轻松实现相同的效果:

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");
}
现在经过的处理程序是
(timerSender,timerEvent)=>
lambda操作,它关闭
receiver
变量,并在触发lambda时使用额外参数手动调用
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");
}
如果你想知道所有这一切的开销,它是相当小的。lambda只是语法糖,是幕后的普通函数(在事件内容中加入了一些自动委托包装)。闭包是使用编译器生成的类实现的,但除非您确实拥有大量的类,否则不会注意到任何代码膨胀

正如评论中指出的,您似乎正在访问
ontimerecursed
代码中的UI元素——因为您没有使用Windows窗体计时器,这样做很有可能会导致异常,因为当计时器触发事件时,代码将在任何线程上运行,而Windows中的UI控件只能从创建它们的线程访问

您可以处理
这个问题。调用
手动修复它,但更容易的是让计时器通过以下方式将事件发送到正确的线程:


最后,在另一条评论的提示下,这里有另一种方法可以存储对闭包的引用,以便以后可以取消订阅活动:

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

好的,如果您添加了对library.related的引用,您可以使用
System.Windows.Forms.Timer
,您不应该将System.Windows.Timer与任何UI组件一起使用(例如,rtbMsg.AppendText可能访问某种Windows控件),System.Timer.appeased在非UI线程上被调用,并且在大多数情况下会导致异常。如果您不是WinForms并且是WPF,那么您需要使用DispatchTimer。如果你能澄清你收到的错误,也许有人能提供更准确的建议。为什么在设置自动重置之前启动计时器并回拨?timer.Enabled=true应该是您最后要做的事情do@nbrooks:说得好,我只是在复制OP的代码。我会编辑的in@nbrooks它与timer.Start()相同吗?@damith-yeah-timer.Start()只是将enabled设置为true。您可能需要处理使用System.timer访问UI对象所导致的交叉线程操作
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)
    {

    }
}