Start a thread for a sub inside a class - vb.net

What im trying to do is start a thread of a Sub which is inside a class , that will change form1's label1.text . Apparently this code doesnt work .
Public Class Form1
Public Class test
Public Sub doit()
Form1.chan("hello")
End Sub
End Class
Delegate Sub changeit(ByVal test As String)
Public Sub chan(ByVal test As String)
If Me.Label1.InvokeRequired Then
Dim d As New changeit(AddressOf chan)
Me.Invoke(d, {test})
Else
Me.Label1.Text = test
Label1.Refresh()
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim a As New test
Dim thread As New Threading.Thread(AddressOf a.doit)
thread.Start()
End Sub
End Class

Related

Thread inside module and add value into me.texbox1

Have anyone idea why my code return "" inside my Textbox ? :-)
This i have in main Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim My_Thread as Threading.Thread
My_Thread = New Threading.Thread(AddressOf Module1.MyTest)
My_Thread.Start()
End Sub
And this in module1
Sub MyTest()
Dim TestingValue as string = "Test"
MainForm.Textbox1.Text = TestingValue
End sub
Invoke all time crash code and another try return "" inside texbox1 :-/
Create a Sub Class with public declarations to any object you want on MainForm, then pass the class as a parameter to the module. This would be a cleaner approach than passing the entire Form class instance. Then using the method that Jimi has suggested you can setyou textboxs without cross thread violation.
Public Class MainForm
Public Class PassToModule
Public TxBx1 As TextBox = MainForm.TextBox1
Public TxBx2 As TextBox = MainForm.TextBox2
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim PassToModule As New PassToModule
Dim My_Thread As Threading.Thread
My_Thread = New Threading.Thread(AddressOf MyTest)
My_Thread.Start(PassToModule)
End Sub
End Class
Module Module1
Dim FromMainForm As MainForm.PassToModule
Sub MyTest(PasToModule As MainForm.PassToModule)
FromMainForm = PasToModule
FromMainForm.TxBx1.BeginInvoke(New MethodInvoker(Sub()
FromMainForm.TxBx1.Text = "Test"
FromMainForm.TxBx2.Text = "Test"
End Sub))
End Sub
End Module

how to safe call a control from another thread using Timers.Timer

I read various posts, and made a practice project, but it does not works.
The form have a button and a text box with a default text 'Updated 0 times'. On button click starts the timer and each time update the text with the number of times the text was updated.
The exception of cross thread calls is not thrown, but when calling the text box, its .Text = "", the text is updated but not the text box on the form. And InvokeRequired is always false.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Here the textBox.Text = "Updated 0 times."
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer()
End Sub
Delegate Sub UpdateTextInvoke(ByVal new_text As String)
Public Sub UpdateText(ByVal new_text As String)
'Here the textBox.Text = ""
Dim txtB As TextBox = Me.TextBox1
'InvokeRequired always = False.
If txtB.InvokeRequired Then
Dim invk As New UpdateTextInvoke(AddressOf UpdateText)
txtB.Invoke(invk, New Object() {new_text})
Else
'The value of this text box is updated, but the text on the form TextBox1 never changes
txtB.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer
Private Shared counter As Integer
Public Shared Sub StartTimer()
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
Form1.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class
SOLVED
In the Class TimerTest added this code 'Private Shared myform As Form1 = Form1'
then changed 'Form1.UpdateText' To 'myform.UpdateText'
As indicated in the comments, you are using the default form instance feature of VB.Net. You could pass an instance of the form to the TimerTest class, and replace the reference to Form1 with the instance.
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim checking_text As String = Me.TextBox1.Text
TimerTest.StartTimer(Me)
End Sub
Public Sub UpdateText(new_text As String)
If TextBox1.InvokeRequired Then
Dim invk As New Action(Of String)(AddressOf UpdateText)
TextBox1.Invoke(invk, {new_text})
Else
TextBox1.Text = new_text
End If
End Sub
End Class
Public Class TimerTest
Private Shared tmr As New System.Timers.Timer()
Private Shared counter As Integer
Private Shared instance As Form1
Public Shared Sub StartTimer(formInstance As Form1)
instance = formInstance
tmr.Interval = 5000
AddHandler tmr.Elapsed, AddressOf UdpateText
tmr.Enabled = True
End Sub
Public Shared Sub UdpateText(ByVal sender As Object, ByVal e As System.EventArgs)
counter += 1
instance.UpdateText(String.Format("Updated {0} time(s).", counter))
End Sub
End Class

