Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 594
rory.ap Avatar asked Dec 14 '17 21:12

rory.ap


4 Answers

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.

like image 168
Hans Passant Avatar answered Sep 30 '22 09:09

Hans Passant


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.

like image 23
Omar Muscatello Avatar answered Sep 30 '22 08:09

Omar Muscatello


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();
}
like image 42
Pavan Chandaka Avatar answered Sep 30 '22 09:09

Pavan Chandaka


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
    }
}
like image 39
habib Avatar answered Sep 30 '22 07:09

habib