C#:活动&线程安全GUI更新

时间:2012-02-29 18:00:43

标签: c# .net .net-3.5 event-handling

我正在编写一个应用程序,通过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方法,所以我正在寻找替代解决方案来异步访问它。

所以我的问题是,事件处理程序是否可以安全地访问表单上的控件?如果没有,事件处理程序如何触发,并且有人可以帮助教育我,或提供一些链接信息,以了解事件处理程序如何与表单控件进行通信?我需要锁定活动吗?

2 个答案:

答案 0 :(得分:2)

UI线程上的控件只能从UI线程访问 - 来自其他线程的任何访问都必然会导致问题。您需要使用InvokeRequiredBeginInvoke()将事件编组到正确的线程(如果它尚未存在)。

Example

答案 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);
    }
}