我正在编写一个应用程序,通过GPIB命令与多个设备通信,在某些设备上运行测试。我已经建立了一个类TestProcedure,它将启动一个新线程并运行测试。在整个测试过程中,我已经设置了几个自定义事件来将信息发送回GUI。以下是一个简单事件的示例:
public event InformationEventHandler<string> TestInfoEvent;
/// <summary>
/// Event raised when information should be passed back to the main testing form.
/// </summary>
/// <param name="s">Information to send back to form.</param>
private void OnInfo(string s)
{
if (TestInfoEvent != null)
TestInfoEvent(this, s);
}
将通过GUI处理,更新如下文本框:
TheTestProcedure.TestInfoEvent += new TestProcedure.InformationEventHandler<string>
(InfoOccurred);
....
private void InfoOccurred(Object sender, string s)
{
this.textBox1.Text = s + Environment.NewLine + this.textBox1.Text;
if (this.textBox1.Text.Length > 10000)
this.textBox1.Text = this.textBox1.Text.Remove(1000);
}
此事件处理似乎工作正常。我没有收到任何交叉线程问题,总体而言,它已按预期工作。但是,在另一种形式上,我刚刚添加了一个类似的事件处理程序,它抛出了一个跨线程异常。事件触发,发送一个简单的类,其中包含我在InputTextBox(自定义ComponentOne控件)中显示的一些信息。特定控件没有.Invoke方法,所以我正在寻找替代解决方案来异步访问它。
所以我的问题是,事件处理程序是否可以安全地访问表单上的控件?如果没有,事件处理程序如何触发,并且有人可以帮助教育我,或提供一些链接信息,以了解事件处理程序如何与表单控件进行通信?我需要锁定活动吗?
答案 0 :(得分:2)
UI线程上的控件只能从UI线程访问 - 来自其他线程的任何访问都必然会导致问题。您需要使用InvokeRequired
和BeginInvoke()
将事件编组到正确的线程(如果它尚未存在)。
答案 1 :(得分:1)
您需要创建一个委托回调,并在测试Invoke()
属性后执行InvokeRequired
。以下代码将以线程安全的方式处理添加。
TheTestProcedure.TestInfoEvent += new TestProcedure.InformationEventHandler<string>
(InfoOccurred);
private void InfoOccurred(Object sender, string s)
{
LogMessage(s);
}
delegate void LogMessageCallback(string text);
void LogMessage(String message)
{
if (this.textBox1.InvokeRequired)
this.Invoke(new LogMessageCallback(LogMessage), message);
else
{
this.textBox1.Text = s + Environment.NewLine + this.textBox1.Text;
if (this.textBox1.Text.Length > 10000)
this.textBox1.Text = this.textBox1.Text.Remove(1000);
}
}