How to Override standard close (X) button in a Windows Form - c#

How do I go about changing what happens when a user clicks the close (red X) button in a Windows Forms application (in C#)? I want to add a simple DialogResult and Messagebox to ask user if he's sure about closing the form.

You should handle the FormClosing event on the Form class. In the handler, you are able to set the value of the CancelEventArgs.Cancel property to true to prevent closure of the form.
Example:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Close?", "Close", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
e.Cancel = true;
}
You can create the handler method by double-clicking the event in the Properties tab while the Windows Forms designer is open:
See https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.form.formclosing?view=windowsdesktop-6.0

Related

How to prevent keystroke in child form reaching parent form?

I have a form that, upon user request, opens a child form, like so --
private void toolTrim_Click(object sender, EventArgs e)
{
Form form = new TrimOptions();
form.ShowDialog();
if (form.DialogResult == DialogResult.OK)
{
//code;
}
{
This child form has a button called btnOk and its property AcceptButton set to btnOk. This means that, when the Enter key is pressed in the child form, it's as if you had clicked on the Ok button, and this code executes.
private void btnOk_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Save();
DialogResult = DialogResult.OK;
Close();
}
The problem is that, when the child form closes, the Enter key that was used to close the child form is captured by the DataGridView in the parent form.
private void filesDataGridView_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Return) //execution stops here if breakpointed
There's a legitimate use for that, but only when the DGV has focus, not when some child form of this form has focus.
So, how to prevent keystrokes in a child form from "bubbling up" to a parent form?
Following Steve's advice, I removed the Close(); having learned that setting DialogResult to any value other than None will close the window.
Following Hans Passant's advice to use KeyDown instead of KeyUp, I realized I had a mixture of KeyDowns and KeyUps. He was also correct, of course, that indeed the DGV had focus. I made them all KeyDowns, and my problem went away.
the other solution would be before opening modal you can disable the parent form once dialog is closed you can enable the parent form, so key up event does not fire.

Why isn't the Validated event firing for controls on a form created in the main form when the child form is closed?

Say I have a winforms application with two forms, the main form that starts up when the program runs, and another form. Here is the code for the main form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var f2 = new Form2();
f2.ShowDialog();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Main Form: Validated!");
}
}
And this is the child form:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Child Form: Validated!");
}
}
When I run the application, I can put the focus in the textbox on the main form, and of course when I tab out, it fires the Validated event and prints Main Form: Validated! to the output. This also happens if I have the focus in the textbox and close the main form (i.e. end the program).
When I click the button on the main form which pops up an instance of the child form, I can put the focus in the textbox on the child form, and the Validated event fires as it should when I tab out of it. However, unlike the main form behavior on closing the form, if I have the focus in the textbox on the child form and I close the child form, the Validated event never fires.
Why doesn't the validated event fire, and is there a way I can make it fire.
I'm relying on the validated event of certain controls to update my view models. I want to make sure they always fire even when the loss of focus is due to a form closing or even the application itself ending.
This is caused by ShowDialog(). It is a documented bug, a mistake in .NET 1.x that they could not fix anymore. From the Form.cs source code:
// NOTE: We should also check !Validate(true) below too in the modal case,
// but we cannot, because we didn't to this in Everett (bug), and doing so
// now would introduce a breaking change. User can always validate in the
// FormClosing event if they really need to. :-(
So just follow the guidance:
protected override void OnFormClosing(FormClosingEventArgs e) {
if (e.CloseReason == CloseReason.UserClosing && this.DialogResult != DialogResult.Cancel) {
if (!base.Validate(true)) e.Cancel = true;
}
base.OnFormClosing(e);
}
With the assumptions that you don't need the event when the dialog is dismissed and you'd want the dialog to stay open when validation fails. The latter clause is new behavior.
Documentation says:
Unlike non-modal forms, the Close method is not called by the .NET
Framework when the user clicks the close form button of a dialog box
or sets the value of the DialogResult property. Instead the form is
hidden and can be shown again without creating a new instance of the
dialog box.
Based on the docs, when you call the ShowDialog method of the second form (Form2) and you close it by clicking on the close button (the button with an X at the upper-right corner of the form) the form is hidden (not closed). This is why the Validated event never fires.
Note: Closing and Closed events will fire anyway.
Note2: Closing the form using ALT + F4 is the same as clicking on the X button of the form.
Demonstration
Form as modal (your example)
The second form is opened by calling ShowDialog.
Add a button on the second form and set the click event as follow:
private void button1_Click(object sender, EventArgs e)
{
this.Close();
}
If you close the form by clicking in that new button the Validated event will fire. If you close the form by clicking the button with an X at the upper-right corner of the form, the Validated event won't fire (because the form has never closed, it has been hidden).
Form as non-modal
The second form is opened by calling Show.
In this case, when you click the button with an X at the upper-right corner of the form the latter will be really closed (not hidden) and the Validated event fires.
Workaround
Hiding the ControlBox
The simplest method is to hide the X button of the form setting the ControlBox property to false (by designer or by code). However, the user could close the form using ALT + F4.
Using Hans Passant solution
Hope to be clear.
If you want, all your modal dialog controls validated, while closing .. probably you can approach below way.... which definitely fires the text box validated event.
Add an event for form closing in Form2 and call ValidateChildren()
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
this.ValidateChildren();
}
MSN Documentation
According to MSN Documentation If the CausesValidation property is set to false, the Validating and Validated events are suppressed.
Verifies the value of the control losing focus by causing the Validating and Validated events to occur :According to MSN Documentation
You can also fired Validating and Validated events by using Validate() method that lose the focus of controls. So you can call Validate method within closing event of Form2. Bellow is the code
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void textBox1_Validated(object sender, EventArgs e)
{
System.Diagnostics.Debug.Print("Child Form: Validated!");
}
private void Form2_Closing(object sender, FormClosingEventArgs e)
{
if (!Validate())
//Write your code that will execute if your form is not validated
}
}