VB Unable to access instance of another class from one method but can from another

I have 2 main classes. The first launches the second which implements a FIX dll. I would like to be able to set variables/textbox.text in the first from the second. I am able to do so from te OnCreate method in the second, but for some reason cannot from the OnLogon method. Any ideas ?
Thanks
Imports QuickFix
Public Class GlobalVariable
Inherits MainFIXClass
Public Shared instance As MainFIXClass
End Class
Public Class MainFIXClass
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GlobalVariable.instance = Me
Connect({"D:\\Config.txt"})
End Sub
Private Sub Connect(args As String())
Dim settings As New QuickFix.SessionSettings(args(0))
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
Try
initiator.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
End Class
Public Class MyQuickFixApp
Inherits MainFIXClass
Implements IApplication
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
Private _instance As MainFIXClass
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_instance = GlobalVariable.instance
_session = Session.LookupSession(sessionID)
_instance.OutputTB.Text = "On Create - " & sessionID.ToString & " " & _session.ToString ' **************************** this line works
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
_instance.OutputTB.Text = "Logged On" ' **************************** this line does not work ?????
MsgBox("Logged On")
End Sub
End Class
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Private WithEvents bw As BackgroundWorker
Delegate Sub ShowOutputDelegate(value As String)
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
GlobalVariable.instance = Me
bw = New BackgroundWorker
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
Try
'If Not TypeOf e.Argument Is String() Then 'only take valid input
' Throw New ArgumentException("Invalid argument")
'End If
'Dim args As String() = DirectCast(e.Argument, String()) 'you can pass your arguments here
initiator.Start()
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
End Sub
Public Sub ShowOutput(msg As String)
If InvokeRequired Then
Invoke(New ShowOutputDelegate(AddressOf ShowOutput), msg)
Else
Me.OutputTB.Text = msg
End If
Me.OutputTB.Text = msg
End Sub
End Class
Public Class MyQuickFixApp
Implements IApplication
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
Private _instance As MainFIXClass
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_instance = GlobalVariable.instance
_session = Session.LookupSession(sessionID)
_instance.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
_instance.ShowOutput("Logged On")
End Sub
End Class
Public Class GlobalVariable
Public Shared instance As MainFIXClass
End Class
To prevent the Window from blocking, you can use Threads or a BackgroundWorker. I prepared a small code snippet that demonstrates how you can use the BackgroundWorker. Please note how the DoWork and WorkCompleted methods are wired to the worker instance by using Handles.
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Implements IApplication
Private WithEvents bw As BackgroundWorker
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
#Region "IApplication Methods"
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_session = Session.LookupSession(sessionID)
Me.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
Me.ShowOutput("Logged On")
End Sub
#End Region
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
bw = New BackgroundWorker
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
bw.ReportProgress(0, "Starting initiator")
initiator.Start()
bw.ReportProgress(0, "Initiator started successfully")
End Sub
Private Sub bw_ReportProgress(source As Object, e As ProgressChangedEventArgs) Handles bw.ProgressChanged
Me.ShowOutput(e.UserState.ToString())
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
MsgBox(e.Error.Message)
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
Me.ShowOutput("Worker finished")
End Sub
Public Sub ShowOutput(msg As String)
Me.OutputTB.Text = msg
End Sub
End Class
Here is a snippet when merging both classes
Imports System.ComponentModel
Imports System.Threading
Imports QuickFix
Imports QuickFix.Fields
Imports QuickFix.MessageCracker
Public Class MainFIXClass
Implements IApplication
Private WithEvents bw As BackgroundWorker
Private _session As Session = Nothing
Private _settings As QuickFix.Session = Nothing
Private _Store As QuickFix.IMessageStore = Nothing
#Region "IApplication Methods"
Public Sub OnCreate(sessionID As SessionID) Implements IApplication.OnCreate
_session = Session.LookupSession(sessionID)
Me.ShowOutput("On Create - " & sessionID.ToString & " " & _session.ToString)
End Sub
Public Sub OnLogon(sessionID As SessionID) Implements IApplication.OnLogon
Me.ShowOutput("Logged On")
End Sub
#End Region
Private Sub CurrencyArb_Load(sender As Object, e As EventArgs) Handles MyBase.Load
bw = New BackgroundWorker
bw.WorkerReportsProgress = True
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bw.DoWork
Dim settings As New QuickFix.SessionSettings("D:\\CurrencyArb.txt")
Dim myApp As IApplication = New MyQuickFixApp()
Dim storeFactory As QuickFix.IMessageStoreFactory = New FileStoreFactory(settings)
Dim logFactory As QuickFix.ILogFactory = New FileLogFactory(settings)
Dim initiator As New QuickFix.Transport.SocketInitiator(myApp, storeFactory, settings, logFactory)
bw.ReportProgress(0, "Starting initiator")
initiator.Start()
bw.ReportProgress(0, "Initiator started successfully")
End Sub
Private Sub bw_ReportProgress(source As Object, e As ProgressChangedEventArgs) Handles bw.ProgressChanged
Me.ShowOutput(e.UserState.ToString())
End Sub
Private Sub bw_WorkCompleted(source As Object, e As RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
If e.Error IsNot Nothing Then
'and exception occured
MsgBox(e.Error.Message)
Else
'everything was fine, you can use the result
Dim result As Object = e.Result
End If
Me.ShowOutput("Worker finished")
End Sub
Public Sub ShowOutput(msg As String)
Me.OutputTB.Text = msg
End Sub
End Class

vb2012 textbox backcolor does't change using thread

I wrote very simple thread example.
Make normal form1 and drop 1 textbox
run thread work on form load
thread change a textbox backcolor looks like switch on/off
But, it doesn't work.....
Can you tell me why doesn't work??
see my source.
=====================================================================
Imports System.Threading
Public Class Monitor
Public wObj As Worker = New Worker()
Public MyThread As Thread = New Thread(AddressOf wObj.DoWork)
Public Sub ChangeTBColor(pOption As Integer)
If pOption = 1 Then
tb1.BackColor = Color.Aqua
Else
tb1.BackColor = Color.Red
End If
End Sub
Private Sub Monitor_Load(sender As Object, e As EventArgs) Handles Me.Load
MyThread.Start()
Console.WriteLine("Running OrgThread..")
Console.WriteLine("Stop running")
End Sub
Private Sub BtnThreadStop_Click(sender As Object, e As EventArgs) Handles BtnThreadStop.Click
Me.wObj.RequestStop()
End Sub
End Class
Public Class Worker
Private LoopStop As Boolean = True
Public Sub DoWork()
Console.WriteLine("User Thread Start!")
Dim iTemp As Integer = 0
While (LoopStop)
Monitor.ChangeTBColor(iTemp Mod 2)
iTemp = iTemp + 1
Thread.Sleep(500)
End While
Console.WriteLine("User Thread End.!")
End Sub
Public Sub RequestStop()
LoopStop = False
End Sub
End Class
As already mentioned, your starting a new thread for your work, the issue is your trying to change the color for a control that need invoking. With this said, we need a delegate for when the control needs to be invoked... In my example, I used one class that handles this all and works great. Also please make sure to import System.ComponentModel because this is needed for the BackgroundWorker... I used the background worker as it takes all the heavy lifting off you would need...
Imports System.ComponentModel
Imports System.Threading
Public Class Monitor
Delegate Sub SetColor(ByVal clr As Integer) 'Your delegate..
Private WithEvents bw As New BackgroundWorker
Public Sub ChangeTBColor(pOption As Integer)
If Me.tb1.InvokeRequired Then 'Invoke if required...
Dim d As New SetColor(AddressOf ChangeTBColor) 'Your delegate...
Me.Invoke(d, New Object() {pOption})
Else
If pOption = 1 Then
tb1.BackColor = Color.Aqua
Else
tb1.BackColor = Color.Red
End If
End If
End Sub
Private Sub Monitor_Load(sender As Object, e As EventArgs) Handles Me.Load
bw.WorkerSupportsCancellation = True
Console.WriteLine("Running OrgThread..")
bw.RunWorkerAsync()
End Sub
Private Sub bw_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork
Dim iTemp As Integer = 0
Dim LoopStop As Boolean = True
Console.WriteLine("User Thread Start!")
While (LoopStop)
If Not (bw.CancellationPending) Then
ChangeTBColor(iTemp Mod 2)
iTemp = iTemp + 1
Thread.Sleep(500)
Else
e.Cancel = True
LoopStop = False
End If
End While
End Sub
Private Sub bw_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bw.RunWorkerCompleted
Console.WriteLine("User Thread End.!")
End Sub
Private Sub BtnThreadStop_Click(sender As Object, e As EventArgs) Handles BtnThreadStop.Click
If bw.IsBusy Then
bw.CancelAsync()
Else
Console.WriteLine("Running OrgThread..")
bw.RunWorkerAsync()
End If
End Sub
End Class
Here's my screenshot of my test... This is tried and tested. Please be sure to vote if this helps you!

VB Net - Pass data from Thread to Main GUI

I've managed to get the data I want in a thread, however I'm having trouble getting my head around passing the data back into my main thread (GUI).
I'm grabbing data from a network stream in a thread, then need to pass it to my main thread in order to pass to other classes etc.
I've seen it mentioned to use backgroundworker for this, but as I'm expecting it to gather data periodically and never stop, I thought a separate thread for this would be best, but I'm very new to multithreading.
If threading is the correct way to go, how can I pass data from it back to my main thread in order to use this for other stuff? I've seen delegates and events mentioned a lot but can't see how I'd pass data with these?
Thanks
Please study this example, and let me know if it fits your requirements:
Controls required: lstItems (ListBox), btnStart (Button), btnStop (Button), Timer1 (Timer).
Form1 code:
Public Class Form1
Dim p_oStringProducer As StringProducer
Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
p_oStringProducer = New StringProducer
p_oStringProducer.Start()
Timer1.Enabled = True
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) _
Handles btnStop.Click
Timer1.Enabled = False
p_oStringProducer.Stop()
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Dim asQueue As Concurrent.ConcurrentQueue(Of String) =
p_oStringProducer.MessageQueue
While asQueue.Count > 0
Dim sItem As String = Nothing
asQueue.TryDequeue(sItem)
lstItems.Items.Add(sItem)
End While
End Sub
End Class
StringProducer code:
Imports System.Threading.Tasks
Public Class StringProducer
Private p_fKeepRunning As Boolean
Private p_oTask As task
Private p_aMessageQueue As Concurrent.ConcurrentQueue(Of String)
Private p_iNextMessageId As Integer
Public ReadOnly Property MessageQueue As _
Concurrent.ConcurrentQueue(Of String)
Get
Return p_aMessageQueue
End Get
End Property
Sub New()
p_oTask = New Task(AddressOf TaskBody)
p_aMessageQueue = New Concurrent.ConcurrentQueue(Of String)
p_iNextMessageId = 0
End Sub
Public Sub Start()
p_fKeepRunning = True
p_oTask.Start()
End Sub
Public Sub [Stop]()
p_fKeepRunning = False
End Sub
Private Sub TaskBody()
While p_fKeepRunning
Threading.Thread.Sleep(2000)
p_aMessageQueue.Enqueue("Message #" & p_iNextMessageId)
p_iNextMessageId += 1
End While
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
Me.Stop()
End Sub
End Class
This was not extensively tested, but it should give you a head start.