Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disabling the Close-Button temporarily

Tags:

c#

winforms

I need to disable just the close button (minimize and maximize should be allowed) temporarily.

Every solution I've tried disables all the buttons or just disables the close button permanently. Is there a way to do it temporarily?

like image 798
Horius Avatar asked Aug 15 '14 06:08

Horius


1 Answers

The way to permanently disable the close button is to set the CS_NOCLOSE style for the form's window class. To do this from a WinForms application, you override the form's CreateParams property and add the SC_NOCLOSE flag using the | operator, e.g.:

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

This is a permanent solution, though, since you cannot update window class styles on-the-fly. You would have to destroy and recreate the window class.

However, you can instead disable the "Close" command in the system menu, which also also automatically disables the close button in the title bar.

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

Note that this really is a transient operation. If you do anything that causes the system menu to be modified by the framework (such as maximizing or minimizing the form), your modifications will be obliterated. More details are in my related answer here. This is normally a problem, and why you'd prefer to use the first solution. But in this case, since you want to dynamically disable and re-enable, it is no big deal.

Finally, do be mindful of the fact that what you're proposing runs counter to the Windows UI Guidelines for dialog boxes. They say, in essence, that users expect to see a close button and that its presence gives them a feeling of security that they can always safely "get out" of whatever popped up of the screen. Thus, you should not disable it. It does call out a progress dialog as an exception, but it goes on to say that a progress dialog should always have a "Cancel" button that allows aborting the operation. In that case, you can simply make the close button in the title bar invoke this "Cancel" button—no need to disable it.

like image 167
Cody Gray Avatar answered Oct 17 '22 17:10

Cody Gray