У MSDN я дізнався CloseReason.UserClosing
, що користувач вирішив закрити форму, але я думаю, це однаково як для натискання кнопки X, так і для натискання кнопки закриття. То як я можу розрізнити ці два у своєму коді?
Дякую усім.
У MSDN я дізнався CloseReason.UserClosing
, що користувач вирішив закрити форму, але я думаю, це однаково як для натискання кнопки X, так і для натискання кнопки закриття. То як я можу розрізнити ці два у своєму коді?
Дякую усім.
Відповіді:
Припускаючи, що ви просите WinForms, ви можете використовувати подію FormClosing () . Подія FormClosing () запускається щоразу, коли форма закривається.
Щоб виявити, чи натиснув користувач кнопку X або вашу кнопку CloseButton, ви можете отримати його через об'єкт відправника. Спробуйте відіслати відправника як елемент керування кнопкою та перевірте, можливо, його назву "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 () .
Закриття форми відбувається, коли форма отримала повідомлення, яке потрібно закрити, і перевірте, чи має він щось робити до закриття.
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
для всіх ваших кнопок закриття форми, дозволить вам зробити бажане розрізнення.
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");
}
Він визначає, коли слід закрити заявку, якщо форма закрита (якщо ваша заявка не приєднана до певної форми).
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, натисніть кнопку панелі інструментів подій, щоб переглянути події в об’єкті Форми, знайдіть подію FormClosing у групі Поведінка та двічі клацніть на ній. Посилання: 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' або кнопку закрити на формі. Інше можна використовувати, коли користувач натискає 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
-Property потрібен typecast
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
Мені також довелося зареєструвати функцію закриття в методі форми "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", яка виникає після "FormClosed". Щоб використовувати цю функцію, зареєструйте її, як показано нижче:
this.FormClosed += MainPage_FormClosed;
private void MainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}