【问题标题】:How do I call a function on the main thread from another thread in vb如何从vb中的另一个线程调用主线程上的函数
【发布时间】:2016-04-13 17:41:09
【问题描述】:

我有一个计时器功能,它在我的 Windows 窗体上调用,当单击 UI 上的按钮时它可以完美运行。但是,在我的应用程序中,我使用 TCP 套接字连接到服务器,当服务器断开连接时,我捕获了抛出的异常,并且我希望此时计时器启动(ticker)然后运行重新连接。 当我从 try catch 中引用计时器时,它不会运行,所以我想它是因为它在主线程上?

这是我的计时器代码: 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

这是我想在捕获异常时调用计时器的子:

 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

如果我运行应用程序并且服务器意外断开连接,目前它不会自动重新连接。但是如果我单击连接按钮(无论如何都会调用计时器),它将运行计时器

有人可以帮忙吗?

提前致谢

【问题讨论】:

  • 您使用的 Timer 类不是线程安全的,在工作线程上调用它的 Start() 方法并不能达到您希望的效果。它永远不会滴答作响。在这段代码中使用 MainForm 也是不正确的,你将永远看不到任何东西。

标签: vb.net multithreading timer


【解决方案1】:

我不能 100% 确定,因为我从未尝试过,但我认为如果您使用 Timers.Timer 而不是 Windows.Forms.Timer,那么您现在正在做的事情将会奏效。默认情况下,Timers.Timer 将在辅助线程上引发其Elapsed 事件,但您可以将表单或其他控件分配给其SynchronizingObject 属性以使其在 UI 线程上引发事件。在这种情况下,从辅助线程调用 Start 应该没问题。

如果这不起作用,那么您可以通过在启动 Timer 之前首先将方法调用编组到 UI 线程来执行您想要的操作。可能看起来像这样:

Private Sub StartTimer()
    If Me.InvokeRequired Then
        Me.Invoke(New Action(AddressOf StartTimer))
    Else
        Me.Timer1.Start()
    End If
End Sub

您可以在任何线程上调用该方法,它会正常工作。

请注意,设置Enabled 属性并调用StartStop 是多余的。 Start 已经将 Enabled 设置为 True 并且 Stop 将其设置为 False。做一个或另一个,而不是两个。当您知道要启动或停止Timer 的事实时,最适合调用方法。如果您的Boolean 值可能是TrueFalse,那么您应该使用该属性。使用文字值设置属性本身并没有错,但这不是预期的。适合使用该属性的一个示例是,当您使用相同的方法从辅助线程启动和停止 Timer 时:

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

同样,在任何线程上调用该方法都可以正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-10
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多