109

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

谢谢大家。

4

12 回答 12

100

假设您要求 WinForms,您可以使用FormClosing() 事件。每当要关闭表单时都会触发事件 FormClosing()。

要检测用户是否单击了 X 或您的 CloseButton,您可以通过 sender 对象获取它。例如,尝试将 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.
}

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

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

FormClosingEventArgs.Cancel = true. 

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

e.Cancel = true.

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

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

FormClosed 发生在窗体实际关闭时,所以在它关闭之后。

这有帮助吗?

于 2010-04-21T14:20:12.700 回答
83

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

Alt F4但是就像你猜的那样,单击 x 按钮,或者右键单击任务栏并单击“关闭”,或者按等没有区别。这一切都有一个CloseReason.UserClosing原因。

于 2010-04-21T14:32:45.827 回答
49

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

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

(例如: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;
            }
        }
    }
于 2011-12-01T17:31:56.283 回答
31

如何通过单击 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()");
}

示例 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");
}
于 2019-11-10T15:44:01.640 回答
8

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

    private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (Application.OpenForms.Count == 0) Application.Exit();
    }
于 2012-10-19T19:33:30.190 回答
5

我总是在我的应用程序中使用 Form Close 方法,该方法从我的退出按钮中捕获 alt + x,alt + f4或另一个表单关闭事件已启动。在这种情况下,我所有的类都将类名定义为 Private string mstrClsTitle = "grmRexcel",一个调用 Form Closing Method 的 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;
                }
            }
        }
    }
}
于 2018-05-14T17:45:04.830 回答
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

于 2016-08-25T15:32:18.097 回答
2
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
            }
        }
    }
}
于 2018-12-01T18:57:56.270 回答
1
if (this.DialogResult == DialogResult.Cancel)
        {

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

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

于 2012-01-12T08:54:49.247 回答
1

我同意DialogResult-Solution 作为更直接的解决方案。

然而,在 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
于 2019-11-08T16:17:51.393 回答
1

我还必须在表单的“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
}
于 2020-02-27T08:36:27.547 回答
0

我做过这样的事情。

private void Form_FormClosing(object sender, FormClosingEventArgs e)
    {
        if ((sender as Form).ActiveControl is Button)
        {
            //CloseButton
        }
        else
        {
            //The X has been clicked
        }
    }
于 2020-08-21T09:09:51.410 回答