2013-02-21 117 views
1

我非常確定只是我這樣做是錯誤的。從SerialDataReceivedEventHandler寫入文本框控件

我有Form1有一個按鈕,onclick調用我的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(我想我必須是?)我不能訪問任何東西? 那麼最好的方法是如何處理呢?

回答

1

您需要將表格實例傳遞給該連接方法(從按鈕的事件處理程序):

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) { 

那麼你可以使用lambda函數和關閉它裏面的「whichForm」引用就像這樣:

但是,此外,你應該確保你實際上並沒有修改從另一個線程以外的其他線程的GUI - 這是h由於SerialPort類的性質很可能,這可能很好地從另一個後臺線程引發事件 - 因此this.Invoke(某些其他lambda)將這個特定的動作組織起來,然後在主線程上執行該特定的動作。

MSDN明確規定:當從所述的SerialPort對象接收到的數據http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx

的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; 
    } 
} 
+0

不確定你的意思。我在connect()方法中看到了這個想法。 但不明白:'Action toBeRunOnGuiThread =()=> this.theTextBox.Text = data; (發送者,e){'('=>'預期) – 2013-02-21 23:39:11

+0

我很抱歉我之前犯的錯誤。再看看代碼..我錯誤地認爲連接方法是Form1類的一部分,它是一個實例方法。然後我意識到它不是該類的一部分,它屬於serialConn,它是靜態的。嘗試從按鈕的單擊事件處理程序中將Form實例(this)發送到您的connect方法。 – 2013-02-21 23:45:15

+0

我重新編輯了整篇文章。通過行動toBeRunOnGuiThread我的意思是,實際觸摸的形式,因此它的TextBox不是你的問題的結束。您還需要以非常安全的方式執行Text屬性的更改。 SerialPort類在後臺線程上運行命令。這樣用戶界面將永遠不會凍結。用戶界面線程需要保持長時間工作狀態,以便處理鼠標點擊,而不是。但所有這一切都伴隨着一個價格。你不能修改後臺線程的用戶界面對象。你需要以某種方式發送消息 – 2013-02-21 23:45:48