No MSDN descobri CloseReason.UserClosing
que o usuário decidiu fechar o formulário, mas acho que é o mesmo para clicar no botão X ou clicar no botão Fechar. Então, como posso diferenciar entre esses dois no meu código?
Obrigado a todos.
No MSDN descobri CloseReason.UserClosing
que o usuário decidiu fechar o formulário, mas acho que é o mesmo para clicar no botão X ou clicar no botão Fechar. Então, como posso diferenciar entre esses dois no meu código?
Obrigado a todos.
Respostas:
Supondo que você esteja solicitando WinForms, você pode usar o evento FormClosing () . O evento FormClosing () é disparado sempre que um formulário deve ser fechado.
Para detectar se o usuário clicou no X ou no CloseButton, você pode obtê-lo por meio do objeto remetente. Tente lançar o remetente como um controle de Botão e verifique, talvez, por seu nome "CloseButton", por exemplo.
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.
}
Caso contrário, nunca precisei diferenciar se X ou CloseButton foi clicado, pois eu queria realizar algo específico no evento FormClosing, como fechar todos os MdiChildren antes de fechar o MDIContainerForm ou verificar o evento para alterações não salvas. Nessas circunstâncias, não precisamos, na minha opinião, diferenciar um dos botões.
Fechar com ALT+ F4também acionará o evento FormClosing (), pois enviará uma mensagem ao Form que diz para fechar. Você pode cancelar o evento definindo o
FormClosingEventArgs.Cancel = true.
Em nosso exemplo, isso seria traduzido como
e.Cancel = true.
Observe a diferença entre os eventos FormClosing () e FormClosed () .
O FormClosing ocorre quando o formulário recebe a mensagem a ser encerrada, e verifique se há algo a fazer antes de ser encerrado.
FormClosed ocorre quando o formulário é realmente fechado, ou seja, após ser fechado.
Isso ajuda?
A CloseReason
enumeração que você encontrou no MSDN serve apenas para verificar se o usuário fechou o aplicativo, se foi devido a um desligamento ou pelo gerenciador de tarefas, etc ...
Você pode fazer diferentes ações, de acordo com o motivo, como:
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
}
Mas, como você adivinhou, não há diferença entre clicar no botão x, ou clicar com o botão direito na barra de tarefas e clicar em 'fechar', ou pressionar Alt F4, etc. Tudo termina em um CloseReason.UserClosing
motivo.
O botão "X" registra, DialogResult.Cancel
portanto, outra opção é avaliar o DialogResult
.
Se você tiver vários botões em seu formulário, provavelmente já está associando diferentes DialogResult
s a cada um e isso fornecerá os meios para saber a diferença entre cada botão.
(Exemplo: 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
permanece None
. Qual pode ser o problema?
X
marcas DialogResult
contêm Cancel
, não None
. Atribuir None
ao seu botão é o mesmo que não definir sua .DialogResult
propriedade e, se você chamar a form.Close()
partir do manipulador de eventos do botão, form.DialogResult
conterá Cancel
. Apenas atribuir um valor diferente de None
ou Cancel
para todos os botões de fechamento de formulário permitirá que você faça a distinção desejada.
Close()
código?Você não pode confiar na razão de fechamento dos argumentos de evento de fechamento do formulário, porque se o usuário clicar no botão X na barra de título ou fechar o formulário usando Alt + F4 ou usar o menu do sistema para fechar o formulário ou o formulário será fechado chamando o Close()
método, todos casos acima, o motivo de fechamento será Fechado pelo usuário, o que não é o resultado desejado.
Para distinguir se o formulário foi fechado pelo botão X ou por Close
método, você pode usar uma das seguintes opções:
WM_SYSCOMMAND
verifique SC_CLOSE
e defina um sinalizador.StackTrace
se algum dos quadros contém Close
chamada de método.Exemplo 1 - Alça 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()");
}
Exemplo 2 - Verificando 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");
}
Ele determina quando fechar o aplicativo se um formulário for fechado (se o seu aplicativo não estiver anexado a um formulário específico).
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (Application.OpenForms.Count == 0) Application.Exit();
}
Eu sempre uso um método Form Close em meus aplicativos que captura alt + x do meu botão de saída, alt + f4 ou outro evento de fechamento de formulário foi iniciado. Todas as minhas classes têm o nome da classe definido como Private string mstrClsTitle = "grmRexcel"
neste caso, um método Exit que chama o Form Closing Method e um Form Closing Method. Também tenho uma declaração para o Método de fechamento de formulário - this.FormClosing = My Form Closing Form Closing method name
.
O código para isso:
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;
}
}
}
}
}
Você pode tentar adicionar um manipulador de eventos a partir do design como este: Abra o formulário na visualização do design, abra a janela de propriedades ou pressione F4, clique no botão da barra de ferramentas do evento para visualizar os eventos no objeto Form, encontre o evento FormClosing no grupo Behavior e clique duas vezes nele. Referência: 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;
}
}
se a condição será executada quando o usuário clicar no 'X' ou no botão Fechar no formulário. O else pode ser usado quando o usuário clica em Alt + f4 para qualquer outra finalidade
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
}
}
}
}
Eu concordo com a DialogResult
-Solution como a mais direta.
No VB.NET, no entanto, o typecast é necessário para obter o 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
Também tive que registrar a função de fechamento dentro do método "InitializeComponent ()" do formulário:
private void InitializeComponent() {
// ...
this.FormClosing += FrmMain_FormClosing;
// ...
}
Minha função "FormClosing" é semelhante à resposta fornecida ( 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");
}
}
Mais uma coisa a mencionar: há também uma função "FormClosed" que ocorre após "FormClosing". Para usar esta função, registre-a conforme mostrado abaixo:
this.FormClosed += MainPage_FormClosed;
private void MainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}