如何在C#中举办活动 - 最佳方法

时间:2010-06-22 04:17:39

标签: c# event-handling

我正在编写Windows窗体应用程序。它有一个执行某些操作的线程,当操作发现它必须通知主窗体更改控件时。

目前,通知使用以下MSDN页面中描述的C#事件hadling: http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx

但我不确定该代表。因为在我上面描述的情况下,线程调用委托。这是一种提高事件的线程安全方法吗?

在C#中实现Windows消息(SendMessage)然后在WindowProc中实现消息处理程序是否更好。

感谢你的时间。

3 个答案:

答案 0 :(得分:4)

除非您需要对线程进行非常精细的控制,否则您可以使用BackgroundWorker代替。它为您处理所有的跨线程通信。您基本上将后台代码放在其DoWork事件处理程序中,然后通过其ProgressChanged和RunWorkerCompleted事件将数据传递回UI线程。上面的链接有一个如何使用它的完整示例。

但总的来说,只要您遵循一些基本准则,只需添加事件处理程序和引发事件就是线程安全的。但是,事件处理程序将在与引发事件的代码相同的线程上调用。可能不希望在后台线程上调用事件处理代码,因此BackgroundWorker就派上用场了。

以下是类的一个非常基本的框架,它以线程安全的方式引发事件。处理事件的代码是否是线程安全的完全是另一回事。

class MyClass {

    public event EventHandler SomethingHappened;

    protected virtual void OnSomethingHappened(EventArgs e) {
        EventHandler handler = SomethingHappened;
        if (handler != null) {
            handler(this, e);
        }
    }

    public void DoSomething() {
        OnSomethingHappened(EventArgs.Empty);
    }

}

答案 1 :(得分:0)

尝试在UI控件上使用InvokeRequired / Invoke。最好避免原始Windows消息队列。

答案 2 :(得分:0)

委托方法并不是那么糟糕,但问题是该事件调用另一个线程中的事件处理程序。这有助于你的UI更新,这需要在主线程中完成。因此,您可以在事件处理程序中适当地使用InvokeRequired。

void OnStatusMessage(string s)
{
  // might be coming from a different thread
  if (txtStatus.InvokeRequired)
  {
    this.BeginInvoke(new MethodInvoker(delegate()
    {
      OnStatusMessage(s);
    }));
  }
  else
  {
    StatusBox.Text += s + "\r\n";
    StatusBox.SelectionStart = txtStatus.TextLength;
    StatusBox.ScrollToCaret();
  }
}

当使用Josh提到的BackgroundWorker时,可能不需要这样做。但是如果你考虑ThreadPool和WaitCallBack(*)来管理线程,它会很有用。

使用Windows消息的一个问题是您必须知道向哪个窗口发送消息,并且多个订阅者更痛苦。 (对于你只需要+ =另一个处理程序的事件)

  • 我无法发布WaitCallBack的超链接,因为我还没有多链接谱系。