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

Solution 1:

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?

Solution 2:

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.

Solution 3:

The "X" button registers as DialogResult.Cancel so another option is to evaluate the DialogResult.

If you have multiple buttons on your form, you're probably already associating different DialogResults to each and this will provide you with the means to tell the difference between each button.

(Example: btnSubmit.DialogResult = DialogResult.OK, btnClose.DialogResult = Dialogresult.Abort)

    public Form1()
    {
        InitializeComponent();

        this.FormClosing += Form1_FormClosing;
    }

    /// <summary>
    /// Override the Close Form event
    /// Do something
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
    {
        //In case windows is trying to shut down, don't hold the process up
        if (e.CloseReason == CloseReason.WindowsShutDown) return;

        if (this.DialogResult == DialogResult.Cancel)
        {
            // Assume that X has been clicked and act accordingly.
            // Confirm user wants to close
            switch (MessageBox.Show(this, "Are you sure?", "Do you still want ... ?", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
            {
                //Stay on this form
                case DialogResult.No:
                    e.Cancel = true;
                    break;
                default:
                    break;
            }
        }
    }