【问题标题】:A problem with MyThread and the Timer ControlMyThread 和 Timer Control 的问题
【发布时间】:2009-10-08 20:36:12
【问题描述】:

我有一个方法,正在第二个线程中调用:

    public byte[] ReadAllBytesFromStream(Stream input)
    {
        clock.Start();

        using (...)
        {
            while (some conditions) //here we read all bytes from a stream (FTP)
            {
                ...
 (int-->)       ByteCount = aValue;
                ...
             }
            return .... ;
        }
    }

    private void clock_Tick(object sender, EventArgs e)
    {
        //show how many bytes we have read in each second
        this.label6.Text = ByteCount.ToString() + " B/s"; 
    }

问题是,时钟已启用,但它没有滴答作响。为什么?

更新:

Tick 事件已正确添加,Interval 属性设置为 1000。

我将计时器控件放在设计视图中的表单上。

【问题讨论】:

  • 我刚刚在设计视图中的窗体上放置了定时器控件
  • 正确添加Tick事件,Interval属性设置为1000

标签: c# multithreading timer


【解决方案1】:

问题是您在第二个线程上启用了计时器,而该线程没有消息泵。

Windows 窗体计时器基于 SetTimer。当定时器启用时,它会创建一个隐藏窗口并将该窗口的句柄发送到 SetTimer API,然后,系统会在每次定时器的时间间隔过去时向窗口发送 WM_TIMER 消息。然后隐藏窗口处理该消息并引发 Tick 事件。

在您的情况下,计时器是在第二个线程上创建的,但它没有消息泵,因此 WM_TIMER 消息永远不会到达您的窗口。您要做的是在 UI 线程上启用计时器,以便在发送 WM_TIMER 消息时在具有消息泵的 UI 线程中对其进行处理。假设您的过程在表单类中,您可以使用对表单的 this 引用来编组调用以启用计时器(如果它不在表单类中,则需要对形式)像这样:

public byte[] ReadAllBytesFromStream(Stream input)
{
    if(this.InvokeRequired)
    {
        this.Invoke(new MethodInvoker(clock.Start));
    }
    else
    {
        clock.Start();
    }

    using (...)
    {
        while (some conditions) //here we read all bytes from a stream (FTP)
        {
            ...
 (int-->)   ByteCount = aValue;
            ...
         }
        return .... ;
    }
}

private void clock_Tick(object sender, EventArgs e)
{
    this.label6.Text = ByteCount.ToString() + " B/s"; //show how many bytes we have read in each second
}

【讨论】:

  • +1 在这个问题上我从来没有想过Invoke。谢谢@Stephen Martin。
【解决方案2】:

在启动计时器之前,您需要将其Tick 事件附加到您要处理该事件的方法中。在这种情况下,您可以在启动计时器之前执行此操作:

clock.Tick += this.clock_Tick;

【讨论】:

    【解决方案3】:

    只有主线程可以更新 UI。假设您的时钟已正确初始化(正如其他人指出的那样)并且正在从您的第二个线程调用“clock_Tick”,您需要像这样重写它:

    private void clock_Tick(object sender, EventArgs e)
    {
        // InvokeRequired will be true on every thread EXCEPT the UI thread
        if (label6.InvokeRequired)
        {
            // Issue an asynchoronous request to the UI thread to perform the update
            label6.BeginInvoke(new MethodInvoker(this.clock_Tick), sender, e);
        }
        else
        {
            // Actually do the update
            label6.Text = ByteCount.ToString() + " B/s";
        }
    }
    

    这是针对 WinForms.. WPF 语法略有不同,但功能相同。

    这是一篇关于整个事件的文章:http://weblogs.asp.net/justin_rogers/pages/126345.aspx

    祝你好运!

    【讨论】:

      【解决方案4】:

      您是否设置了时钟的 Interval 属性?

      【讨论】:

        【解决方案5】:

        这只是一个猜测,但请确保您的计时器控件的 Tick 事件正确绑定到您的 clock_Tick 方法。

        【讨论】:

          【解决方案6】:

          您可能有“System.timer”和“windows.form.timer”冲突,System.timer 在单独的线程上运行,而 form.timer 在主线程中运行以便在 .designer.cs将“计时器”更改为“System.windows.form.timer”它应该可以工作

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-07-10
            • 1970-01-01
            • 1970-01-01
            • 2013-07-23
            相关资源
            最近更新 更多