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

Boh*_*ohn 84 .net c# winforms

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

谢谢大家.

Wil*_*ler 88

假设您要求WinForms,您可以使用FormClosing()事件.只要表单被关闭,就会触发事件FormClosing().

要检测用户是否单击了X或您的CloseButton,您可以通过sender对象获取它.尝试将发送者转换为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.
}
Run Code Online (Sandbox Code Playgroud)

否则,我从来不需要区分是否单击了X或CloseButton,因为我想在FormClosing事件上执行特定的操作,比如在关闭MDIContainerForm之前关闭所有MdiChildren,或者检查未保存的更改的事件.在这种情况下,根据我的说法,我们不需要区别于任何一个按钮.

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

FormClosingEventArgs.Cancel = true. 
Run Code Online (Sandbox Code Playgroud)

在我们的例子中,这将转化为

e.Cancel = true.
Run Code Online (Sandbox Code Playgroud)

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

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

FormClosed发生在窗体实际关闭时,因此关闭后.

这有帮助吗?

  • 这是错的.您无法将发件人转换为按钮,因为它是表单本身.这引发了异常. (26认同)
  • @WillMarcouiller:鉴于您的答案已被接受并且有如此多的赞成票,请考虑修复有关能够投射到按钮的错误信息。 (3认同)
  • 请注意,这是一个不正确的答案。请不要对此点赞。 (2认同)
  • 查看用户@Reza Aghaei 的回答 (2认同)

Phi*_*ier 76

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
}
Run Code Online (Sandbox Code Playgroud)

但是就像你猜测的那样,点击x按钮,或右键单击任务栏并单击"关闭"或按下Alt F4等等没有区别.这一切都归结为一个CloseReason.UserClosing原因.

  • 使用标准Close(); 似乎为我触发了CloseReason.UserClosing.不知道为什么. (10认同)
  • 这并没有回答问题,只是进一步列举了问题。 (2认同)

Ale*_*ipt 41

"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;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 这在我的情况下不起作用.按"X"时,"DialogResult"仍为"无".可能是什么问题呢? (3认同)
  • 就我而言,这比接受的答案更有用。由于“X”被分配为 DialogResult.Cancel,因此为取消按钮分配一些其他值可以轻松地区分它们并适当处理事情。 (2认同)

Rez*_*aei 23

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

您不能依赖表单关闭事件参数的关闭原因,因为:
如果用户单击标题栏上的 X 按钮或
使用 Alt + F4 关闭表单或
使用系统菜单关闭表单或
通过调用Close()方法关闭表单,

对于上述所有情况,关闭原因将是用户关闭( CloseReason.UserClosing),这不是预期的结果。

要区分表单是按 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()");
}
Run Code Online (Sandbox Code Playgroud)

示例 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");
}
Run Code Online (Sandbox Code Playgroud)

  • @mklement0 我希望未来的用户发现它很有用。我发布了答案,因为其他答案都不能正确解决问题,而且对于具有如此数量的视图和高度投票(无效)答案的问题来说,这很奇怪! (4认同)

der*_*kat 6

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

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


小智 5

我总是在我的应用程序中使用Form Close方法,该方法从退出按钮,alt + f4或启动了另一个关闭表单事件中捕获alt + x 。mstrClsTitle = "grmRexcel"在这种情况下,我所有的类都有定义为“私有”字符串的类名,一个调用“表单关闭方法”的Exit方法和一个“表单关闭方法”。我也有一个关于Forms 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;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)