Executing code when my form is closed - c#

My program makes some changes in the registry while it's running, and if they are not properly rolled back, they might cause the user some problems. FOr example, they might not be able to use their Internet connection.
So I need to make sure that when they close the application, I return everything back to normal. To do this, I need to know when they have pressed the Close button of the form. How can I do that? Is there an event that I can handle?

There is an event you can subscribe to called FormClosing this fire before FormClose and allows you to validate/change the settings you need before the form closes
public Form1()
{
InitializeComponent();
FormClosing += Form1_FormClosing;
}
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Reset values
}

I think that what you need is not access to the close button, but rather access to the event which is fired when the form is closed.
Taken from this previous SO post, what you might need is something like so:
void FormClosed(object sender, FormClosedEventArgs e)
{
// do something useful
}

There are more possibilites here.
1) Use the FormClosing event of the form:
private void form_FormClosing(object sender, FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing) { // User clicked 'X' button
if (someThing) e.Cancel = true; // Disable Form closing
}
}
2) You can also hide the 'X' button by set ControlBoxto false. But this will also hide the minimize and maximize buttons.
3) This disables only the 'X' button. Place it in your form.
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams {
get {
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CP_NOCLOSE_BUTTON;
return cp;
}
}

Related

Closing Form with X or created button

I have a Log In form and I need to know if user pressed the X button on form or the button that takes him to the new form. If user closed the program with Alt+F4 or X button the program must be closed.
I was trying with FormClosing event to check whether user pressed X or login.
private void LogIn_FormClosing(object sender, FormClosingEventArgs e)
{
if (string.Equals((sender as Button).Name, #"loginButton"))
{
//some code
}
else
{
Close();
}
}
The FormClosing event handler receives a FormClosingEventArgs argument that contains the property CloseReason, but in your context this is not enough.
Indeed, in both cases (ALT+F4/X-Click or ButtonClick) the argument will contain a CloseReason equal to UserClosing.
I suggest you a simple workaround. In your button click handler (where you should call the close action on the form, not on the formclosing event handler itself), add something to the Tag property of the form like so:
private void Button1_Click(object sender, EventArgs e)
{
this.Tag = "ClosedByUser";
this.Close();
}
now in the FormClosing event handler is simple to check this property
private void LogIn_FormClosing(object sender, FormClosingEventArgs e)
{
if (this.Tag != null)
{
// Button clicked
}
else
{
// other reasons
// Dp not call Close here, you are already closing
// if you don't set e.Cancel = true;
}
}

Hide Windows form from everywhere (taskbar, task switcher, etc)

I have Windows Application form I need to hide Form on form_Load event and it should be hidden from task bar and also from task switcher (i.e. when I press Alt + Tab). means it would not be showing anywhere .
So you should try this:
public void Form1_Load(object sender, EventArgs e)
{
ShowInTaskbar = false;
Hide();
}
ShowInTaskbar indicates wether your Form should appear in the task bar.
To hide it from Alt+Tab I found this solution on StackOverflow:
protected override CreateParams CreateParams
{
get
{
var Params = base.CreateParams;
Params.ExStyle |= 0x80;
return Params;
}
}
Simply overwrite the CreateParams property of your Form as shown above.
UPDATE The order of events when opening a Form leads to the problem that your visibility is restored after the Load event. So you will need to overwrite something like this:
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
// if you still want to hide
Hide();
}

Track closing event of windows form with validation of button clicked in the form

I have a form which contains a close button (there are many control in the form, but I am concerning about the close event) and a save button.
If a form have value in certain text box (say TextBox1),
Then I want to validate that the save button is clicked before closing the form (whether close button or the 'X' button at top is pressed).
But if there is no value in that text box or the form is just initialized and user just want to close the form, it simply closes the form. How to perform this validation.
I would follow the pattern of 99% of windows applications: allow to close a window, but ask to save changes if there are any. Here is a simple implementation of that pattern:
private bool _hasChanges;
private void textBox1_TextChanged(object sender, EventArgs e)
{
this._hasChanges = true;
}
private void form_FormClosing(object sender, FormClosingEventArgs e)
{
if (this._hasChanges)
{
var dialogResult = MessageBox.Show("Save changes?", "Confirm", MessageBoxButtons.YesNoCancel);
switch (dialogResult)
{
case DialogResult.Yes:
this.Save();
break;
case DialogResult.No:
this._hasChanges = false;
break;
}
e.Cancel = this._hasChanges;
}
}
private void Save()
{
// Save
this._hasChanges = false;
}
private void buttonSave_Click(object sender, EventArgs e)
{
this.Save();
}
private void buttonOk_Click(object sender, EventArgs e)
{
this.Close();
}
private void buttonCancel_Click(object sender, EventArgs e)
{
this._hasChanges = false;
this.Close();
}
The pivotal part is the boolean _hasChanges. If there are many controls that can cause changes this can be real pain. An alternative could be to use databinding to a class that implements INotifyPropertyChanged and subscribe to its PropertyChanged event.
Tie into the Closing Event and use your EventHandler to validate that textbox. Keep in mind that Closing occurs at the time the form is closing and (if memory servers correctly) there is a property on the eventarg that will let you cancel closing of the form. This event is raised regardless of how the request is executed.

How to know user has clicked "X" or the "Close" button?

In MSDN I found CloseReason.UserClosing to know that the user had decided to close the form
but I guess it is the same for both clicking the X button or clicking the close button.
So how can I differentiate between these two in my code?
Thanks all.
Assuming you're asking for WinForms, you may use the FormClosing() event. The event FormClosing() is triggered any time a form is to get closed.
To detect if the user clicked either X or your CloseButton, you may get it through the sender object. Try to cast sender as a Button control, and verify perhaps for its name "CloseButton", for instance.
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.
}
Otherwise, I have never ever needed to differentiate whether X or CloseButton was clicked, as I wanted to perform something specific on the FormClosing event, like closing all MdiChildren before closing the MDIContainerForm, or event checking for unsaved changes. Under these circumstances, we don't need, according to me, to differentiate from either buttons.
Closing by ALT+F4 will also trigger the FormClosing() event, as it sends a message to the Form that says to close. You may cancel the event by setting the
FormClosingEventArgs.Cancel = true.
In our example, this would translate to be
e.Cancel = true.
Notice the difference between the FormClosing() and the FormClosed() events.
FormClosing occurs when the form received the message to be closed, and verify whether it has something to do before it is closed.
FormClosed occurs when the form is actually closed, so after it is closed.
Does this help?
The CloseReason enumeration you found on MSDN is just for the purpose of checking whether the user closed the app, or it was due to a shutdown, or closed by the task manager, etc...
You can do different actions, according to the reason, like:
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
}
But like you guessed, there is no difference between clicking the x button, or rightclicking the taskbar and clicking 'close', or pressing Alt F4, etc. It all ends up in a CloseReason.UserClosing reason.
The "X" button registers as DialogResult.Cancel so another option is to evaluate the DialogResult.
If you have multiple buttons on your form, you're probably already associating different DialogResults to each and this will provide you with the means to tell the difference between each button.
(Example: 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;
}
}
}
How to detect if the form closed by click on X button or by calling Close() in code?
You cannot rely on close reason of the form closing event args, because:
if the user click X button on title bar or
close the form using Alt + F4 or
use system menu to close the form or
the form get closed by calling Close() method,
for all of above cases, the close reason will be Closed by User (CloseReason.UserClosing), which is not desired result.
To distinguish if the form closed by X button or by Close method, you can use either of the following options:
Handle WM_SYSCOMMAND and check for SC_CLOSE and set a flag.
Check the StackTrace to see if any of the frames contain Close method call.
Example 1 - Handle 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()");
}
Example 2 - Checking 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");
}
It determines when to close the application if a form is closed (if your application is not attached to a specific form).
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
if (Application.OpenForms.Count == 0) Application.Exit();
}
I always use a Form Close method in my applications that catches alt + x from my exit Button, alt + f4 or another form closing event was initiated. All my classes have the class name defined as Private string mstrClsTitle = "grmRexcel" in this case, an Exit method that calls the Form Closing Method and a Form Closing Method. I also have a statement for the Form Closing Method - this.FormClosing = My Form Closing Form Closing method name.
The code for this:
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;
}
}
}
}
}
You can try adding event handler from design like this: Open form in design view, open properties window or press F4, click event toolbar button to view events on Form object, find FormClosing event in Behavior group, and double click it.
Reference: https://social.msdn.microsoft.com/Forums/vstudio/en-US/9bdee708-db4b-4e46-a99c-99726fa25cfb/how-do-i-add-formclosing-event?forum=csharpgeneral
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
}
}
}
}
if (this.DialogResult == DialogResult.Cancel)
{
}
else
{
switch (e.CloseReason)
{
case CloseReason.UserClosing:
e.Cancel = true;
break;
}
}
if condition will execute when user clicks 'X' or close button on form. The else can be used when user clicks Alt+f4 for any other purpose
I agree with the DialogResult-Solution as the more straight forward one.
In VB.NET however, typecast is required to get the 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
I also had to register the closing function inside the form's "InitializeComponent()" method:
private void InitializeComponent() {
// ...
this.FormClosing += FrmMain_FormClosing;
// ...
}
My "FormClosing" function looks similar to the given answer (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");
}
}
One more thing to mention: There is also a "FormClosed" function which occurs after "FormClosing". To use this function, register it as shown below:
this.FormClosed += MainPage_FormClosed;
private void MainPage_FormClosing(object sender, FormClosingEventArgs e)
{
// your code after the form is closed
}
I've done something like this.
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if ((sender as Form).ActiveControl is Button)
{
//CloseButton
}
else
{
//The X has been clicked
}
}

