Как узнать, что пользователь нажал кнопку «X» или «Закрыть»?


97

В MSDN я узнал CloseReason.UserClosing, что пользователь решил закрыть форму, но я предполагаю, что это то же самое, как при нажатии кнопки X, так и при нажатии кнопки закрытия. Итак, как я могу различить эти два в моем коде?

Спасибо всем.


2
какую кнопку закрытия вы имеете в виду?
Брайан Р. Бонди,

например, закрытие нажатием "ALT + F4"
Бон


@Oliver Не тот вопрос.
Ctrl S

Ответы:


96

Предполагая, что вы запрашиваете WinForms, вы можете использовать событие FormClosing () . Событие FormClosing () запускается каждый раз, когда форма закрывается.

Чтобы определить, щелкнул ли пользователь X или вашу CloseButton, вы можете получить его через объект-отправитель. Попробуйте передать отправителя как элемент управления Button и, возможно, проверьте его имя, например, «CloseButton».

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

В противном случае мне никогда не приходилось различать, был ли нажат X или CloseButton, поскольку я хотел выполнить что-то конкретное в событии FormClosing, например, закрыть все MdiChildren перед закрытием MDIContainerForm или проверить события на наличие несохраненных изменений. В этих обстоятельствах, по моему мнению, нам не нужно различать ни одну из кнопок.

Закрытие с помощью ALT+ F4также вызовет событие FormClosing (), поскольку оно отправляет в форму сообщение о закрытии. Вы можете отменить событие, установив

FormClosingEventArgs.Cancel = true. 

В нашем примере это будет выглядеть так:

e.Cancel = true.

Обратите внимание на разницу между событиями FormClosing () и FormClosed () .

FormClosing происходит, когда форма получила сообщение, которое нужно закрыть, и проверяет, есть ли у нее что-то делать, прежде чем она будет закрыта.

FormClosed возникает, когда форма фактически закрыта, то есть после закрытия.

Это помогает?


Да, спасибо за идею "Cast", использовал эту технику с Delphi 7, но забыл сделать то же самое в C #
Bohn

1
Когда я использую этот код, я получаю сообщение «Ссылка на объект не установлена ​​на экземпляр объекта».
Нейт С.

34
Это не правильно. Вы не можете отправить отправителя на кнопку, потому что это сама форма. Это вызывает исключение.
Xtro

2
Обратите внимание, что это НЕПРАВИЛЬНЫЙ ответ. Пожалуйста, не голосуйте за это.
Наджиб,

1
Посмотрите ответ пользователя @Reza Aghaei
Najeeb

79

CloseReasonПеречисление вы нашли на MSDN только с целью проверки закрыта ли пользователь приложение, или это было связано с простою, или закрывается менеджером задач, и т.д ...

Вы можете выполнять разные действия в зависимости от причины, например:

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
}

Но, как вы уже догадались, нет никакой разницы между нажатием кнопки x, щелчком правой кнопкой мыши на панели задач и щелчком «закрыть», или нажатием Alt F4и т. Д. Все это заканчивается CloseReason.UserClosingпричиной.


11
Используя стандартный Close (); кажется, запускает CloseReason.UserClosing для меня. Не знаю почему.
Dan W

Я нашел это полезным при попытке заблокировать закрытие дочерней формы MDI действием пользователя в форме, но не при закрытии родительской формы.
Стив Петтифер

1
Это не дает ответа на вопрос, а только перечисляет проблему дальше.
Роберт Кернке,

Как связать событие с методом?
user2924019

43

Кнопка «X» регистрируется, DialogResult.Cancelпоэтому еще один вариант - оценить DialogResult.

Если у вас есть несколько кнопок в вашей форме, вы, вероятно, уже связываете разные DialogResults с каждой, и это предоставит вам средства, чтобы определить разницу между каждой кнопкой.

(Пример: 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;
            }
        }
    }

1
В моем случае это более полезно, чем принятый ответ. Поскольку 'X' назначается DialogResult.Cancel, присвоение некоторого другого значения кнопке отмены легко позволяет различать их и обрабатывать вещи соответствующим образом.
MickeyfAgain_BeforeExitOfSO

3
В моем случае это не работает. При нажатии «X» DialogResultостается None. В чем может быть проблема?
Bhaskar

1
@Bhaskar, когда вы создаете экземпляр своего диалога, обязательно установите соответствующий DialogResult для каждой кнопки в вашем диалоге. Я привел пример выше, но не создал блок кода для отображения объявления Dialog.
AlexScript

@Bhaskar: Нажатие Xзаставляет DialogResultсдерживать Cancel, а не None. Назначение Noneвашей кнопке - то же самое, что и отсутствие установки ее .DialogResultсвойства, и если вы вызываете form.Close()из обработчика событий вашей кнопки, он form.DialogResultбудет содержать Cancel. Только присвоение значения, отличного от Noneили Cancelдля всех кнопок закрытия формы, позволит вам сделать желаемое различие.
mklement0

12

Как определить, закрылась ли форма нажатием кнопки X или вызовом Close()кода?

Вы не можете полагаться на причину закрытия аргументов события закрытия формы, потому что, если пользователь нажимает кнопку X в строке заголовка или закрывает форму с помощью Alt + F4 или использует системное меню, чтобы закрыть форму, или форма закрывается путем вызова Close()метода, все все Вышеуказанные случаи, причина закрытия будет закрыта пользователем, что не является желаемым результатом.

