2016-04-13 7 views
0

UIのボタンをクリックすると完全に機能する私のWindowsフォームで呼び出されるタイマー関数があります。しかし、私のアプリケーションでは、TCPソケットを使用してサーバーに接続しているときに、サーバーが切断されたときに、例外がスローされ、この時点でタイマーが開始され(ティッカー)、再接続が実行されます。 私はtry catchからタイマーを参照すると、実行されることはありません。そのため、メインスレッド上にあるので想像してください。ここでメインスレッドの関数をvbの別のスレッドから呼び出す方法

はタイマーのための私のコードです:ここでは パブリックデリゲートサブDroppedConnectionDelegate(ByValのReConn整数として)

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 

は、IDキャッチ例外にタイマーを呼びたい場所からサブです:

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 

アプリケーションを実行するとサーバーが予期せず接続が切断されると、現在自動的に再接続されません。しかし、私は接続ボタン(とにかくタイマーを呼び出す)をクリックすると、タイマーを実行します

誰でも助けてくださいできますか?事前

+0

使用しているTimerクラスはスレッドセーフではありません。ワーカースレッド上でStart()メソッドを呼び出すことは、あなたが望むことをしません。それは決して目立たないでしょう。このコードでMainFormを使用することも間違っています。何も見えません。 –

答えて

1

おかげで私は私が試したことがないよう、100%確実ではないが、私はあなたの代わりにWindows.Forms.TimerTimers.Timerを使用する場合は、あなたが今やっている仕事になると思います。デフォルトでは、Timers.TimerはセカンダリスレッドでElapsedイベントを発生させますが、フォームまたはその他のコントロールをSynchronizingObjectプロパティに割り当てて、UIスレッドでイベントを発生させることができます。その場合、セカンダリスレッドからStartを呼び出すことはOKです。

これが機能しない場合は、最初にTimerを開始する前に、UIスレッドへのメソッド呼び出しをマーシャリングして、必要な操作を行うことができます。これは次のようになります。

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

このメソッドはどのスレッドでも呼び出すことができ、うまく動作します。

Enabledプロパティを設定し、StartまたはStopを呼び出すことは冗長であることに注意してください。 StartはすでにEnabledTrueStopFalseに設定されています。どちらか一方を実行し、両方を実行しない。 Timerを開始または停止したいという事実を知っているときは、メソッドを呼び出すことが最も適切です。 Booleanの値がTrueまたはFalseの場合は、このプロパティを使用する必要があります。リテラル値を使用してプロパティを設定することは、それ自体が間違っているわけではありませんが、意図されたものではありません。うまく動作するすべてのスレッドでそのメソッドを呼び出して、再び

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 

を:あなたは、両方の開始に同じ方法を使用して、セカンダリスレッドからTimerを停止すると、それはプロパティを使用することが適切だ場所の例があります。

関連する問題