当子窗体关闭时,为什么不对主窗体中创建的窗体上的控件触发Validated事件?

问题描述 投票:5回答:4

假设我有一个winforms应用程序,有两个表单,即程序运行时启动的主表单,以及另一个表单。以下是主窗体的代码:

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!"); 
    }
}

这是儿童形式:

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    private void textBox1_Validated(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.Print("Child Form: Validated!");  
    }
}

当我运行应用程序时,我可以将焦点放在主窗体上的文本框中,当然,当我标签出来时,它会触发Validated事件并将Main Form: Validated!打印到输出。如果我将焦点放在文本框中并关闭主窗体(即结束程序),也会发生这种情况。

当我单击主窗体上弹出子窗体实例的按钮时,我可以将焦点放在子窗体的文本框中,并且当我跳出它时,Validated事件会触发。但是,与关闭表单时的主要表单行为不同,如果我将焦点放在子表单上的文本框中并关闭子表单,则Validated事件永远不会触发。

为什么验证事件不会触发,有没有办法可以解雇它。

我依靠某些控件的验证事件来更新我的视图模型。我想确保即使丢失焦点是由于表格关闭甚至应用程序本身结束,它们也总是会触发。

c# .net winforms events
4个回答
10
投票

这是由ShowDialog()引起的。这是一个记录在案的错误,.NET 1.x中的一个错误,它们无法再修复。来自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. :-(

所以只需按照指导:

    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);
    }

假设您在解除对话框时不需要该事件,并且您希望在验证失败时对话框保持打开状态。后一个条款是新行为。


4
投票

Documentation说:

与非模态窗体不同,当用户单击对话框的关闭窗体按钮或设置DialogResult属性的值时,.NET Framework不会调用Close方法。而是隐藏表单,并且可以在不创建对话框的新实例的情况下再次显示该表单。

根据文档,当你调用第二种形式的ShowDialog方法(Form2)并通过单击关闭按钮(窗体右上角带有X的按钮)关闭它时,表单被隐藏(不是关闭)。这就是为什么Validated事件永远不会发生的原因。

注意:无论如何,ClosingClosed事件都会发生。

注意2:使用ALT + F4关闭表单与单击表单的X按钮相同。


示范

Form as modal (your example)

第二种形式是通过调用ShowDialog打开的。在第二个表单上添加一个按钮,并将click事件设置如下:

private void button1_Click(object sender, EventArgs e)
{
    this.Close();
}

如果您通过单击该新按钮关闭表单,则会触发Validated事件。如果通过单击表单右上角带有X的按钮来关闭表单,则Validated事件将不会触发(因为表单从未关闭,它已被隐藏)。

Form as non-modal

第二种形式是通过调用Show打开的。在这种情况下,当您单击窗体右上角带有X的按钮时,后者将真正关闭(不隐藏)并触发Validated事件。


Workaround

Hiding the ControlBox

最简单的方法是隐藏将ControlBox属性设置为false的表单的X按钮(由设计人员或代码)。但是,用户可以使用ALT + F4关闭表单。

Using Hans Passant solution

希望明确。


1
投票

如果你愿意,你所有的模态对话框控件都会被验证,而关闭..可能你可以接近以下方式......这肯定会激活文本框验证事件。

在Form2中添加表单结束事件并调用ValidateChildren()

private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
    this.ValidateChildren();
}

1
投票

MSN Documentation

根据MSN文档如果CausesValidation属性设置为false,则抑制Validating和Validated事件。

通过导致验证和验证事件发生来验证控件失去焦点的值:根据MSN文档

您还可以使用失去控件焦点的Validate()方法来触发Validating和Validated事件。因此,您可以在Form2的结束事件中调用Validate方法。贝娄是代码

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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.