Disabling the Close-Button temporarily

后端 未结 7 1120
后悔当初
后悔当初 2020-12-31 14:45

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

Every solution I\'ve tried disables all the buttons

相关标签:
7条回答
  • 2020-12-31 14:55
    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 
        }
    }
    

    This worked for me

    0 讨论(0)
  • 2020-12-31 15:01

    Using Win32 API, you can do this the following way:

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

    You will need to use GetClassLong / SetClassLong to enable the CS_NOCLOSE style. You then can remove it with the same operations, just use (style & ~CS_NOCLOSE) in SetClassLongPtr.

    Actually, you can do this in WPF apps as well (yeah, I know, the question is about WinForms, but maybe someone will need this some day):

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

    Still, you should consider what others have suggested: just show a MessageBox or another kind of message to indicate that user should not close the window right now.


    Edit: Since window class is just a UINT, you can use GetClassLong and SetClassLong functions instead of GetClassLongPtr and SetClassLongPtr (as says MSDN):

    If you are retrieving a pointer or a handle, this function has been superseded by the GetClassLongPtr function. (Pointers and handles are 32 bits on 32-bit Windows and 64 bits on 64-bit Windows.)

    This resolves the problem described by Cody Gray regarding the absense of *Ptr funcs in 32-bit OS.

    0 讨论(0)
  • 2020-12-31 15:05

    You can't hide it, but you can disable it:

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

    Source: http://www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms

    If you absolutely need to hide it, the only way to do it is to create a borderless form, then draw your own minimize and maximize buttons. Here is an article on how to do this: http://www.codeproject.com/Articles/42223/Easy-Customize-Title-Bar

    Before considering either of these solutions, you should maybe rethink why you need to do this. Depending on what you are trying to do, there is probably a much better way to present the UI to the user other than taking away the familiar 'X' close button.

    0 讨论(0)
  • 2020-12-31 15:08

    Although it may be possible, I have never seen it. That's just not how programs do it and your program should follow known patterns so it's users know how to use it.

    If closing a program is temporarily not possible, show a message explaining why, when your user tries. This way you can present a solution ("you must first do...") instead of simply presenting a problem ("cannot be closed").

    In addition, there are multiple ways to close a form. You are only looking at one of them. Disabling one will still leave the others and you would want to prevent all options that lead to closing your window, so it's best to handle the Closing event appropriately.

    0 讨论(0)
  • 2020-12-31 15:09

    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.

    0 讨论(0)
  • 2020-12-31 15:10

    As per other answers you are working against the guidelines and framework but, if you really must, one work around would be to put all your form content into a Usercontrol and then pass that between form instances that either have the close button enabled or disabled on load.

    So as you trigger the disable or enable of the close button you create a new form instance in which the close button is toggled and then pass in the reference to your usercontrol, then dereference the usercontrol in the current form and transfer to the new form.

    You'd likely get a some flicker as you did this. Terrible idea IMHO but it is "an" option.

    0 讨论(0)
提交回复
热议问题