Как узнать, что пользователь нажал кнопку «X» или «Закрыть»?
97
В MSDN я узнал CloseReason.UserClosing, что пользователь решил закрыть форму, но я предполагаю, что это то же самое, как при нажатии кнопки X, так и при нажатии кнопки закрытия. Итак, как я могу различить эти два в моем коде?
Предполагая, что вы запрашиваете WinForms, вы можете использовать событие FormClosing () . Событие FormClosing () запускается каждый раз, когда форма закрывается.
Чтобы определить, щелкнул ли пользователь X или вашу CloseButton, вы можете получить его через объект-отправитель. Попробуйте передать отправителя как элемент управления Button и, возможно, проверьте его имя, например, «CloseButton».
privatevoidForm1_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, например, закрыть все MdiChildren перед закрытием MDIContainerForm или проверить события на наличие несохраненных изменений. В этих обстоятельствах, по моему мнению, нам не нужно различать ни одну из кнопок.
Закрытие с помощью ALT+ F4также вызовет событие FormClosing (), поскольку оно отправляет в форму сообщение о закрытии. Вы можете отменить событие, установив
FormClosingEventArgs.Cancel = true.
В нашем примере это будет выглядеть так:
e.Cancel = true.
Обратите внимание на разницу между событиями FormClosing () и FormClosed () .
FormClosing происходит, когда форма получила сообщение, которое нужно закрыть, и проверяет, есть ли у нее что-то делать, прежде чем она будет закрыта.
FormClosed возникает, когда форма фактически закрыта, то есть после закрытия.
Да, спасибо за идею "Cast", использовал эту технику с Delphi 7, но забыл сделать то же самое в C #
Bohn
1
Когда я использую этот код, я получаю сообщение «Ссылка на объект не установлена на экземпляр объекта».
Нейт С.
34
Это не правильно. Вы не можете отправить отправителя на кнопку, потому что это сама форма. Это вызывает исключение.
Xtro
2
Обратите внимание, что это НЕПРАВИЛЬНЫЙ ответ. Пожалуйста, не голосуйте за это.
Наджиб,
1
Посмотрите ответ пользователя @Reza Aghaei
Najeeb
79
CloseReasonПеречисление вы нашли на MSDN только с целью проверки закрыта ли пользователь приложение, или это было связано с простою, или закрывается менеджером задач, и т.д ...
Вы можете выполнять разные действия в зависимости от причины, например:
voidForm_FormClosing(object sender, FormClosingEventArgs e)
{
if(e.CloseReason == CloseReason.UserClosing)
// Prompt user to save his dataif(e.CloseReason == CloseReason.WindowsShutDown)
// Autosave and clear up ressources
}
Но, как вы уже догадались, нет никакой разницы между нажатием кнопки x, щелчком правой кнопкой мыши на панели задач и щелчком «закрыть», или нажатием AltF4и т. Д. Все это заканчивается CloseReason.UserClosingпричиной.
Используя стандартный Close (); кажется, запускает CloseReason.UserClosing для меня. Не знаю почему.
Dan W
Я нашел это полезным при попытке заблокировать закрытие дочерней формы MDI действием пользователя в форме, но не при закрытии родительской формы.
Стив Петтифер
1
Это не дает ответа на вопрос, а только перечисляет проблему дальше.
Роберт Кернке,
Как связать событие с методом?
user2924019
43
Кнопка «X» регистрируется, DialogResult.Cancelпоэтому еще один вариант - оценить DialogResult.
Если у вас есть несколько кнопок в вашей форме, вы, вероятно, уже связываете разные DialogResults с каждой, и это предоставит вам средства, чтобы определить разницу между каждой кнопкой.
publicForm1()
{
InitializeComponent();
this.FormClosing += Form1_FormClosing;
}
///<summary>/// Override the Close Form event/// Do something///</summary>///<param name="sender"></param>///<param name="e"></param>privatevoidForm1_FormClosing(Object sender, FormClosingEventArgs e)
{
//In case windows is trying to shut down, don't hold the process upif (e.CloseReason == CloseReason.WindowsShutDown) return;
if (this.DialogResult == DialogResult.Cancel)
{
// Assume that X has been clicked and act accordingly.// Confirm user wants to closeswitch (MessageBox.Show(this, "Are you sure?", "Do you still want ... ?", MessageBoxButtons.YesNo, MessageBoxIcon.Question))
{
//Stay on this formcase DialogResult.No:
e.Cancel = true;
break;
default:
break;
}
}
}
В моем случае это более полезно, чем принятый ответ. Поскольку 'X' назначается DialogResult.Cancel, присвоение некоторого другого значения кнопке отмены легко позволяет различать их и обрабатывать вещи соответствующим образом.
MickeyfAgain_BeforeExitOfSO
3
В моем случае это не работает. При нажатии «X» DialogResultостается None. В чем может быть проблема?
Bhaskar
1
@Bhaskar, когда вы создаете экземпляр своего диалога, обязательно установите соответствующий DialogResult для каждой кнопки в вашем диалоге. Я привел пример выше, но не создал блок кода для отображения объявления Dialog.
AlexScript
@Bhaskar: Нажатие Xзаставляет DialogResultсдерживать Cancel, а не None. Назначение Noneвашей кнопке - то же самое, что и отсутствие установки ее .DialogResultсвойства, и если вы вызываете form.Close()из обработчика событий вашей кнопки, он form.DialogResultбудет содержать Cancel. Только присвоение значения, отличного от Noneили Cancelдля всех кнопок закрытия формы, позволит вам сделать желаемое различие.
mklement0
12
Как определить, закрылась ли форма нажатием кнопки X или вызовом Close()кода?
Вы не можете полагаться на причину закрытия аргументов события закрытия формы, потому что, если пользователь нажимает кнопку X в строке заголовка или закрывает форму с помощью Alt + F4 или использует системное меню, чтобы закрыть форму, или форма закрывается путем вызова Close()метода, все все Вышеуказанные случаи, причина закрытия будет закрыта пользователем, что не является желаемым результатом.
Чтобы определить, закрыта ли форма кнопкой X или Closeметодом, вы можете использовать любой из следующих вариантов:
Обработать, WM_SYSCOMMANDпроверить SC_CLOSEи установить флаг.
Проверьте, StackTraceсодержит ли какой-либо из кадров Closeвызов метода.
Пример 1 - Ручка WM_SYSCOMMAND
publicbool ClosedByXButtonOrAltF4 {get; privateset;}
privateconstint SC_CLOSE = 0xF060;
privateconstint WM_SYSCOMMAND = 0x0112;
protectedoverridevoidWndProc(ref Message msg)
{
if (msg.Msg == WM_SYSCOMMAND && msg.WParam.ToInt32() == SC_CLOSE)
ClosedByXButtonOrAltF4 = true;
base.WndProc(ref msg);
}
protectedoverridevoidOnShown(EventArgs e)
{
ClosedByXButtonOrAltF4 = false;
}
protectedoverridevoidOnFormClosing(FormClosingEventArgs e)
{
if (ClosedByXButtonOrAltF4)
MessageBox.Show("Closed by X or Alt+F4");
else
MessageBox.Show("Closed by calling Close()");
}
Пример 2 - Проверка StackTrace
protectedoverridevoidOnFormClosing(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");
}
Отлично сделано. Жаль, что вы опоздали на вечеринку - трудно конкурировать со старыми, уже получившими высокую оценку ответами.
mklement0
1
@ mklement0 Надеюсь, будущие пользователи сочтут это полезным. Я опубликовал ответ, потому что ни один из других ответов не может правильно решить проблему, и это довольно странно для вопроса с таким количеством просмотров и высоко оцененными (неработающими) ответами!
Reza Aghaei
Большое спасибо. Я использовал, StackTrace()и это решило проблему.
Али Маджед HA
@AliMajedHA Круто!
Реза Агаи,
7
Он определяет, когда закрыть приложение, если форма закрыта (если ваше приложение не привязано к определенной форме).
Я всегда использую метод закрытия формы в своих приложениях, который улавливает alt + x от моей кнопки выхода, alt + f4 или другое событие закрытия формы было инициировано. Все мои классы имеют имя класса, определенное mstrClsTitle = "grmRexcel"в данном случае как частная строка , метод Exit, который вызывает метод закрытия формы и метод закрытия формы. У меня также есть заявление о методе закрытия формы - this.FormClosing = My Form Closing Form Closing method name.
Код для этого:
namespaceRexcel_II
{
publicpartialclassfrmRexcel : Form
{
privatestring mstrClsTitle = "frmRexcel";
publicfrmRexcel()
{
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>privatevoidbtnExit_Click(object sender, EventArgs e)
{
this.Close();
}
///<summary>/// Handles the Form Closing event//////</summary>///<param name="sender"></param>///<param name="e"></param>privatevoidfrmRexcel_FormClosing(object sender, FormClosingEventArgs e)
{
// ---- If windows is shutting down, // ---- I don't want to hold up the processif (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 applicationswitch (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 applicationcase 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» или кнопку закрытия формы. Else можно использовать, когда пользователь нажимает Alt + F4 для любой другой цели.
Я согласен с 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
privatevoidFrmMain_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");
}
}
Еще одна вещь, о которой стоит упомянуть: существует также функция "FormClosed", которая появляется после "FormClosing". Чтобы использовать эту функцию, зарегистрируйте ее, как показано ниже:
this.FormClosed += MainPage_FormClosed;
privatevoidMainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}
privatevoidForm_FormClosing(object sender, FormClosingEventArgs e)
{
if ((sender as Form).ActiveControl is Button)
{
//CloseButton
}
else
{
//The X has been clicked
}
}
Ответы:
Предполагая, что вы запрашиваете WinForms, вы можете использовать событие FormClosing () . Событие 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, например, закрыть все MdiChildren перед закрытием MDIContainerForm или проверить события на наличие несохраненных изменений. В этих обстоятельствах, по моему мнению, нам не нужно различать ни одну из кнопок.
Закрытие с помощью ALT+ F4также вызовет событие FormClosing (), поскольку оно отправляет в форму сообщение о закрытии. Вы можете отменить событие, установив
FormClosingEventArgs.Cancel = true.
В нашем примере это будет выглядеть так:
e.Cancel = true.
Обратите внимание на разницу между событиями FormClosing () и FormClosed () .
FormClosing происходит, когда форма получила сообщение, которое нужно закрыть, и проверяет, есть ли у нее что-то делать, прежде чем она будет закрыта.
FormClosed возникает, когда форма фактически закрыта, то есть после закрытия.
Это помогает?
источник
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 }
Но, как вы уже догадались, нет никакой разницы между нажатием кнопки x, щелчком правой кнопкой мыши на панели задач и щелчком «закрыть», или нажатием Alt F4и т. Д. Все это заканчивается
CloseReason.UserClosing
причиной.источник
Кнопка «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; } } }
источник
DialogResult
остаетсяNone
. В чем может быть проблема?X
заставляетDialogResult
сдерживатьCancel
, а неNone
. НазначениеNone
вашей кнопке - то же самое, что и отсутствие установки ее.DialogResult
свойства, и если вы вызываетеform.Close()
из обработчика событий вашей кнопки, онform.DialogResult
будет содержатьCancel
. Только присвоение значения, отличного отNone
илиCancel
для всех кнопок закрытия формы, позволит вам сделать желаемое различие.Как определить, закрылась ли форма нажатием кнопки X или вызовом
Close()
кода?Вы не можете полагаться на причину закрытия аргументов события закрытия формы, потому что, если пользователь нажимает кнопку X в строке заголовка или закрывает форму с помощью Alt + F4 или использует системное меню, чтобы закрыть форму, или форма закрывается путем вызова
Close()
метода, все все Вышеуказанные случаи, причина закрытия будет закрыта пользователем, что не является желаемым результатом.Чтобы определить, закрыта ли форма кнопкой 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"); }
источник
StackTrace()
и это решило проблему.Он определяет, когда закрыть приложение, если форма закрыта (если ваше приложение не привязано к определенной форме).
private void MyForm_FormClosed(object sender, FormClosedEventArgs e) { if (Application.OpenForms.Count == 0) Application.Exit(); }
источник
Я всегда использую метод закрытия формы в своих приложениях, который улавливает alt + x от моей кнопки выхода, alt + f4 или другое событие закрытия формы было инициировано. Все мои классы имеют имя класса, определенное
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; } } } } }
источник
Вы можете попробовать добавить обработчик событий из дизайна следующим образом: откройте форму в режиме просмотра, откройте окно свойств или нажмите F4, нажмите кнопку панели инструментов событий, чтобы просмотреть события в объекте Form, найдите событие FormClosing в группе Behavior и дважды щелкните его. Ссылка: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral
источник
if (this.DialogResult == DialogResult.Cancel) { } else { switch (e.CloseReason) { case CloseReason.UserClosing: e.Cancel = true; break; } }
Если условие будет выполнено, когда пользователь щелкнет «X» или кнопку закрытия формы. Else можно использовать, когда пользователь нажимает Alt + F4 для любой другой цели.
источник
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
-PropertyPrivate 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
источник
Мне также пришлось зарегистрировать закрывающую функцию внутри метода формы "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"); } }
Еще одна вещь, о которой стоит упомянуть: существует также функция "FormClosed", которая появляется после "FormClosing". Чтобы использовать эту функцию, зарегистрируйте ее, как показано ниже:
this.FormClosed += MainPage_FormClosed; private void MainPage_FormClosing(object sender, FormClosingEventArgs e) { // your code after the form is closed }
источник
Я сделал что-то подобное.
private void Form_FormClosing(object sender, FormClosingEventArgs e) { if ((sender as Form).ActiveControl is Button) { //CloseButton } else { //The X has been clicked } }
источник