C# Validate before leaving accept_button event

Excuse me if this is a silly question but i'm a beginer here.
I have a simply custom dialog with two buttons: Accept and Cancel. The Accept button is the acceptButton of the form.
I want to do some validations on the Accept_Click event and decide if i can close the dialog or not, but everytime it leaves this method, the dialog automatically closes itself and returns Ok.
What can I do to stop the dialog from closing itself? or i have to do things in some other way?
thanks
I would have a form level variable (call it _vetoClosing) In the accept button's Click event, I would run validation and set the variable based on that:
private void acceptButton_Click(object sender, EventArgs e)
{
// Am I valid
_vetoClosing = !isValid();
}
Then in the FormClosing event, I would cancel close if _vetoClosing is true
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
// Am I allowed to close
if (_vetoClosing)
{
_vetoClosing = false;
e.Cancel = true;
}
}
Turning Accept button off is suboptimal because you loose the Enter to Press functionality.
A cleaner solution would be to set DialogResult to None:
private void acceptButton_Click(object sender, EventArgs e)
{
if (!isValid()) {
this.DialogResult = System.Windows.Forms.DialogResult.None;
}
}
I would validate as the controls change, and only enable the Accept button if the whole form is valid.
This would allow you to keep your button as the default button (AcceptButton), but prevent this from occurring.
Is the AcceptButton or CancelButton on the form set to that button? If so, try unsetting it and manually setting DialogResult in your handler when you want to close the dialog.

Categories

Resources