.NET的事件机制

时间:2015-12-27 15:49:21

标签: c# .net events message-loop

在我所见到的关于C#/ .NET的所有书籍中,当他们谈论事件时, 他们谈论创建消费事件。

我很想知道我们的代码背后是如何工作的 - 运行它的机制是什么。

我对Windows消息循环对于引发的事件的队列行为有所了解。 例如,WM_KEYDOWNWM_LBUTTONDOWN等等。

但是会发生什么,例如,如果我创建了一个不继承class Control的类,并且这个类引发了一个事件?
(另一个类,也没有继承class Control,接收它)

引发的事件会通过消息循环吗?
听起来不那么逻辑。
(但假设该项目是一个Windows窗体项目,只有两个类 - 发送者和接收者根本不是GUI类,而是你写的简单类)

对我们代码背后机制的文章的任何解释或链接都将受到高度赞赏。

1 个答案:

答案 0 :(得分:4)

我希望我能正确理解你的问题。我想我们正在谈论两件事。

首先 - C#中的事件如何工作 第二 - 用C#编写的WinForms应用程序如何知道你何时点击了一个按钮。

C#中的事件是他们自己独特的事情。你可以编写一个控制台应用程序,创建自己的事件,听取它,激活它,响应它等等......这一切都可行。您通过调用Add()订阅事件,并通过调用Remove()取消订阅。事件本身会跟踪哪些方法正在监听它以及何时引发它,调用所有这些方法。

Jon Skeet解释得更好: How do C# Events work behind the scenes?

但这些事件只是C#代码。与您提到的Win32消息相关但不同。在Winforms应用程序中,当用户单击按钮时,应用程序如何知道它?我们可以使用调试器(关闭“我的代码”https://msdn.microsoft.com/en-us/library/dn457346.aspx选项)并在点击事件中设置断点,您将能够看到正在发生的事情。

Callstack

所以在Windows.Forms.Controls.ControlNativeWindow中有一个WndProc方法,它接受一个System.Windows.Forms.Message m。

之前是'debuggableCallback'方法。这反映了您对Win32API应用程序的期望。

来源: http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/NativeWindow.cs,ad40308c5b6490dd

/// <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类来封装大部分类。