如何从VB中的另一个线程在主线程上调用函数 [英] How do I call a function on the main thread from another thread in vb
问题描述
我有一个计时器函数,该函数在Windows窗体上调用,当单击UI上的按钮时,该函数可以完美工作.但是,在我的应用程序Im使用TCP套接字连接到服务器时,当服务器断开Im的连接时,它会捕获抛出的异常和Id,就像此时要启动计时器(ticker),然后运行重新连接. 当我从try catch中引用计时器时,它不会运行,所以我可以想象它是因为它在主线程上?
I have a timer function which is called on my windows form which works perfectly when a button on the UI is clicked. However, in my application Im connecting to a server using a TCP socket, when the server disconnects Im catching the exception thrown and Id like at this point for the timer to start (ticker) then run the reconnection. When i reference the timer from the try catch it wont run, so I imagine its because its on the main thread?
这是我的计时器代码: 公共委托子DroppedConnectionDelegate(ByVal ReConn为整数)
Here is my code for the timer: Public Delegate Sub DroppedConnectionDelegate(ByVal ReConn As Integer)
Public Sub DroppedConnection(ByVal ReConn As Integer)
Console.Write("Dropped Connection()")
Thread.Sleep(1000)
If ReConn = 1 Then
MakeConnection(My.Settings.savedIP, False)
Else
isRunning = False
Second = 0
'client.Close()
'client.Dispose()
Timer1.Interval = 1000
Timer1.Enabled = True
Timer1.Start() 'Timer starts functioning
End If
' End If
End Sub
Public Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Second = Second + 1
Console.WriteLine(Second)
If Second >= 10 Then
Timer1.Stop() 'Timer stops functioning
Timer1.Enabled = False
MakeConnection(ServerAddressString, False)
End If
End Sub
这里是我想在catch异常时调用计时器的子项:
Here is the sub from where Id like to call the timer on catch exception:
Public Shared Sub ReceiveCallback(ByVal ar As IAsyncResult)
Dim state As StateObject = CType(ar.AsyncState, StateObject)
Dim client As Socket = state.workSocket
Dim strReceiveBuffer As String = String.Empty
' Read data from the remote device.
Dim bytesRead As Integer
Console.WriteLine("ar to string = " & ar.ToString)
'While client.Connected
If (AsynchronousClient.connectDone.WaitOne(5000, True)) Then
Try
If client.Connected = True Then
bytesRead = client.EndReceive(ar)
Console.WriteLine("Socket Connected")
If bytesRead > 0 Then
state.sb.Clear()
' There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead))
strReceiveBuffer = state.sb.ToString()
MainForm.main_Response = state.sb.ToString()
If strReceiveBuffer.IndexOf("doses-remaining") > 0 Then
response = state.sb.ToString()
MainForm.GetLabelTextToString(response)
'receiveDone.Set()
'isReceived = True
'Return
End If
' Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)
Else
' All the data has arrived; put it in response.
If state.sb.Length > 1 Then
response = state.sb.ToString()
End If
' Signal that all bytes have been received.
receiveDone.Set()
isReceived = True
End If
Else
MainForm.WriteLog("RecieveCallback() Error outside catch :" & Date.Today.ToString & " " & TimeOfDay)
MainForm.UpdateList("RecievecallBack error, attempting reconnect..." & client.RemoteEndPoint.ToString())
MainForm.isRunning = False
MainForm.DroppedConnection(0)
End If
Catch ex As Exception
'MessageBox.Show("ReceiveCallback Error, Check Log.")
MainForm.WriteLog("RecieveCallback() Error inside catch :" & Date.Today.ToString & " " & TimeOfDay & ex.Message)
MainForm.UpdateList("RecievecallBack error, attempting reconnect..." & client.RemoteEndPoint.ToString())
client.Shutdown(SocketShutdown.Both)
client.Close()
client.Dispose()
MainForm.isRunning = False
Dim d As DroppedConnectionDelegate = AddressOf MainForm.DroppedConnection
'MainForm.DroppedConnection(0)
d.BeginInvoke(0, Nothing, Nothing)
Exit Try
End Try
End If
' End While
End Sub 'ReceiveCallback
如果我运行该应用程序并且服务器意外断开连接,则当前它不会自动重新连接.但是,如果我单击连接"按钮(仍然会调用计时器),它将运行计时器
If I run the application and the server disconnects unexpectedly, currently it wont reconnect automatically. But it will run the timer if I click the connect button (which calls the timer anyway)
任何人都可以帮忙吗?
预先感谢
推荐答案
我不确定自己从未尝试过100%,但是我认为如果您使用Timers.Timer
而不是Windows.Forms.Timer
,那么您会现在正在工作.默认情况下,Timers.Timer
将在辅助线程上引发其Elapsed
事件,但是您可以为其SynchronizingObject
属性分配表单或其他控件以使其在UI线程上引发事件.在这种情况下,从辅助线程调用Start
应该可以.
I'm not 100% sure as I've never tried but I think that if you use a Timers.Timer
instead of a Windows.Forms.Timer
then what you're doing now will work. By default, a Timers.Timer
will raise its Elapsed
event on a secondary thread but you can assign a form or other control to its SynchronizingObject
property to make it raise events on the UI thread. Calling Start
from a secondary thread should be OK in that case.
如果这不起作用,那么您可以通过在启动Timer
之前首先编组对UI线程的方法调用来进行所需的操作.可能看起来像这样:
If that doesn't work then you can do what you want by first marshalling a method call to the UI thread before starting the Timer
. That might look like this:
Private Sub StartTimer()
If Me.InvokeRequired Then
Me.Invoke(New Action(AddressOf StartTimer))
Else
Me.Timer1.Start()
End If
End Sub
您可以在任何线程上调用该方法,它将起作用.
You can call that method on any thread and it will just work.
请注意,设置Enabled
属性并调用Start
或Stop
是多余的. Start
已将Enabled
设置为True
,并且Stop
将其设置为False
.做一个或另一个,不要两个都做.当您知道要启动或停止Timer
的事实时,最合适的方法是调用方法.如果您的Boolean
值可能是True
或False
,则应使用该属性.使用文字值设置属性本身并不是错误的,但这不是预期的.当您使用相同的方法从辅助线程启动和停止Timer
时,使用该属性的位置的一个示例:
Note that setting the Enabled
property and calling Start
or Stop
is redundant. Start
already sets Enabled
to True
and Stop
sets it to False
. Do one or the other, not both. It is most appropriate to call a method when you know for a fact that you want to either start or stop the Timer
. If you have a Boolean
value that might be either True
or False
then you should use the property. Setting the property using a literal value is not wrong per se but it is not what was intended. An example of where it's appropriate to use the property is when you use the same method to both start and stop the Timer
from a secondary thread:
Private Sub EnableTimer(enable As Boolean)
If Me.InvokeRequired Then
Me.Invoke(New Action(Of Boolean)(AddressOf EnableTimer), enable)
Else
Me.Timer1.Enabled = enable
End If
End Sub
同样,在任何线程上调用该方法都将起作用.
Again, calling that method on any thread will just work.
这篇关于如何从VB中的另一个线程在主线程上调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!