C# - 事件处理程序与表单的交叉引用

C# - Eventhandler cross reference with Forms

如果我尝试在我的主 WindowsForm 中执行此代码,我会遇到以下异常:

'System.InvalidOperationException' 类型的未处理异常发生在 System.Windows.Forms.dll 附加信息:跨线程操作无效:控件 'richTextBox1' 从创建它的线程以外的线程访问。

我发现了很多关于事件、事件处理程序和线程的信息。然而,我从来没有真正深入研究过事件以及如何手动创建它们或多线程。 我在 MSDN

上找到了这篇文章

--> Link <-- 但我并没有真正理解它。如果尝试将我的输出写入 richtextbox1,则会出现错误。

SerialPort Arduino = new SerialPort();
    public Form1()
    {
        InitializeComponent();
        this.Load += Form1_Load;

    }

    void Form1_Load(object sender, EventArgs e)
    {
      string[] k = SerialPort.GetPortNames();
      cBPortWaehlen.DataSource = k;

    } 
    private void btnOpenPort_Click(object sender, EventArgs e)

    {
        if (!Arduino.IsOpen)
        {
            Arduino.DataReceived += Arduino_DataReceived;
            Arduino.BaudRate = 115200;
            Arduino.PortName = cBPortWaehlen.SelectedItem.ToString();
            Arduino.Open();
        }
        else
        {
            MessageBox.Show("Port schon offen");
        }

    }

    private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
            this.richTextBox1.AppendText(Arduino.ReadExisting());

    }

    private void btnClosePort_Click(object sender, EventArgs e)
    {
        Arduino.Close();

    }

确保您仅使用 UI 线程更新表单。每次设置访问 UI 组件的 属性 时(例如 this.richTextBox1.AppendText),请注意将其委托给 UI 线程以避免交叉-线程异常。

你可以这样做:

delegate void UpdateDelegate(string text);

private void UpdateInformation(string text)
{
   if(this.InvokeRequired)
   {
      UpdateDelegate ud = new UpdateDelegate(UpdateInformation);
      this.BeginInvoke(ud, new object[] { text } );
   }
   else 
   {
      this.myTextBox.Text = text;
   }
}

你也可以使用匿名委托,但是上面的东西可能更容易理解。

当您在

中收到数据时
private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
        this.richTextBox1.AppendText(Arduino.ReadExisting());

}

该事件源自另一个正在监视您的 Arduino 的线程。

默认情况下,您的 winforms 应用程序至少有一个线程(UI 线程)。 如果您在该线程上执行代码,它将停止 UI,使其无响应。

因此,如果您希望在 UI 保持响应的同时在后台发生某些事情,则必须在单独的线程中完成。

不幸的是(但出于几个实际原因),线程不能使用彼此的引用。

但是他们可以互相发送消息。

其中之一是调用特定操作的请求。 Windows Forms 内置了几个方便的方法来使用它:

private void Arduino_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
        if(richTextBox1.InvokeRequired)
        {
            richTextBox1.Invoke(
               (Action)delegate 
               { 
                 richTextBox1.AppendText(Arduino.ReadExisting()); 
               }
            );
        }
}