暂时禁用关闭按钮

本文关键字:关闭按钮 | 更新日期: 2023-09-27 18:18:18

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

我尝试过的每个解决方案都禁用所有按钮或只是永久禁用关闭按钮。有没有办法暂时做到这一点?

暂时禁用关闭按钮

永久禁用关闭按钮的方法是为窗体的窗口类设置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事件。

isprocessing = true;
form.FormClosing += new FormClosingEventHandler(form_cancel); 
private void form_cancel(object sender, FormClosingEventArgs e)
{
   if (isprocessing)
   {
      e.Cancel = true;  //disables the form close when processing is true
   }
   else
   {
      e.Cancel = false; //enables it later when processing is set to false at some point 
    }
}

这对我有效

关闭按钮在以下条件下被禁用:如果我们添加:MessageBoxButtons。YesNo

DialogResult Dr = MessageBox.Show(this, "", "", MessageBoxButtons.YesNo, MessageBoxIcon.Information);

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

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

在考虑这些解决方案之前,您应该重新考虑为什么需要这样做。根据你想做的事情,可能有更好的方式向用户呈现UI,而不是去掉熟悉的"X"关闭按钮。

根据其他的答案,你正在工作的指导方针和框架,但是,如果你真的必须,一个工作将是把所有的表单内容到一个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样式。然后你可以用同样的操作删除它,只需使用(style &~CS_NOCLOSE) in SetClassLongPtr.

实际上,你也可以在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函数的问题。