如何知道用户点击了“X”或“关闭”按钮?

时间:2010-04-21 14:15:44

标签: c# .net winforms

在MSDN中,我发现CloseReason.UserClosing知道用户已决定关闭该表单 但我想单击X按钮或单击关闭按钮都是一样的。 那么如何在我的代码中区分这两者呢?

谢谢大家。

12 个答案:

答案 0 :(得分:83)

假设您要求使用WinForms,可以使用FormClosing() event。只要表单被关闭,就会触发事件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事件上执行特定的操作,例如在关闭MDIContainerForm之前关闭所有MdiChildren,或者检查未保存的更改的事件。在这种情况下,根据我的说法,我们不需要区别于任何一个按钮。

ALT + F4 关闭也会触发FormClosing()事件,因为它会向表示要关闭的表单发送一条消息。您可以通过设置

取消活动
FormClosingEventArgs.Cancel = true. 

在我们的示例中,这将转换为

e.Cancel = true.

注意FormClosing()和FormClosed()事件之间的区别。

FormClosing在表单收到要关闭的消息时发生,并在关闭之前验证它是否有事可做。

Formclosed在窗体实际关闭时发生,因此在关闭后会发生。

这有帮助吗?

答案 1 :(得分:73)

您在MSDN上找到的CloseReason枚举仅用于检查用户是关闭应用程序,还是由于关闭,或由任务管理器关闭等等...

根据原因,您可以采取不同的行动,例如:

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的理由结束。

答案 2 :(得分:38)

“X”按钮注册为DialogResult.Cancel,因此另一个选项是评估DialogResult

如果表单上有多个按钮,则可能已经将不同的DialogResult与每个按钮相关联,这将为您提供区分每个按钮的方法。

(示例:btnSubmit.DialogResult = DialogResult.OKbtnClose.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;
            }
        }
    }

答案 3 :(得分:6)

如果表单已关闭(如果您的应用程序未附加到特定表单),它将确定何时关闭应用程序。

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

答案 4 :(得分:4)

我总是在我的应用程序中使用Form Close方法,从我的退出按钮, alt + f4 或其他表单关闭事件启动时捕获alt + x。在这种情况下,我的所有类都将类名定义为私有字符串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;
                }
            }
        }
    }
}

答案 5 :(得分:2)

您可以尝试从设计中添加事件处理程序,如下所示:在设计视图中打开表单,打开属性窗口或按F4,单击事件工具栏按钮以查看Form对象上的事件,在Behavior组中找到FormClosing事件,然后双击它。 参考:https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral

答案 6 :(得分:2)

如何通过单击X按钮或调用代码中的Close()来检测是否关闭了表单?

您不能依赖于表单关闭事件args的关闭原因,因为如果用户单击标题栏上的X按钮或使用Alt + F4或使用系统菜单关闭表单或通过调用{ {1}}方法,在上述所有情况下,关闭原因都是被用户关闭,这不是理想的结果。

要区分是通过X按钮还是通过Close()方法关闭表单,可以使用以下任一选项:

  • 处理WM_SYSCOMMAND并检查Close并设置一个标志。
  • 检查StackTrace,以查看是否有任何框架包含SC_CLOSE方法调用。

示例1-处理Close

WM_SYSCOMMAND

示例2-检查StackTrace

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

答案 7 :(得分:1)

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

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

如果用户在表单上单击“X”或关闭按钮时将执行条件。当用户单击Alt + f4用于任何其他目的时,可以使用else

答案 8 :(得分:1)

我同意<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script> <article> <header> <p class="inputDate">2018-06-15 11:27:30</p> <p class="outputDate"></p> </header> <div id="question1"> <p>1.Lorem ipsum dolor sit amet ?</p> </div> <div id="answer1"> <p>1.Amet sit dolor ipsum lorem.</p> </div> </article> <article> <header> <p class="inputDate">2019-07-18 15:15:45</p> <p class="outputDate"></p> </header> <div id="question2"> <p>2.Lorem ipsum dolor sit amet ?</p> </div> <div id="answer2"> <p>2.Amet sit dolor ipsum lorem.</p> </div> </article> <article> <header> <p class="inputDate">2019-08-14 10:23:00</p> <p class="outputDate"></p> </header> <div id="question3"> <p>3.Lorem ipsum dolor sit amet ?</p> </div> <div id="answer3"> <p>3.Amet sit dolor ipsum lorem.</p> </div> </article>-解决方案是更直接的解决方案。

但是在VB.NET中,必须进行类型转换才能获得DialogResult-属性

CloseReason

答案 9 :(得分:0)

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

答案 10 :(得分: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
}

答案 11 :(得分:0)

我已经做了类似的事情。

private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if ((sender as Form).ActiveControl is Button)
        {
            //CloseButton
        }
        else
        {
            //The X has been clicked
        }
    }