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.
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).
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.
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
.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With