W MSDN dowiedziałem CloseReason.UserClosing
się, że użytkownik zdecydował się zamknąć formularz, ale wydaje mi się, że to samo dotyczy zarówno kliknięcia przycisku X, jak i przycisku zamykania. Jak więc mogę rozróżnić te dwa elementy w moim kodzie?
Dziękuje wszystkim.
Odpowiedzi:
Zakładając, że pytasz o WinForms, możesz użyć zdarzenia FormClosing () . Zdarzenie FormClosing () jest wyzwalane za każdym razem, gdy formularz ma zostać zamknięty.
Aby wykryć, czy użytkownik kliknął X lub przycisk CloseButton, możesz go uzyskać za pośrednictwem obiektu nadawcy. Spróbuj rzutować nadawcę jako kontrolkę Button i sprawdź, na przykład, jej nazwę „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. }
W przeciwnym razie nigdy nie musiałem rozróżniać, czy kliknięto X lub CloseButton, ponieważ chciałem wykonać coś konkretnego na zdarzeniu FormClosing, na przykład zamknąć wszystkie MdiChildren przed zamknięciem MDIContainerForm lub sprawdzić zdarzenia pod kątem niezapisanych zmian. W tych okolicznościach nie musimy według mnie odróżniać żadnego z przycisków.
Zamknięcie przez ALT+ F4wyzwoli również zdarzenie FormClosing (), ponieważ wysyła komunikat do Form z informacją o zamknięciu. Możesz anulować wydarzenie, ustawiając
FormClosingEventArgs.Cancel = true.
W naszym przykładzie oznaczałoby to
e.Cancel = true.
Zwróć uwagę na różnicę między zdarzeniami FormClosing () i FormClosed () .
FormClosing ma miejsce, gdy formularz otrzymał wiadomość do zamknięcia i sprawdź, czy ma coś do zrobienia, zanim zostanie zamknięty.
FormClosed występuje, gdy formularz jest faktycznie zamknięty, a więc po jego zamknięciu.
czy to pomaga?
źródło
CloseReason
Wyliczenie znalazłeś na MSDN jest tylko w celu sprawdzenia, czy użytkownik zamknął aplikację, czy to ze względu na zamknięcie lub zamknięte przez menedżera zadań, etc ...Możesz wykonać różne czynności, w zależności od powodu, na przykład:
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 }
Ale tak jak się domyślasz, nie ma różnicy między kliknięciem przycisku x a kliknięciem prawym przyciskiem myszy na pasku zadań i kliknięciem „zamknij” lub naciśnięciem przycisku Alt F4itp. Wszystko kończy się na
CloseReason.UserClosing
przyczynie.źródło
Przycisk „X” rejestruje się jako,
DialogResult.Cancel
więc inną opcją jest ocena plikuDialogResult
.Jeśli masz wiele przycisków w swoim formularzu, prawdopodobnie już przypisujesz różne przyciski
DialogResult
do każdego z nich, co zapewni Ci sposób odróżnienia każdego przycisku.(Przykład:
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; } } }
źródło
DialogResult
pozostajeNone
. Jaki może być problem?X
powoduje , żeDialogResult
zawieraCancel
, a nieNone
. PrzypisanieNone
do przycisku jest tym samym, co nie ustawianie jego.DialogResult
właściwości w ogóle, a jeśli wywołaszform.Close()
z modułu obsługi zdarzeń przycisku,form.DialogResult
będzie zawieraćCancel
. Tylko przypisanie wartości innej niżNone
lubCancel
do wszystkich przycisków zamykających formularz umożliwi dokonanie pożądanego rozróżnienia.Jak sprawdzić, czy formularz został zamknięty poprzez kliknięcie przycisku X lub wywołanie
Close()
kodu?Nie można polegać na zamkniętej przyczynie argumentów zdarzenia zamykającego formularz, ponieważ jeśli użytkownik kliknie przycisk X na pasku tytułowym lub zamknie formularz za pomocą Alt + F4 lub użyje menu systemowego do zamknięcia formularza lub formularz zostanie zamknięty przez wywołanie
Close()
metody, wszystko w powyższych przypadkach, blisko powód zostanie zamknięty przez Użytkownika, co nie jest pożądanym rezultatem.Aby rozróżnić, czy formularz jest zamknięty przyciskiem X, czy
Close
metodą, możesz użyć jednej z następujących opcji:WM_SYSCOMMAND
i sprawdźSC_CLOSE
i ustaw flagę.StackTrace
czy którakolwiek z ramek zawieraClose
wywołanie metody.Przykład 1 - Uchwyt
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()"); }
Przykład 2 - sprawdzanie 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"); }
źródło
StackTrace()
i rozwiązałem problem.Określa, kiedy zamknąć wniosek, jeśli formularz jest zamknięty (jeśli wniosek nie jest dołączony do konkretnego formularza).
private void MyForm_FormClosed(object sender, FormClosedEventArgs e) { if (Application.OpenForms.Count == 0) Application.Exit(); }
źródło
Zawsze używam metody Form Close w moich aplikacjach, która przechwytuje alt + x z mojego przycisku wyjścia, alt + f4 lub inne zdarzenie zamykające formularz zostało zainicjowane. Wszystkie moje klasy mają
mstrClsTitle = "grmRexcel"
w tym przypadku nazwę klasy zdefiniowaną jako Prywatny ciąg , metodę Exit, która wywołuje metodę zamykania formularza i metodę zamykania formularza. Mam również oświadczenie dotyczące metody zamykania formularza -this.FormClosing = My Form Closing Form Closing method name
.Kod do tego:
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; } } } } }
źródło
Możesz spróbować dodać obsługę zdarzeń z projektu w następujący sposób: Otwórz formularz w widoku projektu, otwórz okno właściwości lub naciśnij klawisz F4, kliknij przycisk paska narzędzi zdarzenia, aby wyświetlić zdarzenia w obiekcie Form, znajdź zdarzenie FormClosing w grupie Zachowanie i kliknij je dwukrotnie. Źródła: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral
źródło
if (this.DialogResult == DialogResult.Cancel) { } else { switch (e.CloseReason) { case CloseReason.UserClosing: e.Cancel = true; break; } }
Jeśli warunek zostanie wykonany, gdy użytkownik kliknie przycisk „X” lub przycisk zamknięcia w formularzu. Tej else można użyć, gdy użytkownik kliknie Alt + f4 w jakimkolwiek innym celu
źródło
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 } } } }
źródło
Zgadzam się z rozwiązaniem
DialogResult
-Solution jako prostszym.Jednak w VB.NET do uzyskania opcji
CloseReason
-Property wymagane jest rzutowanie typuPrivate 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
źródło
Musiałem również zarejestrować funkcję zamykającą w metodzie „InitializeComponent ()” formularza:
private void InitializeComponent() { // ... this.FormClosing += FrmMain_FormClosing; // ... }
Moja funkcja „FormClosing” wygląda podobnie do podanej odpowiedzi ( 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"); } }
Jeszcze jedna rzecz, o której warto wspomnieć: istnieje również funkcja „FormClosed”, która występuje po „FormClosing”. Aby użyć tej funkcji, zarejestruj ją, jak pokazano poniżej:
this.FormClosed += MainPage_FormClosed; private void MainPage_FormClosing(object sender, FormClosingEventArgs e) { // your code after the form is closed }
źródło
Zrobiłem coś takiego.
private void Form_FormClosing(object sender, FormClosingEventArgs e) { if ((sender as Form).ActiveControl is Button) { //CloseButton } else { //The X has been clicked } }
źródło