繁体   English   中英

线程调用不一致

[英]thread call fires inconsistently

我是高级编程语言的初学者。 我正在尝试为串口创建一个WForms应用程序,即时通讯使用VS 2010 C#

我收到以下错误:

Cross-thread operation not valid: Control 'rtxtDataArea' accessed from a thread other than the thread it was created on.

这发生在这里:

private void ComPort_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
    {
         recievedData = ComPort.ReadExisting(); //read all available data in the receiving buffer.

        // Show in the terminal window 
        rtxtDataArea.ForeColor = Color.Green;    // error , 
        rtxtDataArea.AppendText(recievedData + "\n");
    }

当我收到一些数据时,我试图改变文本框的颜色。 它会触发交叉线程错误。

问题是,当我尝试更改标签的颜色时,为什么它不会在此处触发相同的错误?

private void btnConnect_Click(object sender, EventArgs e)
    {
        if (ComPort.IsOpen)
        {
            disconnect();
        }
        else
        {
            connect();
            rdText.ForeColor = Color.Blue;//ok, it works
        }
    }

; 这工作; 第一个没有。

为什么? ComPort_DataReceived_1与btnConnect_Click的性质不同吗? 或者是什么原因?

我已经阅读了很多关于线程的内容,但我理解我无法使用,有人可以给出一个直观的解释吗?

在winforms中,只有一个线程可以改变UI上的任何内容,如启用按钮,更改文本框等。通常这是UI线程。 这通常是你唯一的主题。

但是,如果您启动一个新线程,该线程可能希望更改UI。 如果此新线程触发表单收到的事件,则会发生这种情况。

每当您看到从其创建的线程以外的线程访问的消息 ,您几乎可以肯定是这种情况。

解决此问题的最简单方法是使用Control.IsInvokeRequiredControl.Invoke函数。 这样做的模式如下。 以下函数更新myForm上的myButton

private void UpdateMyButton (MyType myParameter)
{
    if (myButton.InvokeRequired)
    {   // this is not the thread that created the button to update
        this.Invoke(new MethodInvoker( () => this.UpdateMyButton(myParameter)));
        // this will let the UI thread call this function with the same parameter.
    }
    else
    {   // Now called by the UI thread: this thread may change myButton
        myButton.Enabled = myParameter.ShouldButtonEnable;
        myButton.Text = myParameter.ButtonText;
    }
}

顺便说一句,如果你必须更新表单上的几个控件,你应该为每个控件检查InvokeRequired。 但是,由于它们通常由相同的UI线程创建,因此检查this.InvokeRequired就足够了。

Control.Invoke在调用完成后返回,因此在更新所有项目之后。 返回Invoke后,您可以使用UpdateMyButton的结果。

如果你不希望你的非ui线程等待UpdateMyButton的完成,请考虑使用Control.BeginInvoke:“嘿UI线程,只要你有时间,你可以为我更新UpdateMutton。当然在那种情况下你无法使用UpdateMyButton的结果

因为“DataReceived”在另一个线程而不是UI线程上运行。 您必须使用Invoke:

private void ComPort_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
  recievedData = ComPort.ReadExisting(); //read all available data in the receiving buffer.

  if (InvokeRequired)
  {
    // If not on UI thread, then invoke
    Invoke(new MethodInvoker(() =>
    {
      // Show in the terminal window 
      rtxtDataArea.ForeColor = Color.Green; // error , 
      rtxtDataArea.AppendText(recievedData + "\n");
    }));
  }
  else
  {
    // On UI thread, invoke not needed
    // Show in the terminal window 
    rtxtDataArea.ForeColor = Color.Green; // error , 
    rtxtDataArea.AppendText(recievedData + "\n");
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM