C# - 带有Forms的Eventhandler交叉引用

时间:2015-01-23 15:11:29

标签: c# forms events

如果我尝试在主WindowsForm中执行此代码,则会出现以下异常:

System.Windows.Forms.dll中发生未处理的“System.InvalidOperationException”类型异常 附加信息:跨线程操作无效:控制'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();

    }

2 个答案:

答案 0 :(得分:3)

中收到数据时
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()); 
               }
            );
        }
}

答案 1 :(得分:1)

确保您仅使用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;
   }
}

您也可以使用匿名委托,但上面的内容可能更容易理解。