사용자가 "X"또는 "닫기"버튼을 클릭했는지 어떻게 알 수 있습니까?


94

MSDN CloseReason.UserClosing에서 사용자가 양식을 닫기로 결정한 것을 알았지 만 X 단추를 클릭하거나 닫기 단추를 클릭하는 것이 동일하다고 생각합니다. 그렇다면 내 코드에서이 둘을 어떻게 구별 할 수 있습니까?

모두 감사합니다.


2
어떤 닫기 버튼을 의미합니까?
Brian R. Bondy

예를 들어 "ALT + F4"로 닫기
Bohn


@Oliver 같은 질문이 아닙니다.
Ctrl S

답변:


95

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

그렇지 않으면 MDIContainerForm을 닫기 전에 모든 MdiChildren을 닫거나 저장되지 않은 변경 사항을 확인하는 이벤트와 같이 FormClosing 이벤트에 대해 특정 작업을 수행하기를 원했기 때문에 X 또는 CloseButton을 클릭했는지 구분할 필요가 없었습니다. 이러한 상황에서 우리는 두 버튼을 구별 할 필요가 없습니다.

ALT+로 닫으면 F4FormClosing () 이벤트가 트리거되어 닫으라는 메시지를 Form에 보냅니다. 이벤트를 취소 할 수 있습니다.

FormClosingEventArgs.Cancel = true. 

이 예에서 이것은

e.Cancel = true.

FormClosing () 및 FormClosed () 이벤트 의 차이점을 확인하십시오 .

FormClosing은 양식이 닫힐 메시지를 수신 할 때 발생하며 닫히기 전에 할 일이 있는지 확인합니다.

FormClosed는 양식이 실제로 닫힐 때 발생하므로 닫힌 후에 발생합니다.

도움이 되나요?


예, "Cast"아이디어에 감사드립니다. Delphi 7에서이 기술을 사용했지만 C #에서 동일한 작업을 수행하는 것을 잊었습니다
Bohn

사실 이것은 Delphi에서 .NET으로의 포트입니다. =) 도와 줘서 기뻐요!
Will Marcouiller 2010

1
이 코드를 사용할 때 '개체 참조가 개체의 인스턴스로 설정되지 않았습니다'가 표시됩니다.
Nate S.

33
이것은 잘못되었습니다. 양식 자체이기 때문에 발신자를 버튼으로 캐스팅 할 수 없습니다. 예외가 발생합니다.
Xtro 2015 년

1
이것은 잘못된 답변입니다. 이것을 찬성하지 마십시오.
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 자식 양식을 닫는 것을 차단하려고 할 때 유용하지만 부모가 닫힐 때는 그렇지 않습니다.
Steve Pettifer 2014 년

1
이것은 질문에 대한 답이 아니라 문제를 더 열거 할뿐입니다.
Robert Koernke

이벤트를 메소드에 어떻게 바인딩합니까?
user2924019 19

43

"X"버튼이 등록 DialogResult.Cancel되므로 다른 옵션은 DialogResult.

양식에 여러 개의 단추가있는 경우 이미 DialogResult각 단추에 서로 다른을 연결하고있을 가능성 이 있으며 이는 각 단추의 차이점을 구분할 수있는 수단을 제공합니다.

(예 : 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 2013

3
제 경우에는 작동하지 않습니다. 'X'를 DialogResult누르면가 유지 None됩니다. 무엇이 문제일까요?
Bhaskar

1
@Bhaskar, 대화 상자를 인스턴스화 할 때 대화 상자의 각 단추에 적절한 DialogResult를 설정해야합니다. 위의 예제를 제공했지만 Dialog 선언을 표시하는 코드 블록을 만들지 않았습니다.
AlexScript apr

@Bhaskar : 누르면 X차종은 DialogResult포함 Cancel하지 None. 지정 None하여 버튼에 자사의 설정하지 않는 것과 동일 .DialogResult전혀 속성을, 그리고 당신이 호출하는 경우 form.Close()귀하의 버튼의 이벤트 핸들러에서, form.DialogResult포함됩니다 Cancel. None또는 Cancel모든 양식 닫기 버튼에 다른 값을 지정하는 것만으로 원하는 구분을 할 수 있습니다.
mklement0

9

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 2019

7

양식이 닫힌 경우 애플리케이션을 닫을시기를 결정합니다 (애플리케이션이 특정 양식에 첨부되지 않은 경우).

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

5

내 응용 프로그램에서 항상 종료 버튼, alt + f4 또는 다른 양식 닫기 이벤트 에서 alt + x를 포착하는 Form Close 메서드를 사용합니다 . 내 모든 클래스에는 mstrClsTitle = "grmRexcel"이 경우에 Private 문자열 로 정의 된 클래스 이름 이 있습니다.이 경우 Form Closing 메서드와 Form Closing 메서드를 호출하는 Exit 메서드가 있습니다. Form Closing Method에 대한 설명도 있습니다.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;
                }
            }
        }
    }
}


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-Solution이보다 솔직한 것에 동의합니다 .

그러나 VB.NET에서는 CloseReason-Property 를 가져 오려면 typecast가 필요합니다.

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

한 가지 더 언급 할 사항 : "FormClosing"이후에 발생하는 "FormClosed"함수도 있습니다. 이 기능을 사용하려면 아래와 같이 등록하십시오.

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
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.