I have finally got my VB.net project working again.
I have been stuck for 2 days trying to work out how to use a timer
and to display changes on a form.
The problem is that when the timer event fires it is run on a
separate thread so trying to display anything on any of the controls
on the form produces this message at runtime.
Error: Cross-thread operation not valid: Control 'TextBox2' accessed
from a thread other than the thread it was created on.
I have read much but couldn't understand what to put where and in
what order – until now. My program builds bars from level one
quotes. When the timer fires it's time to store a new bar into an
array. (I dropped the idea of using a collection). Each time the new
bar is processed I want to send some visual information to the user.
This is how it's done:
Option Strict On
Option Explicit On
Imports VB = Microsoft.VisualBasic
Friend Class frmSABT
Inherits System.Windows.Forms.Form
Implements MBTQUOTELib.IMbtQuotesNotify
Delegate Sub SetTextCallback(ByVal [text] As String)
Private Quotes As MBTQUOTELib.MbtQuotes
''don't use system.windows.form.timer as very inaccurate
Friend TPeriod As Integer = 8000 '8 sec period for testing
purposes
Dim WithEvents Timer1 As New System.Timers.Timer(TPeriod)
Dim nsym As Integer = -1 '-1 = no symbols
Dim aFXPairs(3) As FX55 ' use nsym as index 0..3
' this form focuses on level 1 service only
Private Sub IMbtQuotesNotify_OnQuoteData(ByRef NQR As
MBTQUOTELib.QUOTERECORD) _
Implements MBTQUOTELib.IMbtQuotesNotify.OnQuoteData ' this is
Level 1 quote
' NQR is new quote record
Dim key As String = NQR.bstrSymbol
Dim i As Integer
Dim a As Double = NQR.dAsk
Dim b As Double = NQR.dBid
Dim str As String
If (b <> 0) And (a <> 0) Then 'process valid quote
For i = 0 To nsym
If aFXPairs(i).sym = key Then Exit For ' get i
Next
aFXPairs(i).LastQ.HighA = a
aFXPairs(i).LastQ.HighB = b
.
.
.
.
.
Public Sub TimerFired(ByVal sender As Object, ByVal e As
System.Timers.ElapsedEventArgs) Handles Timer1.Elapsed
Dim i As Integer
Dim s As String
For i = 0 To nsym
aFXPairs(i).AnotherBar() 'process bar
Next
i = 0
s = CStr(aFXPairs(i).getlastq.Bid)
` display info
SetText(s) ` this works
Me.TextBox2.Text = s 'this doesn't
End Sub
Private Sub SetText(ByVal [text] As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If Me.TextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {[text]})
Else
Me.TextBox1.Text = [text]
End If
End Sub
End Class 'form