暂时禁用关闭按钮

我需要暂时禁用关闭按钮(应该允许最小化和最大化)。

我尝试过的每个解决方案都会禁用所有按钮,或者只是永久禁用关闭按钮。 有办法临时做吗?

永久禁用关闭按钮的方法是为窗体的窗口类设置CS_NOCLOSE样式 。 要从WinForms应用程序执行此操作,您将覆盖窗体的CreateParams属性并使用|来添加SC_NOCLOSE标志| 运营商,例如:

 protected override CreateParams CreateParams { get { const int CS_NOCLOSE = 0x200; CreateParams cp = base.CreateParams; cp.ClassStyle = cp.ClassStyle | CS_NOCLOSE; return cp; } } 

但这是一个永久的解决方案,因为您无法即时更新窗口类样式。 您必须销毁并重新创建窗口类。

但是,您可以在系统菜单中禁用“关闭”命令,这也会自动禁用标题栏中的关闭按钮。

 internal static class NativeMethods { public const int SC_CLOSE = 0xF060; public const int MF_BYCOMMAND = 0; public const int MF_ENABLED = 0; public const int MF_GRAYED = 1; [DllImport("user32.dll")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool revert); [DllImport("user32.dll")] public static extern int EnableMenuItem(IntPtr hMenu, int IDEnableItem, int enable); } public class MyForm : Form { // ... // If "enable" is true, the close button will be enabled (the default state). // If "enable" is false, the Close button will be disabled. bool SetCloseButton(bool enable) { IntPtr hMenu = NativeMethods.GetSystemMenu(this.Handle, false); if (hMenu != IntPtr.Zero) { NativeMethods.EnableMenuItem(hMenu, NativeMethods.SC_CLOSE, NativeMethods.MF_BYCOMMAND | (enable ? NativeMethods.MF_ENABLED : NativeMethods.MF_GRAYED)); } } } 

请注意,这确实是一个瞬态操作。 如果您执行任何导致系统菜单被框架修改的内容(例如最大化或最小化表单),您的修改将被删除。 更多细节在我的相关答案中 。 这通常是一个问题,为什么你更喜欢使用第一个解决方案。 但在这种情况下,由于您想要动态禁用和重新启用,这没什么大不了的。

最后,请注意您提议的内容与Windows UI准则对话框背道而驰。 他们说,从本质上讲,用户希望看到一个关闭按钮,它的存在给他们一种安全感,他们总能安全地“摆脱”任何弹出的屏幕。 因此,您不应该禁用它。 它确实将进度对话框作为例外调用,但它继续说进度对话框应该总是有一个“取消”按钮,允许中止操作。 在这种情况下,您只需使标题栏中的关闭按钮调用此“取消”按钮 – 无需禁用它。

虽然有可能,但我从未见过它。 这不是程序如何做到的,你的程序应该遵循已知的模式,因此用户知道如何使用它。

如果暂时无法关闭程序,请在用户尝试时显示一条消息,说明原因。 这样你就可以提出一个解决方案(“你必须先做……”)而不是简单地提出问题(“不能关闭”)。

此外,有多种方法可以关闭表单。 你只看其中一个。 禁用一个仍将离开其他人,您可能希望阻止所有导致关闭窗口的选项,因此最好适当地处理Closing事件。

你不能隐藏它,但你可以禁用它:

 private const int CP_NOCLOSE_BUTTON = 0x200; protected override CreateParams CreateParams { get { CreateParams myCp = base.CreateParams; myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON ; return myCp; } } 

资料来源: http : //www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms

如果你绝对需要隐藏它,唯一的方法是创建一个无边框表单,然后绘制自己的最小化和最大化按钮。 这是一篇关于如何做到这一点的文章: http : //www.codeproject.com/Articles/42223/Easy-Customize-Title-Bar

在考虑这些解决方案之前,您应该重新考虑为什么需要这样做。 根据您要做的事情,除了拿走熟悉的“X”关闭按钮之外,可能有更好的方式向用户呈现UI。

根据其他答案,你正在反对指南和框架,但是,如果你真的必须,一个解决方法是将所有表单内容放入Usercontrol,然后在启用了关闭按钮或禁用关闭按钮的表单实例之间传递加载。

因此,当您触发禁用或启用关闭按钮时,您将创建一个新的表单实例,其中切换关闭按钮,然后将引用传递给您的usercontrol,然后取消引用当前表单中的usercontrol并转移到新表单。

当你这样做时,你可能会得到一些闪烁。 可怕的想法恕我直言,但它是“一个”选项。

使用Win32 API,您可以通过以下方式执行此操作:

 [DllImport("User32.dll")] private static extern uint GetClassLong(IntPtr hwnd, int nIndex); [DllImport("User32.dll")] private static extern uint SetClassLong(IntPtr hwnd, int nIndex, uint dwNewLong); private const int GCL_STYLE = -26; private const uint CS_NOCLOSE = 0x0200; private void Form1_Load(object sender, EventArgs e) { var style = GetClassLong(Handle, GCL_STYLE); SetClassLong(Handle, GCL_STYLE, style | CS_NOCLOSE); } 

您将需要使用GetClassLong / SetClassLong来启用CS_NOCLOSE样式。 然后,您可以使用相同的操作删除它,只需在SetClassLongPtr中使用(style&~CS_NOCLOSE)。

实际上,你也可以在WPF应用程序中执行此操作(是的,我知道,问题是关于WinForms,但有些人可能会在某一天需要这个):

 private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) { var hwnd = new WindowInteropHelper(this).Handle; var style = GetClassLong(hwnd, GCL_STYLE); SetClassLong(hwnd, GCL_STYLE, style | CS_NOCLOSE); } 

不过,您应该考虑其他人的建议:只显示一个MessageBox或其他类型的消息,以指示用户不应该立即关闭窗口。


编辑:由于窗口类只是一个UINT,您可以使用GetClassLong和SetClassLong函数而不是GetClassLongPtr和SetClassLongPtr(如MSDN所述):

如果要检索指针或句柄,则此函数已被GetClassLongPtr函数取代。 (指针和句柄在32位Windows上为32位,在64位Windows上为64位。)

这解决了Cody Gray在32位操作系统中缺少* Ptr函数所描述的问题。