Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations sizbut on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Timer thread issue

Status
Not open for further replies.

griffitd

Programmer
Aug 20, 2002
189
GB
Hi

I have the following code

Public Class frmDataLogger

Dim WithEvents tmrDateTime As New System.Timers.Timer

Private Sub frmDataLogger_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

tmrDateTime.Interval = 1000
tmrDateTime.Enabled = True
AddHandler tmrDateTime.Elapsed, AddressOf Me.UpdateDateTime

End Sub

Private Sub UpdateDateTime()
lblDate.Text = DateTime.Now.ToString("dd/MM/yyyy")
lblTime.Text = DateTime.Now.ToString("HH:mm:ss")
End Sub

When the UpdateDateTime is calle i get a cross thread operation not valid.

Hope you can help

Thanks
 
First, if you use WithEvents you really want to use handles instead of AddHandler. It kind of defeats the purpose if you don't. And either way you have to declare the variables needed for the event. So your code should be like either of the following.

Code:
Private tmrDateTime As New System.Timers.Timer

    Private Sub frmDataLogger_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tmrDateTime.Interval = 1000
        tmrDateTime.Enabled = True
        AddHandler tmrDateTime.Elapsed, New System.Timers.ElapsedEventHandler(AddressOf Me.UpdateDateTime)
    End Sub

    Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
        lblDate.Text = DateTime.Now.ToString("dd/MM/yyyy")
        lblTime.Text = DateTime.Now.ToString("HH:mm:ss")
    End Sub
or
Code:
Private WithEvents tmrDateTime As New System.Timers.Timer

    Private Sub frmDataLogger_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        tmrDateTime.Interval = 1000
        tmrDateTime.Enabled = True
    End Sub

    Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmrDateTime.Elapsed
        lblDate.Text = DateTime.Now.ToString("dd/MM/yyyy")
        lblTime.Text = DateTime.Now.ToString("HH:mm:ss")
    End Sub

The problem with cross threading is different. It is because you are using a system timer. Unless you are not using a form you instead want to use a Windows.Form.Timer. Then you will not get the cross threading error and don't have to jump through as many hoops when you want to use it.

If for some reason you just need to use the system timer then you have to change and add something like the following:
Code:
    Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
        SetLabelText(DateTime.Now.ToString("dd/MM/yyyy"), Label1)
        SetLabelText(DateTime.Now.ToString("HH:mm:ss"), Label2)
    End Sub

    Private Sub SetLabelText(ByVal text As String, ByVal lbl As Label)
        Dim varObj(1) As Object
        varObj(0) = text
        varObj(1) = lbl

        If Me.InvokeRequired Then
            Me.BeginInvoke(New delLabelText(AddressOf LabelText), varObj)
        Else
            LabelText(varObj(0), varObj(1))
        End If
    End Sub

    Private Delegate Sub delLabelText(ByVal text As String, ByVal lbl As Label)
    Private Sub LabelText(ByVal text As String, ByVal lbl As Label)
        lbl.Text = text
    End Sub


-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Hi

Thanks for the reply.

I have entered the code but i still get the same error. I put the code in a brand new project and also get the same error:

Cross-thread operation not valid: Control 'lblDate' accessed from a thread other than the thread it was created on.

Thanks
 
Show which code you used. Did you switch to a Form Timer or did you use the delegate above?

-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Hi - I used

Public Class Form1
Private WithEvents tmrDateTime As New System.Timers.Timer

Private Sub frmDataLogger_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
tmrDateTime.Interval = 1000
tmrDateTime.Enabled = True
End Sub

Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmrDateTime.Elapsed
lblDate.Text = DateTime.Now.ToString("dd/MM/yyyy")
lblTime.Text = DateTime.Now.ToString("HH:mm:ss")
End Sub
End Class

The project has one form with the two labels and the code attached and thats it

Ta
 
Ok, that was only part of what you had to change. Since you are still using a System Timer instead of a Form Timer you have to use the other half of the code.

So change this:
Code:
    Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmrDateTime.Elapsed
        lblDate.Text = DateTime.Now.ToString("dd/MM/yyyy")
        lblTime.Text = DateTime.Now.ToString("HH:mm:ss")
    End Sub

To this:
Code:
    Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmrDateTime.Elapsed
        SetLabelText(DateTime.Now.ToString("dd/MM/yyyy"), lblDate)
        SetLabelText(DateTime.Now.ToString("HH:mm:ss"), lblTime)
    End Sub

    Private Sub SetLabelText(ByVal text As String, ByVal lbl As Label)
        Dim varObj(1) As Object
        varObj(0) = text
        varObj(1) = lbl

        If Me.InvokeRequired Then
            Me.BeginInvoke(New delLabelText(AddressOf LabelText), varObj)
        Else
            LabelText(varObj(0), varObj(1))
        End If
    End Sub

    Private Delegate Sub delLabelText(ByVal text As String, ByVal lbl As Label)
    Private Sub LabelText(ByVal text As String, ByVal lbl As Label)
        lbl.Text = text
    End Sub

-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Thanks Mucj appreciated.

That worked.

If i wanted to do this:

Private WithEvents tmrMain As New System.Timers.Timer

Private Sub frmDataLogger_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
tmrMain.Interval = 1000
tmrMain.Enabled = True
End Sub

Private Sub UpdateDateTime(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles tmrMain.Elapsed
ProcessData()
End Sub

Private Sub ProcessData()
'code
lstMain.Items.Add(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"))
'Save the time to a database code
End Sub



would i do something similar
 
Yes, because the System Timer is on a different thread any thing you do that affects the form must be done through a delegate. The important parts of the code you need are:

Where it checks if a delegate is needed:
Code:
        If Me.InvokeRequired Then
            'Some form of Me.BeginInvoke
        Else
            'Direct call if InvokeRequired = False
        End If
Even if you are sure a delegate is required it is a good practice to check anyway.

Then you need a delegate to call:
Code:
Private Delegate Sub ...

-I hate Microsoft!
-Forever and always forward.
-My kingdom for a edit button!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top