区分用户关闭表单和用户关闭应用
Distinguish between user closing form and user closing app
我正在处理以下场景:
- 当用户试图关闭我的应用程序中的一个特定表单时(通过 Ctrl + F4 或通过专用按钮)我需要他在满足特定条件时注销,
- 因此我覆盖了
OnFormClosed
方法,检查条件,如果满足条件,我会显示一个消息框,一旦用户单击确定,他就会退出我的应用程序,
- 我正在调查
FormClosedEventArgs.CloseReason
,并且仅在 UserClosing
、 的情况下应用此逻辑
- 但是,当用户试图关闭整个应用程序时(通过 Alt + F4 或右上角的关闭按钮,
CloseReason
仍然是 UserClosing
,因此没有关闭应用程序,而是向他显示了消息框,然后他退出了应用程序。这是不希望的,因为应用程序关闭显然比注销更强大。
所以我的问题 - 是否有一种很好的方法来区分用户关闭表单或用户关闭整个应用程序?我可能可以通过覆盖 ProcessCmdKey
来设置一些 bool 标志,以区分 Alt + F4 和 Ctrl + F4,但这不是很好,也没有解决单击关闭按钮时的问题。
我不认为有任何内置方法可以做你想做的事(除了预处理系统击键)。用户在应用程序中发起的任何关闭(MDI 表单除外)都将是 ÙserClosing
.
一个解决方法是将您的表单嵌入到另一个表单中(将 Owner
设置为外部表单)并检查内部表单关闭是否具有 FormOwnerClosing
原因(即如果您单击外部表单上的 'X' 会发生这种情况),并检查父表单上的 UserClosing
而不是实际表单(内部表单),但我认为这更不优雅而且会将您的代码拆分为两种不同的形式。
没有什么好的方法,您必须在 FormClosing 事件开始触发之前 window 检测到用户关闭了您的主要 window 。这不是 Winforms 中公开的功能,但您可以通过覆盖主 window 的表单 class 中的 WndProc() 方法轻松添加它。您对 WM_SYSCOMMAND 消息感兴趣,SC_CLOSE 命令:
public static bool MainWindowClosing;
protected override void WndProc(ref Message m) {
if (m.Msg == 0x112 && (m.WParam.ToInt32() & 0xfff0) == 0xf060) {
MainWindowClosing = true;
}
base.WndProc(ref m);
}
现在您可以在其他 classes:
中测试该变量
protected override void OnFormClosing(FormClosingEventArgs e) {
if (!Form1.MainWindowClosing && e.CloseReason == CloseReason.UserClosing) {
// Display your dialog
//...
}
base.OnFormClosing(e);
}
如果您采取任何措施阻止用户关闭您的应用,则需要将 MainWindowClosing 设置回 false。我不想提的是,在高度安全的 Windows 登录之外添加登录过程是一个严重的错误,很可能会泄露密码。
我正在处理以下场景:
- 当用户试图关闭我的应用程序中的一个特定表单时(通过 Ctrl + F4 或通过专用按钮)我需要他在满足特定条件时注销,
- 因此我覆盖了
OnFormClosed
方法,检查条件,如果满足条件,我会显示一个消息框,一旦用户单击确定,他就会退出我的应用程序, - 我正在调查
FormClosedEventArgs.CloseReason
,并且仅在UserClosing
、 的情况下应用此逻辑
- 但是,当用户试图关闭整个应用程序时(通过 Alt + F4 或右上角的关闭按钮,
CloseReason
仍然是UserClosing
,因此没有关闭应用程序,而是向他显示了消息框,然后他退出了应用程序。这是不希望的,因为应用程序关闭显然比注销更强大。
所以我的问题 - 是否有一种很好的方法来区分用户关闭表单或用户关闭整个应用程序?我可能可以通过覆盖 ProcessCmdKey
来设置一些 bool 标志,以区分 Alt + F4 和 Ctrl + F4,但这不是很好,也没有解决单击关闭按钮时的问题。
我不认为有任何内置方法可以做你想做的事(除了预处理系统击键)。用户在应用程序中发起的任何关闭(MDI 表单除外)都将是 ÙserClosing
.
一个解决方法是将您的表单嵌入到另一个表单中(将 Owner
设置为外部表单)并检查内部表单关闭是否具有 FormOwnerClosing
原因(即如果您单击外部表单上的 'X' 会发生这种情况),并检查父表单上的 UserClosing
而不是实际表单(内部表单),但我认为这更不优雅而且会将您的代码拆分为两种不同的形式。
没有什么好的方法,您必须在 FormClosing 事件开始触发之前 window 检测到用户关闭了您的主要 window 。这不是 Winforms 中公开的功能,但您可以通过覆盖主 window 的表单 class 中的 WndProc() 方法轻松添加它。您对 WM_SYSCOMMAND 消息感兴趣,SC_CLOSE 命令:
public static bool MainWindowClosing;
protected override void WndProc(ref Message m) {
if (m.Msg == 0x112 && (m.WParam.ToInt32() & 0xfff0) == 0xf060) {
MainWindowClosing = true;
}
base.WndProc(ref m);
}
现在您可以在其他 classes:
中测试该变量 protected override void OnFormClosing(FormClosingEventArgs e) {
if (!Form1.MainWindowClosing && e.CloseReason == CloseReason.UserClosing) {
// Display your dialog
//...
}
base.OnFormClosing(e);
}
如果您采取任何措施阻止用户关闭您的应用,则需要将 MainWindowClosing 设置回 false。我不想提的是,在高度安全的 Windows 登录之外添加登录过程是一个严重的错误,很可能会泄露密码。