从SerialDataReceivedEventHandler写入文本框控件
问题描述:
我非常确定只是我这样做是错误的。从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
(我想我必须是?)我不能访问任何东西? 那么最好的方法是如何处理呢?
答
您需要将表格实例传递给该连接方法(从按钮的事件处理程序):
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;
}
}
不确定你的意思。我在connect()方法中看到了这个想法。 但不明白:'Action toBeRunOnGuiThread =()=> this.theTextBox.Text = data; (发送者,e){'('=>'预期) – 2013-02-21 23:39:11
我很抱歉我之前犯的错误。再看看代码..我错误地认为连接方法是Form1类的一部分,它是一个实例方法。然后我意识到它不是该类的一部分,它属于serialConn,它是静态的。尝试从按钮的单击事件处理程序中将Form实例(this)发送到您的connect方法。 – 2013-02-21 23:45:15
我重新编辑了整篇文章。通过行动toBeRunOnGuiThread我的意思是,实际触摸的形式,因此它的TextBox不是你的问题的结束。您还需要以非常安全的方式执行Text属性的更改。 SerialPort类在后台线程上运行命令。这样用户界面将永远不会冻结。用户界面线程需要保持长时间工作状态,以便处理鼠标点击,而不是。但所有这一切都伴随着一个价格。你不能修改后台线程的用户界面对象。你需要以某种方式发送消息 – 2013-02-21 23:45:48