How to know user has clicked "X" or the "Close" button?

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

Thanks all.

365588 次浏览

假设您要求使用 WinForms,则可以使用 事件。每当要关闭窗体时,都会触发 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.
}

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

Closing by ALT+F4 will also trigger the FormClosing() event, as it sends a message to the Form that says to close. You may cancel the event by setting the

FormClosingEventArgs.Cancel = true.

在我们的例子中,这意味着

e.Cancel = true.

Notice the difference between the FormClosing() and the 表格关闭() events.

当窗体收到要关闭的消息并在关闭之前验证它是否有要做的事情时,就会发生 FormClose。

当窗体实际上是闭合的时候发生,所以在它闭合之后。

这有帮助吗?

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

But like you guessed, there is no difference between clicking the x button, or rightclicking the taskbar and clicking 'close', or pressing Alt F4, etc. It all ends up in a CloseReason.UserClosing reason.

The "X" button registers as DialogResult.Cancel so another option is to evaluate the DialogResult.

If you have multiple buttons on your form, you're probably already associating different DialogResults to each and this will provide you with the means to tell the difference between each button.

(例子: 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;
}
}
}
if (this.DialogResult == DialogResult.Cancel)
{


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

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

它确定在窗体关闭时何时关闭应用程序(如果应用程序未附加到特定窗体)。

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

您可以尝试从设计中添加事件处理程序,如下所示: 在设计视图中打开窗体,打开属性窗口或按 F4,单击事件工具栏按钮查看窗体对象上的事件,在行为组中查找表单关闭事件,然后双击它。 参考文献: < a href = “ https://social.msdn.microsoft.com/Forums/vStudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclose-event? forum = cSharp general”rel = “ nofollow”> https://social.msdn.microsoft.com/forums/vstudio/en-us/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral

I always use a Form Close method in my applications that catches alt + x from my exit Button, Alt + f4 or another form closing event was initiated. All my classes have the class name defined as Private string mstrClsTitle = "grmRexcel" in this case, an Exit method that calls the Form Closing Method and a Form Closing Method. I also have a statement for the 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;
}
}
}
}
}
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
}
}
}
}

我同意 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

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

不能依赖窗体关闭事件参数的紧密原因,因为:
if the user click X button on title bar or
使用 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-检查堆栈跟踪

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

我还必须在表单的“ InitializeComponent ()”方法中注册结束函数:

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

我的“ FormCclose”函数看起来类似于给定的答案(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");
}
}

还有一件事要提到: 在“ FormCclose”之后还有一个“ FormClose”函数。要使用这个函数,注册它如下所示:

this.FormClosed += MainPage_FormClosed;


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

I've done something like this.

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