How to know user has clicked “X” or the “Close” button?

前端 未结 12 992
野性不改
野性不改 2020-11-27 12:19

In MSDN I found CloseReason.UserClosing to know that the user had decided to close the form but I guess it is the same for both clicking the X button or clickin

相关标签:
12条回答
  • 2020-11-27 12:53

    Assuming you're asking for WinForms, you may use the FormClosing() event. The event FormClosing() is triggered any time a form is to get closed.

    To detect if the user clicked either X or your CloseButton, you may get it through the sender object. Try to cast sender as a Button control, and verify perhaps for its name "CloseButton", for instance.

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
        if (string.Equals((sender as Button).Name, @"CloseButton"))
            // Do something proper to CloseButton.
        else
            // Then assume that X has been clicked and act accordingly.
    }
    

    Otherwise, I have never ever needed to differentiate whether X or CloseButton was clicked, as I wanted to perform something specific on the FormClosing event, like closing all MdiChildren before closing the MDIContainerForm, or event checking for unsaved changes. Under these circumstances, we don't need, according to me, to differentiate from either buttons.

    Closing by ALT+F4 will also trigger the FormClosing() event, as it sends a message to the Form that says to close. You may cancel the event by setting the

    FormClosingEventArgs.Cancel = true. 
    

    In our example, this would translate to be

    e.Cancel = true.
    

    Notice the difference between the FormClosing() and the FormClosed() events.

    FormClosing occurs when the form received the message to be closed, and verify whether it has something to do before it is closed.

    FormClosed occurs when the form is actually closed, so after it is closed.

    Does this help?

    0 讨论(0)
  • 2020-11-27 12:54
    if (this.DialogResult == DialogResult.Cancel)
            {
    
            }
            else
            {
                switch (e.CloseReason)
                {
                    case CloseReason.UserClosing:
                        e.Cancel = true;
                        break;
                }
            }
    

    if condition will execute when user clicks 'X' or close button on form. The else can be used when user clicks Alt+f4 for any other purpose

    0 讨论(0)
  • 2020-11-27 12:58

    You can try adding event handler from design like this: Open form in design view, open properties window or press F4, click event toolbar button to view events on Form object, find FormClosing event in Behavior group, and double click it. Reference: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral

    0 讨论(0)
  • 2020-11-27 12:59

    How to detect if the form closed by click on X button or by calling Close() in code?

    You cannot rely on close reason of the form closing event args, because if the user click X button on title bar or close the form using Alt + F4 or use system menu to close the form or the form get closed by calling Close() method, all all above cases, the close reason will be Closed by User which is not desired result.

    To distinguish if the form closed by X button or by Close method, you can use either of the following options:

    • Handle WM_SYSCOMMAND and check for SC_CLOSE and set a flag.
    • Check the StackTrace to see if any of the frames contain Close method call.

    Example 1 - Handle WM_SYSCOMMAND

    public bool ClosedByXButtonOrAltF4 {get; private set;}
    private const int SC_CLOSE = 0xF060;
    private const int WM_SYSCOMMAND = 0x0112;
    protected override void WndProc(ref Message msg)
    {
        if (msg.Msg == WM_SYSCOMMAND && msg.WParam.ToInt32() == SC_CLOSE)
            ClosedByXButtonOrAltF4 = true;
        base.WndProc(ref msg);
    }
    protected override void OnShown(EventArgs e)
    {
        ClosedByXButtonOrAltF4 = false;
    }   
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        if (ClosedByXButtonOrAltF4)
            MessageBox.Show("Closed by X or Alt+F4");
        else
            MessageBox.Show("Closed by calling Close()");
    }
    

    Example 2 - Checking StackTrace

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        if (new StackTrace().GetFrames().Any(x => x.GetMethod().Name == "Close"))
            MessageBox.Show("Closed by calling Close()");
        else
            MessageBox.Show("Closed by X or Alt+F4");
    }
    
    0 讨论(0)
  • 2020-11-27 12:59

    I agree with the DialogResult-Solution as the more straight forward one.

    In VB.NET however, typecast is required to get the CloseReason-Property

        Private Sub MyForm_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
    
            Dim eCast As System.Windows.Forms.FormClosingEventArgs
            eCast = TryCast(e, System.Windows.Forms.FormClosingEventArgs)
            If eCast.CloseReason = Windows.Forms.CloseReason.None Then
                MsgBox("Button Pressed")
            Else
                MsgBox("ALT+F4 or [x] or other reason")
            End If
    
        End Sub
    
    0 讨论(0)
  • 2020-11-27 13:01

    The CloseReason enumeration you found on MSDN is just for the purpose of checking whether the user closed the app, or it was due to a shutdown, or closed by the task manager, etc...

    You can do different actions, according to the reason, like:

    void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if(e.CloseReason == CloseReason.UserClosing)
            // Prompt user to save his data
    
        if(e.CloseReason == CloseReason.WindowsShutDown)
            // Autosave and clear up ressources
    }
    

    But like you guessed, there is no difference between clicking the x button, or rightclicking the taskbar and clicking 'close', or pressing Alt F4, etc. It all ends up in a CloseReason.UserClosing reason.

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