4

在我迄今为止看到的所有关于 C#/.NET 的书籍中,当他们谈论事件时,
他们谈论的是创建使用事件。

我很想了解它在我们的代码背后是如何工作的——运行它的机制是什么。

我从 Windows 消息循环的作用类似于引发事件的队列这一事实中知道一点。
例如, WM_KEYDOWN, 或WM_LBUTTONDOWN, 等等。

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

引发的事件会通过消息循环吗?
听起来不太合乎逻辑..
(但假设该项目是一个 Windows 窗体项目,只有 2 个类 - 发送方和接收方根本不是 GUI 类,而是您编写的简单类)

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

4

1 回答 1

4

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

首先 - 事件在 C# 中的工作方式其次 - 用 C# 编写的 WinForms 应用程序如何知道您何时单击了按钮。

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

Jon Skeet 解释得更好: C# 事件如何在幕后工作?

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

调用栈

所以在 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 类是为了封装我们的大部分内容而编写的。

于 2015-12-27T16:28:16.430 回答