为什么最大化/最小化事件会导致关闭按钮在禁用后重新启用?
我已使用 P/Invoke 调用 GetSystemMenu 和 EnableMenuItem (win32api) 来禁用关闭功能。但是,在最小化或最大化我的 Windows 窗体应用程序后,该按钮将重新启用。
显然,最小化或最大化是导致这种行为的原因,但是如何呢?我不知道在哪里可以防止这种行为。
我是否应该阻止最大化和最小化行为,或者 IP/Invoked 调用的方式是否存在特别错误?加载应用程序(主窗体)后,我通过单击按钮调用静态方法。
class PInvoke
{
// P/Invoke signatures
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
// SysCommand (WM_SYSCOMMAND) constant
internal const UInt32 SC_CLOSE = 0xF060;
// Constants used with Add/Check/EnableMenuItem
internal const UInt32 MF_BYCOMMAND = 0x00000000;
internal const UInt32 MF_ENABLED = 0x00000000;
internal const UInt32 MF_GRAYED = 0x00000001;
internal const UInt32 MF_DISABLED = 0x00000002;
/// <summary>
/// Sets the state of the Close (X) button and the System Menu close functionality.
/// </summary>
/// <param name="window">Window or Form</param>
/// <param name="bEnabled">Enabled state</param>
public static void EnableCloseButton(IWin32Window window, bool bEnabled)
{
IntPtr hSystemMenu = GetSystemMenu(window.Handle, false);
EnableMenuItem(hSystemMenu, SC_CLOSE, MF_BYCOMMAND | (bEnabled ? MF_ENABLED : MF_GRAYED));
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
每个窗口都有一个窗口类,它定义该类的所有窗口的样式。您可以使用
CS_NOCLOSE
类样式来删除该类窗口的关闭按钮。请参阅此处和此处了解如何设置此类标志的详细信息。如果这不能满足您的需求,为了可用性,我不会禁用最小化/最大化,但您可以监听最小化/最大化事件并重新运行代码以禁用关闭按钮。最后可以处理关闭事件,而干脆不关闭。然后您就知道您的窗口肯定不会关闭,即使关闭按钮无意中启用。
Each window has a window class, which defines styles for all windows of that class. You can use
CS_NOCLOSE
class style to remove the close button for windows of that class. See here and here for details how to set this class flag.If this doesn't give you what you want, I wouldn't disable minimize/maximize for sake of usability, but you could listen for minimize/maximimize events and re-run the code to disable the close button. Finally, it is possible to handle the close event, and simply not close. Then you know your window will definitely not be closed, even if the close button does inadvertently become enabled.
接受的答案确实提出了一种可能的解决方法(我已经使用过很多次),但是它根本没有回答最初提出的问题:
在我自己发现这种看似无法解释的行为后,我在谷歌搜索中完全没有结果,从而得出了这个问题。没有找到真正解释这种行为的答案,
我被迫自己进行一些挖掘。
作为参考,请注意,与原始问题中所示完全相同的代码在本机 Win32 应用程序中运行良好。重新启用“关闭”菜单项似乎仅限于 WinForms 应用程序。
研究
System.Windows.Forms.Form
类的源代码发现了一个有趣的实现细节:.NET Framework 设计者显然决定在每次表单的>WindowState
更改,其中包括系统发送的最大化和最小化事件。具体来说,有两个名为
AdjustSystemMenu
的方法,负责更改系统菜单以响应这些事件(并弄乱您自己完成的任何自定义操作)。如果您有兴趣检查代码(为了那些参与 Mono 等项目的人的利益,我已放弃在此处发布代码),请获取 .NET Reflector。我不完全确定为什么做出这个决定,但至少我现在有了解释。
The accepted answer does propose a possible workaround to the problem (and one that I've used many times), but it simply doesn't answer the question that was originally asked:
I arrived at this question during the course of a completely fruitless Google search after discovering this seemingly unexplainable behavior for myself. Not finding an answer that actually explained the behavior,
I was forced to resort to some digging of my own.
For reference, note that the exact same code as shown in the original question works fine in a native Win32 application. The re-enabling of the Close menu item seems limited to WinForms applications.
Studying the source code for the
System.Windows.Forms.Form
class uncovers an interesting implementation detail: The .NET Framework designers apparently decided to adjust the form's system menu each time that the form'sWindowState
changes, which includes maximize and minimize events sent by the system.Specifically, there are two methods by the name
AdjustSystemMenu
that are responsible for altering the system menu in response to the these events (and messing up any customization that you may have done yourself). If you're interested in examining the code (which I have abstained from posting here for the benefit of those involved with projects such as Mono), grab a free copy of .NET Reflector.I'm not entirely sure why this decision was made, but at least I have my explanation now.
我有同样的要求。在尝试了多种方法来禁用关闭菜单选项,然后删除并尝试重新创建它(正确)后,我发现了来自 Microsoft http://support.microsoft.com/kb/184686。
就像魅力一样。这仍然是一个 hack,但它确实有效。
这是我对 VB 原始文件的(松散的)C# 转换
I had the same requirement. After trying several ways to disable the close menu option and then deleting and trying to recreate it (correctly), I found this hack from Microsoft http://support.microsoft.com/kb/184686 .
Works like a charm. It's still a hack, but it works.
Here's my (loose) C# conversion of the VB original