.NET 的事件机制
.NET's Event Mechanism
我目前看到的所有关于C#/.NET的书,在谈到事件的时候,
他们谈论创造和消费事件。
我很想了解它在我们的代码背后是如何工作的——运行它的机制是什么。
我从 Windows 消息循环对所引发事件的行为类似于队列这一事实中略知一二。
例如,WM_KEYDOWN
,或WM_LBUTTONDOWN
,等等。
但是会发生什么,例如,如果我创建了一个不继承 class Control
的 class,并且这个 class 引发了一个事件?
(另一个 class,也没有继承 class Control
,接收它)
引发的事件会通过消息循环吗?
听起来不太合逻辑..
(但假设该项目是一个 Windows Forms 项目,只有 2 个 classes - 发送者和接收者根本不是 GUI classes,而是简单的 class是你写的)
任何解释或link关于我们代码背后的机制的文章将不胜感激。
希望我没有正确理解您的问题。我想我们在谈论两件事。
首先 - C# 中事件的工作原理
第二 - 用 C# 编写的 WinForms 应用程序如何知道您何时单击了按钮。
C# 中的事件是它们自己独特的事物。您可以编写一个控制台应用程序、创建您自己的事件、收听它、触发它、响应它等等……这一切都可以正常工作。您通过调用 Add() 订阅事件,通过调用 Remove() 取消订阅。事件本身跟踪哪些方法正在侦听它,并在引发时调用所有这些方法。
Jon Skeet 解释得更好:
How do C# Events work behind the scenes?
但这些事件只是 C# 代码。与您提到的 Win32 消息相关但又不同。在 Winforms 应用程序中,当用户单击按钮时,应用程序如何知道它?我们可以使用调试器(关闭 'My Code' https://msdn.microsoft.com/en-us/library/dn457346.aspx 选项)并在点击事件中设置断点,您将能够看到发生了什么。
所以在 Windows.Forms.Controls.ControlNativeWindow 中有一个 WndProc 方法接受一个 System.Windows.Forms.Message m。
在那之前是一个'debuggableCallback'方法。这反映了您对 Win32API 应用程序的期望。
/// <include file='doc\NativeWindow.uex' path='docs/doc[@for="NativeWindow.DebuggableCallback"]/*' />
/// <devdoc>
/// Window message callback method. Control arrives here when a window
/// message is sent to this Window. This method packages the window message
/// in a Message object and invokes the wndProc() method. A WM_NCDESTROY
/// message automatically causes the releaseHandle() method to be called.
/// </devdoc>
/// <internalonly/>
private IntPtr DebuggableCallback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) {
// Note: if you change this code be sure to change the
// corresponding code in Callback above!
Message m = Message.Create(hWnd, msg, wparam, lparam);
try {
if (weakThisPtr.IsAlive && weakThisPtr.Target != null) {
WndProc(ref m);
}
else {
DefWndProc(ref m);
}
}
finally {
if (msg == NativeMethods.WM_NCDESTROY) ReleaseHandle(false);
if (msg == NativeMethods.WM_UIUNSUBCLASS) ReleaseHandle(true);
}
return m.Result;
}
因此,最终,如果您 运行 在 Windows 上,它是由您期望的相同 Win32 API 消息驱动的。只不过写的System.Windows.Forms类是为了封装我们的大部分。
我目前看到的所有关于C#/.NET的书,在谈到事件的时候,
他们谈论创造和消费事件。
我很想了解它在我们的代码背后是如何工作的——运行它的机制是什么。
我从 Windows 消息循环对所引发事件的行为类似于队列这一事实中略知一二。
例如,WM_KEYDOWN
,或WM_LBUTTONDOWN
,等等。
但是会发生什么,例如,如果我创建了一个不继承 class Control
的 class,并且这个 class 引发了一个事件?
(另一个 class,也没有继承 class Control
,接收它)
引发的事件会通过消息循环吗?
听起来不太合逻辑..
(但假设该项目是一个 Windows Forms 项目,只有 2 个 classes - 发送者和接收者根本不是 GUI classes,而是简单的 class是你写的)
任何解释或link关于我们代码背后的机制的文章将不胜感激。
希望我没有正确理解您的问题。我想我们在谈论两件事。
首先 - C# 中事件的工作原理 第二 - 用 C# 编写的 WinForms 应用程序如何知道您何时单击了按钮。
C# 中的事件是它们自己独特的事物。您可以编写一个控制台应用程序、创建您自己的事件、收听它、触发它、响应它等等……这一切都可以正常工作。您通过调用 Add() 订阅事件,通过调用 Remove() 取消订阅。事件本身跟踪哪些方法正在侦听它,并在引发时调用所有这些方法。
Jon Skeet 解释得更好: How do C# Events work behind the scenes?
但这些事件只是 C# 代码。与您提到的 Win32 消息相关但又不同。在 Winforms 应用程序中,当用户单击按钮时,应用程序如何知道它?我们可以使用调试器(关闭 'My Code' https://msdn.microsoft.com/en-us/library/dn457346.aspx 选项)并在点击事件中设置断点,您将能够看到发生了什么。
所以在 Windows.Forms.Controls.ControlNativeWindow 中有一个 WndProc 方法接受一个 System.Windows.Forms.Message m。
在那之前是一个'debuggableCallback'方法。这反映了您对 Win32API 应用程序的期望。
/// <include file='doc\NativeWindow.uex' path='docs/doc[@for="NativeWindow.DebuggableCallback"]/*' />
/// <devdoc>
/// Window message callback method. Control arrives here when a window
/// message is sent to this Window. This method packages the window message
/// in a Message object and invokes the wndProc() method. A WM_NCDESTROY
/// message automatically causes the releaseHandle() method to be called.
/// </devdoc>
/// <internalonly/>
private IntPtr DebuggableCallback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam) {
// Note: if you change this code be sure to change the
// corresponding code in Callback above!
Message m = Message.Create(hWnd, msg, wparam, lparam);
try {
if (weakThisPtr.IsAlive && weakThisPtr.Target != null) {
WndProc(ref m);
}
else {
DefWndProc(ref m);
}
}
finally {
if (msg == NativeMethods.WM_NCDESTROY) ReleaseHandle(false);
if (msg == NativeMethods.WM_UIUNSUBCLASS) ReleaseHandle(true);
}
return m.Result;
}
因此,最终,如果您 运行 在 Windows 上,它是由您期望的相同 Win32 API 消息驱动的。只不过写的System.Windows.Forms类是为了封装我们的大部分。