Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A problem with MyThread and the Timer Control

I have a method, which is being invoked in the second Thread:

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

the problem is, the clock is Enabled, but it's not ticking. Why?

Updates:

The Tick event is properly added, the Interval property is set to 1000.

I put the Timer Control on the form in the Design View.

like image 932
Tony Avatar asked Aug 05 '26 22:08

Tony


2 Answers

The problem is that you are enabling your timer on the second thread and this thread does not have a message pump.

The Windows forms timer is based on SetTimer. When the timer is enabled it creates a hidden window and sends the handle to that window to the SetTimer API, The system, in turn, sends the window a WM_TIMER message every time the interval for the timer has elapsed. The hidden window then processes that message and raises the Tick event.

In your situation the timer is created on the second thread but it does not have a message pump so the WM_TIMER message never reaches your window. What you want to do is enable your timer on your UI thread so that when the WM_TIMER message is sent it is processed in the UI thread which has a message pump. Assuming your procedure is inside your form class you can use the this reference to your form to marshal the call to enable the timer (if it isn't inside the form class you'll need a reference to the form) like so:

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
}
like image 182
Stephen Martin Avatar answered Aug 08 '26 13:08

Stephen Martin


Before you start the timer you need to attach its Tick event to your method that you want to handle the event. In this case you would do this prior to starting the timer:

clock.Tick += this.clock_Tick;
like image 44
Andrew Hare Avatar answered Aug 08 '26 13:08

Andrew Hare