我正在编写Windows窗体应用程序。它有一个执行某些操作的线程,当操作发现它必须通知主窗体更改控件时。
目前,通知使用以下MSDN页面中描述的C#事件hadling: http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx
但我不确定该代表。因为在我上面描述的情况下,线程调用委托。这是一种提高事件的线程安全方法吗?
在C#中实现Windows消息(SendMessage)然后在WindowProc中实现消息处理程序是否更好。
感谢你的时间。
答案 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消息的一个问题是您必须知道向哪个窗口发送消息,并且多个订阅者更痛苦。 (对于你只需要+ =另一个处理程序的事件)