线程调用不一致地激发
本文关键字:不一致 调用 线程 | 更新日期: 2023-09-27 17:58:03
我是高级编程语言的初学者。我正在尝试为串行端口制作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.IsInvokeRequired和Control。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线程创建的,因此检查一下就足够了。InvokeRequired。
Invoke在调用完成后返回,因此在所有项更新后返回。返回Invoke后,您可以使用UpdateMyButton的结果。
如果你不想让你的非ui线程等待UpdateMyButton的完成,可以考虑使用Control.BeginVoke:"嘿,ui线程,只要你有时间,你能为我更新MyButton吗?当然,在这种情况下,你不能使用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");
}
}