Close form using the cross button

I'm working on a C# project. I need to do the following but I'm not really experienced and I can't find it on the Internet.
I want to do an action when the user clicks on the cross button (for closing one form). I mean, if the user clicks on the "X" button on the top right of the form I want to use a method that deletes one file.
I just want to know the code for noticing that the user clicked on the "X" (close) button. I hope you guys understand my question. Thank you so much!!
I don't think it's user friendly to delete something on closing a form (especially as the 'X' button is understood as the close button by everybody who uses a computer), but you can override the OnFormClosing method of a form. Something like this:
// this will also close the form
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (e.CloseReason == CloseReason.WindowsShutDown) return;
// Do some stuff here (delete the file or whatever)
}
If you want to alter the behavior so bad that the form won't close on pressing 'X', you could do sth like
protected override void OnFormClosing(FormClosingEventArgs e)
{
e.Cancel = true;
// some stuff here...
}
Which is very nasty IMO
You have to handle FormClosing event:
The FormClosing event occurs as the form is being closed. When a form
is closed, it is disposed, releasing all resources associated with the
form. If you cancel this event, the form remains opened. To cancel the
closure of a form, set the Cancel property of the FormClosingEventArgs
passed to your event handler to true.

Strange behaviour with dialog box belonging to dialog box

I have a form that I use the ShowDialog() method to bring up so the user can't change control back to the main form, and on the sub form I have a MessageBox.Show() method call which returns a DialogResult.
Only problem is, no matter what the dialog result of the message box, it causes my sub form to close. Is there a behaviour I am overlooking or is there something the matter with my code?
The code in the main form to open the sub form:
private void btnScanFree_Click(object sender, EventArgs e)
{
frmScan scanForm = new frmScan();
scanForm.ShowDialog();
}
And the code in the cancel button click method on the sub form:
private void btnCancel_Click(object sender, EventArgs e)
{
if (dgvScannedItems.RowCount > 0)
{
DialogResult dr = MessageBox.Show("There are scanned items that have not been inserted to the database. Are you sure you want to go back?", "Go Back", MessageBoxButtons.YesNo);
if (dr == System.Windows.Forms.DialogResult.Yes)
{
this.Close();
}
}
else
{
this.Close();
}
}
On the sub form, if there are no rows in the data grid view, then the form should close, otherwise a message box should appear with yes and no buttons and a question asking the user if they want to continue closing the form. But whether they press yes or no, it closes both the message box (which it always should) and the sub form (which half the time it should not).
BtnCancel is a dialog Button and sets DialogResult of the form to cancel or no or something similar. Since you have opened the form as a dialog via ShowDialog setting the DialogResult Causes the form to close and return the result.
So you need to set the DialogResult property of the BtnCancel to nothing to prevent this "starnge" behaviour.
Why not add a watch on dgvScannedItems.RowCount and see what the value is?

Save MdiChildren on Application exit

I would like to store some data about open MdiChildren to restore them when the application restarts.
But the MdiChildren property seems to empty on the ApplicationExit event.
Which event do I listen to to be able to get a list of open MdiChildren when user closes the main window?
try following code. It works for me. you can put additional loginc in If to check if any child window is visible ot not and if not then don't ask any question.
private void MDIParent1_FormClosing(object sender,
FormClosingEventArgs e)
{
if (MessageBox.Show("Close?",
AppDomain.CurrentDomain.ToString(), MessageBoxButtons.YesNo) ==
DialogResult.No)
{
e.Cancel = true;
}
}

Categories

Resources