暂时禁用关闭按钮

时间:2014-08-15 06:20:06

标签: c# winforms

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

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

7 个答案:

答案 0 :(得分:10)

永久禁用关闭按钮的方法是为表单的窗口类设置CS_NOCLOSE style。要从WinForms应用程序执行此操作,请覆盖表单CreateParams property并使用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));                                
        }
    }   
}

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

最后,请注意您提出的建议与Windows UI Guidelines for dialog boxes背道而驰的事实。他们说,从本质上讲,用户希望看到一个关闭按钮,它的存在给他们一种安全感,他们可以随时安全地“走出去”。任何弹出的屏幕。因此,您不应该禁用它。它确实将进度对话框作为例外调用,但它继续说进度对话框应始终具有"取消"允许中止操作的按钮。在这种情况下,你可以简单地使标题栏中的关闭按钮调用这个"取消"按钮 - 无需禁用它。

答案 1 :(得分:1)

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

如果暂时无法关闭程序,请在用户尝试时显示一条消息,说明原因。通过这种方式,您可以提供解决方案("您必须先做...")而不是简单地提出问题("无法关闭")。

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

答案 2 :(得分:0)

你无法隐藏它,但你可以禁用它:

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' X'关闭按钮。

答案 3 :(得分:0)

使用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或其他类型的消息,指示用户不应该立即关闭该窗口。


<强> 编辑: 由于window类只是一个UINT,你可以使用GetClassLong和SetClassLong函数代替GetClassLongPtr和SetClassLongPtr(如MSDN所述):

  

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

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

答案 4 :(得分:0)

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

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

你这样做可能会有一些闪烁。可怕的想法恕我直言,但它是&#34;一个&#34;选项。

答案 5 :(得分:0)

关闭按钮在下面的状态下被禁用: 如果我们添加:MessageBoxButtons.YesNo

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

答案 6 :(得分:0)

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 
    }
}

这对我有用