2012-02-29 46 views
3

我正在编写一个应用程序,通过GPIB命令与多个设备进行通信,并在某些设备上运行测试。我建立了一个类TestProcedure,它将启动一个新线程并运行测试。在整个测试过程中,我已经设置了几个自定义事件来将信息发送回GUI。下面是一个简单事件的例子:C#:事件和线程安全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方法,所以我正在寻找替代解决方案来异步访问它。

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

回答

3

UI线程上的控件只能从UI线程访问 - 任何来自其他线程的访问都必然会引发问题。如果事件不在那里,则需要使用InvokeRequiredBeginInvoke()将事件整理到正确的线程。

Example

+0

我应该添加一个调用到事件本身?这个工作是否与说文字框一样? 编辑:对不起,刚才看到你的例子我会看看 – Corey 2012-02-29 18:05:52

+0

你会首先在你的事件处理函数中检查“InvokeRequired”,如果它返回“true”,你需要使用'的BeginInvoke()'。如果返回值为'false',那么您已经在UI线程中,因此您可以直接安全地访问控件(例如,'txtName.Text = ...;'是有效的,如果您在错误的线程中,可能会失败。) – xxbbcc 2012-02-29 18:07:53

+1

我修正了引用'BeginInvoke()'的答案,因为你可能需要这个,而不是'Control.Invoke()'。 – xxbbcc 2012-02-29 18:11:38

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); 
    } 
} 
+0

什么是“日志”?它应该是'this.InvokeRequired'。 – 2012-02-29 18:14:39

+0

对不起,修正了片段。 – Walk 2012-02-29 18:16:55