1

これを間違った方法で行っているのは私だけだと確信しています。

onclick が私Form1の serialConn.cs で呼び出されるメソッドを呼び出すボタンがありますconnect()

public static bool connect(string comPort) {
        BTserial = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
        BTserial.Open();
        if (BTserial.IsOpen) {
            BTserial.DataReceived += new SerialDataReceivedEventHandler(DataReceivedEvent);
            return true;
        } else {
            return false;
        }
    }

private static void DataReceivedEvent(object sender, SerialDataReceivedEventArgs e) {
        Debug.WriteLine("Data Incomming!");
        // Check if Chars are received
        if (e.EventType == SerialData.Chars) {
            Debug.WriteLine("Chars!");
            // Create new buffer
            byte[] ReadBuffer = new byte[BTserial.BytesToRead];

            // Read bytes from buffer
            BTserial.Read(ReadBuffer, 0, ReadBuffer.Length);
            BTserial.DiscardInBuffer();

            // Encode to string
            string data = bytesToString(ReadBuffer);

            ReadBuffer = null;
            data = null;
        }
    }

そして、それはすべて良いですが、データが受信されたら、それを私のコントローラーにTextBox印刷したいForm1.. では、これにどのようにアプローチするのが最善の方法でしょうか?DataReceivedEvent()static

4

1 に答える 1

1

Form インスタンスをこの接続メソッドに渡す必要があります (ボタンのイベント ハンドラーから)。

public class Form1 : Form {

  public void Button1_Click(object sender, EventArgs e) {
    serialConn.connect("the com port here", this);
  }

  // ... etc ...

}

serialConn 中:

public static bool connect(string comPort, Form1 whichForm) {

次に、ラムダ関数を使用して、その内部の「whichForm」参照を次のように閉じることができます。

しかしさらに、メインのスレッド以外の別のスレッドから GUI を実際に変更しないようにする必要があります。これは、別のバックグラウンド スレッドからイベントを非常によく発生させる可能性のある SerialPort クラスの性質により、可能性が高くなります。したがって、メインスレッドで実行される特定のアクションをマーシャリングする this.Invoke( some other lambda ) です。

MSDN は明確に述べています: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx

SerialPort オブジェクトからデータを受信すると、セカンダリ スレッドで DataReceived イベントが発生します。このイベントはメイン スレッドではなくセカンダリ スレッドで発生するため、UI 要素など、メイン スレッドの一部の要素を変更しようとすると、スレッド例外が発生する可能性があります。メインのフォームまたはコントロールの要素を変更する必要がある場合は、Invoke を使用して変更要求を返信します。これにより、適切なスレッドで作業が行われます。

public static bool connect(string comPort, Form1 whichForm) {
    BTserial = new SerialPort(comPort, 9600, Parity.None, 8, StopBits.One);
    BTserial.Open();
    if (BTserial.IsOpen) {
        BTserial.DataReceived += (sender, e) => {
          Debug.WriteLine("Data Incomming!");
          // Check if Chars are received
          if (e.EventType == SerialData.Chars) {
              Debug.WriteLine("Chars!");
              // Create new buffer
              byte[] ReadBuffer = new byte[BTserial.BytesToRead];

              // Read bytes from buffer
              BTserial.Read(ReadBuffer, 0, ReadBuffer.Length);
              BTserial.DiscardInBuffer();

              // Encode to string
              string data = bytesToString(ReadBuffer);


              Action toBeRunOnGuiThread = () => whichForm.theTextBox.Text = data;

              // to guard yourself from all evil
              // you could check to see if it is needed to
              if (whichForm.InvokeRequired) 
                // marshal the call to the action all the way to the GUI thread
                whichForm.Invoke(toBeRunOnGuiThread);
              else
                // or, if we ARE on the GUI thread already, just call it from this thread
                toBeRunOnGuiThread();

              ReadBuffer = null;
              data = null;
          }
    };
        return true;
    } else {
        return false;
    }
}
于 2013-02-21T23:31:14.563 に答える