为什么我的C#中System.Timers.Timer事件没有触发

5
System.Timers.Timer timer = new System.Timers.Timer();

private void button1_Click(object sender, EventArgs e)
{
    timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
    timer.Interval = 2000;

    timer.Enabled = true;
    timer.Start();
}

private void timer_Elapsed(object myobject, System.Timers.ElapsedEventArgs e)
{
    Say("Time hit" + DateTime.Now.ToString());
}

我漏掉了什么?

编辑:

尝试添加:

timer.AutoReset = true;

对于那些好奇的人,Say方法是:

private void Say(string s)
        {

            try
            {
                txtSay.AppendText(s + "\r\n");
            }
            catch
            {
            }
        }

say方法没有问题。它可以与其他所有东西一起使用。


6
你点击了按钮1吗?;) - Øyvind Bråthen
2
Say方法中你做什么? - Jahan Zinedine
1
你的 Say 方法存在UI跨线程问题。在这种情况下,你应该会得到一个异常,然而... - leppie
此外,在 UI 中应该使用 System.Windows.Forms.Timer,而不是 System.Timers.Timer - leppie
1
真正的解决方案从来不是编写空的catch块,以此来隐藏错误。这样做可以避免你在编写SO问题时浪费大量时间。 - Cody Gray
显示剩余10条评论
6个回答

5

我觉得你没有提到你遇到了跨线程异常的问题。 尝试像这样更改代码:

Invoke(new Action(()=>Say("Time hit" + DateTime.Now.ToString())));

是的!!! 没错。您能指导我阅读为什么会发生这种情况吗? - Isaac Pounder
1
@IsaacPounder: 请详细了解ISynchronizeInvoke接口。 - leppie
@IsaacPounder:嘿,如果你移除空的catch语句,然后将异常信息复制粘贴到你选择的搜索引擎中,你会找到你需要的一切... - Ade Stringer
@Isaac System.Timers.Timer在新线程中开始执行。请阅读如何:对Windows窗体控件进行线程安全调用 - Renatas M.

5

因为

  1. your Timers.Timer does not set a SyncObject
  2. Therefore your event fires on another thread
  3. Setting the Text property raises a cross-threading Exception
  4. And then you swallow that exception without any trace

    private void Say(string s)
    {
        try
        {
            txtSay.AppendText(s + "\r\n");
        }
        catch  // empty catch-block: the real fundamental problem
        {
        }
    }
    
所以计时器事件确实会触发,但它会产生一个隐藏的错误。
一个简短而实用的解决方案是使用Windows.Timer来进行GUI相关的计时器。

是的,我实际上已经使用Windows窗体计时器使其工作。但是我正在使用此表单进行测试,但是我实际需要此功能的地方没有GUI(也没有文本框)。您还正确指出我没有捕获该异常。在您的情况下,文本框示例的解决方案有效。我赞同。 - Isaac Pounder

0

这可能不正确,但根据MSDN的示例,您不应该需要调用t.Start(),t.Enable应该会启动它。由于您通过执行t.Enabled和t.Start来启动它,因此可能会与AutoRest属性发生冲突。

我还会通过添加断点或类似的东西来确保Say方法按照其应有的方式工作。在这种情况下,我不知道您正在调用哪个AppendText。

有一点猜测。


0

正如Reniuz所说,您可能会收到异常,因为您正在尝试从不同的线程更新UI。 Timer类在单独的线程上运行,以防止其干扰应用程序的响应能力。

这是一个很好的例子,说明为什么try { /* something */ } catch {}是一个坏主意 - 您通过编写此代码完全隐藏了错误。 如果您没有编写它,您可能已经能够从异常消息中找出需要在正确的线程上调用UI更新。


0

您不需要在 Click 方法中设置 EventHandler。在您的类构造函数中设置它,它将起作用。

在点击功能中保留 Start() 方法:

private void button1_Click(object sender, EventArgs e)
{
    timer.Start();
}

0
在C++/CLI(使用.NET的托管C++ - 它非常接近C#),您应该通过此计时器设置对象进行同步。
它可能看起来像这样:+-
timer->SynchronizingObject = txtSay;

在C#中,可能使用"."代替"->"

请参阅文章


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接