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());
}
);
}
}
如果我尝试在我的主 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());
}
);
}
}