Чтобы определить, закрыта ли форма кнопкой X или Closeметодом, вы можете использовать любой из следующих вариантов:

  • Обработать, WM_SYSCOMMANDпроверить SC_CLOSEи установить флаг.
  • Проверьте, StackTraceсодержит ли какой-либо из кадров Closeвызов метода.

Пример 1 - Ручка 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()");
}

Пример 2 - Проверка 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");
}

1
Отлично сделано. Жаль, что вы опоздали на вечеринку - трудно конкурировать со старыми, уже получившими высокую оценку ответами.
mklement0

1
@ mklement0 Надеюсь, будущие пользователи сочтут это полезным. Я опубликовал ответ, потому что ни один из других ответов не может правильно решить проблему, и это довольно странно для вопроса с таким количеством просмотров и высоко оцененными (неработающими) ответами!
Reza Aghaei

Большое спасибо. Я использовал, StackTrace()и это решило проблему.
Али Маджед HA

@AliMajedHA Круто!
Реза Агаи,

7

Он определяет, когда закрыть приложение, если форма закрыта (если ваше приложение не привязано к определенной форме).

    private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (Application.OpenForms.Count == 0) Application.Exit();
    }

5

Я всегда использую метод закрытия формы в своих приложениях, который улавливает alt + x от моей кнопки выхода, alt + f4 или другое событие закрытия формы было инициировано. Все мои классы имеют имя класса, определенное mstrClsTitle = "grmRexcel"в данном случае как частная строка , метод Exit, который вызывает метод закрытия формы и метод закрытия формы. У меня также есть заявление о методе закрытия формы - this.FormClosing = My Form Closing Form Closing method name.

Код для этого:

namespace Rexcel_II
{
    public partial class frmRexcel : Form
    {
        private string mstrClsTitle = "frmRexcel";

        public frmRexcel()
        {
            InitializeComponent();

            this.FormClosing += frmRexcel_FormClosing;
        }

        /// <summary>
        /// Handles the Button Exit Event executed by the Exit Button Click
        /// or Alt + x
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExit_Click(object sender, EventArgs e)
        {            
            this.Close();        
        }


        /// <summary>
        /// Handles the Form Closing event
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmRexcel_FormClosing(object sender, FormClosingEventArgs e)
        {

            // ---- If windows is shutting down, 
            // ---- I don't want to hold up the process
            if (e.CloseReason == CloseReason.WindowsShutDown) return;
            {

                // ---- Ok, Windows is not shutting down so
                // ---- either btnExit or Alt + x or Alt + f4 has been clicked or
                // ---- another form closing event was intiated
                //      *)  Confirm user wants to close the application
                switch (MessageBox.Show(this, 
                                    "Are you sure you want to close the Application?",
                                    mstrClsTitle + ".frmRexcel_FormClosing",
                                    MessageBoxButtons.YesNo, MessageBoxIcon.Question))
                {

                    // ---- *)  if No keep the application alive 
                    //----  *)  else close the application
                    case DialogResult.No:
                        e.Cancel = true;
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

2

Вы можете попробовать добавить обработчик событий из дизайна следующим образом: откройте форму в режиме просмотра, откройте окно свойств или нажмите F4, нажмите кнопку панели инструментов событий, чтобы просмотреть события в объекте Form, найдите событие FormClosing в группе Behavior и дважды щелкните его. Ссылка: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral


1
if (this.DialogResult == DialogResult.Cancel)
        {

        }
        else
        {
            switch (e.CloseReason)
            {
                case CloseReason.UserClosing:
                    e.Cancel = true;
                    break;
            }
        }

Если условие будет выполнено, когда пользователь щелкнет «X» или кнопку закрытия формы. Else можно использовать, когда пользователь нажимает Alt + F4 для любой другой цели.


1
namespace Test
{
    public partial class Member : Form
    {
        public Member()
        {
            InitializeComponent();
        }

        private bool xClicked = true;

        private void btnClose_Click(object sender, EventArgs e)
        {
            xClicked = false;
            Close();
        }

        private void Member_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (xClicked)
            {
                // user click the X
            } 
            else 
            {
                // user click the close button
            }
        }
    }
}

1

Я согласен с DialogResult-Решением, как с более прямым.

Однако в VB.NET требуется приведение типов для получения 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

Мне также пришлось зарегистрировать закрывающую функцию внутри метода формы "InitializeComponent ()":

private void InitializeComponent() {
// ...
this.FormClosing += FrmMain_FormClosing;
// ...
}

Моя функция "FormClosing" похожа на данный ответ ( https://stackoverflow.com/a/2683846/3323790 ):

private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) {
    if (e.CloseReason == CloseReason.UserClosing){
        MessageBox.Show("Closed by User", "UserClosing");
    }

    if (e.CloseReason == CloseReason.WindowsShutDown){
        MessageBox.Show("Closed by Windows shutdown", "WindowsShutDown");
    }
}

Еще одна вещь, о которой стоит упомянуть: существует также функция "FormClosed", которая появляется после "FormClosing". Чтобы использовать эту функцию, зарегистрируйте ее, как показано ниже:

this.FormClosed += MainPage_FormClosed;

private void MainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}

0

Я сделал что-то подобное.

private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if ((sender as Form).ActiveControl is Button)
        {
            //CloseButton
        }
        else
        {
            //The X has been clicked
        }
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.