2017-07-24 72 views
0

我有一个类似于“显示串行进入文本框 - 跨线程操作”的问题,但我不明白给出的答案。如何更新C#窗口与接收到的串口串口文本框?

基于我找到的教程视频示例,我创建了一个非常简单的C#表单来发送/接收串行数据。效果很好,但该示例要求您单击一个按钮来接收数据,而我现在希望通过更新“已收到”文本框自动显示接收到的数据。

image of Form1

Program.cs是VSE2015产生:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace spcontrol 
{ 
    static class Program 
    { 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(new Form1()); 
    } 
    } 
} 

Form1.cs中示出基于教程示例工作码(即, “接收” 按钮必须被点击):

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.IO.Ports; 

namespace spcontrol 
{ 
    public partial class Form1 : Form 
    { 

    public Form1() 
    { 
     InitializeComponent(); 
     GetAvailablePorts(); 
     //serialPort1.DataReceived += new SerialDataReceivedEventHandler(port_OnReceiveData); 
    } 

    void GetAvailablePorts() 
    { 
     string[] ports = SerialPort.GetPortNames(); 
     comboBox_portnames.Items.AddRange(ports); 
    } 

    private void button_openport_Click(object sender, EventArgs e) 
    { 
     try 
     { 
     if (comboBox_portnames.Text == "" || comboBox_baudrate.Text == "") 
     { 
      textBox_received.Text = "Please select port settings."; 
     } 
     else 
     { 
      textBox_received.Text = ""; 
      serialPort1.PortName = comboBox_portnames.Text; 
      serialPort1.BaudRate = Convert.ToInt32(comboBox_baudrate.Text); 
      serialPort1.Open(); 
      button_send.Enabled = true; 
      button_receive.Enabled = true; 
      textBox_sent.Enabled = true; 
      button_openport.Enabled = false; 
      button_closeport.Enabled = true; 
      comboBox_portnames.Enabled = false; 
      comboBox_baudrate.Enabled = false; 
      serialPort1.DataBits = 8; 
      serialPort1.Parity = Parity.None; 
      serialPort1.StopBits = StopBits.One; 
      serialPort1.Handshake = Handshake.None; 
      label_config.Text = serialPort1.PortName + " " + serialPort1.BaudRate + " 8N1 None"; 
      progressBar_status.Value = progressBar_status.Maximum; 
     } 
     } 
     catch (UnauthorizedAccessException) 
     { 
     textBox_received.Text = "Unauthorized access."; 
     } 
    } 

    private void button_closeport_Click(object sender, EventArgs e) 
    { 
     serialPort1.Close(); 
     button_send.Enabled = false; 
     button_receive.Enabled = false; 
     textBox_sent.Enabled = false; 
     button_openport.Enabled = true; 
     button_closeport.Enabled = false; 
     comboBox_portnames.Enabled = true; 
     comboBox_baudrate.Enabled = true; 
     progressBar_status.Value = progressBar_status.Minimum; 
    } 

    private void button_send_Click(object sender, EventArgs e) 
    { 
     serialPort1.WriteLine(textBox_sent.Text); 
     textBox_sent.Text = ""; 
     textBox_sent.Focus(); 
    } 

    private void button_receive_Click(object sender, EventArgs e) 
    { 
     try 
     { 
     textBox_received.Text = serialPort1.ReadLine(); 
     } 
     catch (TimeoutException) 
     { 
     textBox_received.Text = "Timeout exception."; 
     } 
    } 

    //private void port_OnReceiveData(object sender, SerialDataReceivedEventArgs e) 
    //{ 
    // SerialPort sp = (SerialPort)sender; 
    // textBox_received.Text += sp.ReadExisting(); 
    //} 

    } 
} 

注释掉的代码是我尝试自动处理接收到的数据文本框显示(取消注释此代码并注释掉“button_rec”中的“try”语句。eive_Click”功能)

但这样做给我的跨线程错误:

Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll Additional information: Cross-thread operation not valid: Control 'textBox_received' accessed from a thread other than the thread it was created on.

我读过有关使用调用或BeginInvoke的东西,但从未有足够的上下文中的答案对我来说(非 - 程序员)弄清楚如何实现,再加上通常答案遍布整个地图,并且没有共识哪个是正确的/最好的。有人可以提供一个简单的解决方案,我需要添加到我的代码,使其工作? 谢谢。

回答

0
private void port_OnReceiveData(object sender, SerialDataReceivedEventArgs e) { 
    SerialPort sp = (SerialPort)sender; 
    UpdateTextBox (sp.ReadExisting()); 
} 

public void UpdateTextBox(string value) { 
    if (InvokeRequired) 
    { 
     this.Invoke(new Action<string>(UpdateTextBox), new object[] {value}); 
     return; 
    } 
    textBox_received.Text += value; 
} 
0

要理解这个问题,UI形式有自己的线程,UI线程特定使事情安全和方便,在UI一切都在它的线程的消息循环处理。通常在线程池或UI线程之外的特定线程上调度来自串行端口或其他通信通道的事件。你需要跨越其他线程和UI线程之间的边界。在Windows窗体上有Form实例,Invoke和BeginInvoke方法,他们将安排一些工作到UI消息循环,UI线程会在自己的时间执行它。 Invoke同步等待直到执行完成,BeginInvoke不会,除非您使用返回值玩。以我的回答作为介绍大型和广泛的多线程同步,通信,交互的世界。祝你好运。

+0

ipavlu,我很欣赏这个解释。而且由lhdina分享的代码解决了我的问题。我没有在这个UI中做任何其他处理,所以我想Invoke方法对我来说已经足够了。 – jpc2112