如何使用收到的串行端口字符串更新C#windows窗体文本框?

如何使用收到的串行端口字符串更新C#windows窗体文本框?,c#,multithreading,winforms,textbox,serial-port,C#,Multithreading,Winforms,Textbox,Serial Port,我有一个类似于主题“在文本框中显示串行-跨线程操作”的问题,但我不理解给出的答案 根据我找到的一个教程视频示例,我创建了一个非常简单的C#表单来发送/接收串行数据。很好,但是这个示例要求您单击一个按钮来接收数据,而我希望它现在通过更新“received”文本框来自动显示接收到的任何内容 Program.cs由VSE2015生成: using System; using System.Collections.Generic; using System.Linq; using System.Thr

我有一个类似于主题“在文本框中显示串行-跨线程操作”的问题,但我不理解给出的答案

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

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());
    }
  }
}
注释掉的代码是我尝试自动显示接收到的数据文本框(取消注释此代码并注释掉“button\u receive\u Click”函数中的“try”语句。)

但这样做会产生交叉线程错误:

引发异常:中的“System.InvalidOperationException” System.Windows.Forms.dll类型的未处理异常 中发生“System.InvalidOperationException” System.Windows.Forms.dll其他信息:跨线程 操作无效:从线程访问控件“textBox_received” 而不是创建它的线程

我读过一些关于使用Invoke或BeginInvoke的文章,但是答案中没有足够的上下文让我(一个非程序员)去弄清楚如何实现,而且答案通常都在地图上,没有一致的意见,哪一个是正确的/最好的。有人可以提供一个简单的解决方案,我需要添加到我的代码,使这项工作? 谢谢。

接收数据的专用无效端口(对象发送方,SerialDataReceivedEventArgs e){
SerialPort sp=(SerialPort)发送方;
UpdateTextBox(sp.ReadExisting());
}
公共void UpdateTextBox(字符串值){
如果(需要调用)
{
Invoke(新操作(UpdateTextBox),新对象[]{value});
返回;
}
textBox_received.Text+=值;
}

为了理解这个问题,UI表单有自己的线程,UI特定的线程,为了使事情安全和简单,UI中的所有内容都在其线程的消息循环中处理。来自串行端口或其他通信通道的事件等事件通常安排在线程池或UI线程外的特定线程上。您需要的是跨越其他线程和UI线程之间的边界。在windows窗体上有窗体实例、Invoke和BeginInvoke的方法,它们将安排一些工作到UI消息循环,UI线程将在自己的时间内执行它。Invoke会同步地等待执行完成,而BeginInvoke不会,除非您使用返回值。以我的回答作为多线程同步、通信和交互的广阔世界的介绍。祝你好运。

ipavlu,我感谢你的解释。lhdina共享的代码解决了我的问题。我没有在这个UI中进行任何其他处理,因此我认为Invoke方法对我来说已经足够了。
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();
    //}

  }
}
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;
}