精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
锐英源精品开源心得,转载请注明:“锐英源www.wisestudy.cn,孙老师作品,电话13803810136。”需要全文内容也请联系孙老师。
As RS-232 is still used often in industrial applications, Microsoft has added the SerialPort class to its .NET 2.0 framework. 由于RS-232仍然经常使用在工业应用中,微软向.NET 2.0框架增加了SerialPort类。
When communicating with a Windows Forms application and displaying the received data, for instance in a TextBox, the problem occurs, that the serial port and the textbox are using different threads. MSDN describes a way to solve this problem. 当和一个Windows窗体应用程序通信,并显示接收到的数据,例如在文本框,有问题会出现,即,串行端口和文本框使用不同的线程。MSDN描述了一个方式来解决这个问题。
As an example of how to apply all this, using Visual C#, a small application has been built: 运用这一技术的例子示范,已建成一个小型应用程序:
First of all, you have to place, from the Toolbox=>Components, a SerialPort onto the Form. 首先,你必须从“工具箱”=>“组件”拖一个 SerialPort到窗体上。
Then, in the Properties, set the serial port to 9600,8N1 and the port name to X (don't be alarmed; after the application has started, you will get the opportunity to choose a proper COM-name!) 然后,在“属性”窗口里,设置串口参数为9600,8 N1和端口名称为X(不要惊慌,在应用程序启动后,你将有机会选择正确的COM名!)
Now, place the top-textbox (txtIn), showing received data, and the lower textbox (txtOut), showing the data to be send after clicking the Send button. Optionally, you could also place a StatusStrip (as I did). 现在,放置页最上方文本框(txtIn),用它表示接收到的数据,和页下方文本框(txtOut),用它表示发出的数据,点击“发送”按钮就会发送。可选的步骤有,您也可以增加 StatusStrip(像我一样)。
Add a ComboBox (cmbComSelect) with DropDownStyle set to and Sorted set to true. 添加一个ComboBox(cmbComSelect),DropDownStyle设置为DropDown, Sorted设置为true。
The System.IO.Ports namespace contains classes for controlling serial ports. The most important class is the SerialPort class.System.IO.Ports命名空间中包含的类用于控制串行端口。最重要的类是 SerialPort类。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO.Ports; namespace RS232 { public partial class fclsRS232Tester : Form { string InputData = String.Empty; // This delegate enables asynchronous calls for setting // the text property on a TextBox control:// 此委托实现异步调用 此调用可设置 一个TextBox控件的text属性 delegate void SetTextCallback(string text); public fclsRS232Tester() { InitializeComponent(); // Nice methods to browse all available ports:浏览所有可用的端口的最佳方法 string[] ports = SerialPort.GetPortNames(); // Add all port names to the combo box:/ / 添加所有的端口名称的组合框 foreach (string port in ports) { cmbComSelect.Items.Add(port); } } private void cmbComSelect_SelectionChangeCommitted(object sender, EventArgs e) { if (port.IsOpen) port.Close(); port.PortName = cmbComSelect.SelectedItem.ToString(); stsStatus.Text = port.PortName + ": 9600,8N1"; // try to open the selected port:/ / 尝试打开选定的端口: try { port.Open(); } // give a message, if the port is not available:/ /如果该端口是不可用的,发出信息: catch { MessageBox.Show("Serial port " + port.PortName + " cannot be opened!", "RS232 tester", MessageBoxButtons.OK, MessageBoxIcon.Warning); cmbComSelect.SelectedText = ""; stsStatus.Text = "Select serial port!"; } } private void btnSend_Click(object sender, EventArgs e) { if (port.IsOpen) port.WriteLine(txtOut.Text); else MessageBox.Show("Serial port is closed!", "RS232 tester", MessageBoxButtons.OK, MessageBoxIcon.Error); txtOut.Clear(); } private void btnClear_Click(object sender, EventArgs e) { txtIn.Clear(); } private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e) { InputData = port.ReadExisting(); if (InputData != String.Empty) { //txtIn.Text = InputData; // because of different threads this // does not work properly !!,因为不同的线程 // 不正常工作! SetText(InputData); } } /* To make a thread-safe call a Windows Forms control:
为了实现对Windows窗体控件的线程安全调用:
1. Query the control's InvokeRequired property.查询控件的InvokeRequired属性。
2. If InvokeRequired returns true, call Invoke with a delegate that makes the actual call to the control. 如果InvokeRequired返回真,提供委托来调用Invoke,让委托完成对控件的实际调用。
3. If InvokeRequired returns false, call the control directly.如果InvokeRequired返回假,直接调用该控件。 In the following code example, this logic is implemented in a utility method called SetText. A delegate type named SetTextDelegate encapsulates the SetText method. When the TextBox control's InvokeRequired returns true, the SetText method creates an instance of SetTextDelegate and calls the form's Invoke method. This causes the SetText method to be called on the thread that created the TextBox control, and in this thread context the Text property is set directly
在下面的代码示例中,这个逻辑是由一个工具方法setText来实施。
命名为SetTextDelegate的委托类型封装SetText方法。
当TextBox控件的InvokeRequired 返回true,SetText方法创建一个SetTextDelegate的委托实例和调用窗体的Invoke方法。这将导致SetText方法在创建TextBox控件的线程上调用
,在此线程上下文中Text属性被直接设置
还可以参考:http://msdn2.microsoft.com/en-us/library/ms171728(VS.80).aspx
*/ // This method demonstrates a pattern for making thread-safe // calls on a Windows Forms control. 此方法说明了对Windows窗体控件线程安全调用中的一个模式 // // If the calling thread is different from the thread that // created the TextBox control, this method creates a // SetTextCallback and calls itself asynchronously using the // Invoke method.如果调用线程和创建TextBox控件的线程不是一个线程 / /此方法创建一个SetTextCallback委托实例且使用Invoke方法异步调用自己 // If the calling thread is the same as the thread that created // the TextBox control, the Text property is set directly. 如果调用线程和创建TextBox控件的线程是一个,则 //直接设置Text属性 private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true.InvokeRequired需要比较调用线程的线程ID和创建线程ID / / / / 如果这些线程是不同的,则返回true。 if (this.txtIn.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else this.txtIn.Text += text; } } }