【问题标题】:Why isn't the Validated event firing for controls on a form created in the main form when the child form is closed?为什么当子窗体关闭时,在主窗体中创建的窗体上的控件没有触发 Validated 事件?
【发布时间】:2017-12-14 21:27:25
【问题描述】:

假设我有一个带有两个窗体的 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 事件永远不会触发。

为什么验证的事件不触发,有没有办法让它触发。

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

【问题讨论】:

  • 子窗体上有多少个控件?只是文本框?如果添加例如,行为是否保持不变子窗体的按钮?
  • 它也有一个按钮,我可以通过它跳出文本框并触发Validated 事件。
  • 如果你 Show() 它而不是 ShowDialog() 怎么样?
  • 是的,Show 工作正常。但我需要一个模态表单。

标签: c# .net winforms events


【解决方案1】:

这是由 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);
    }

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

【讨论】:

    【解决方案2】:

    Documentation 说:

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

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

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

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


    演示

    形式为模态(您的示例)

    通过调用ShowDialog 打开第二个表单。 在第二个表单上添加一个按钮,并设置点击事件如下:

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

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

    非模态形式

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


    解决方法

    隐藏控制框

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

    使用Hans Passant solution

    希望清楚。

    【讨论】:

      【解决方案3】:

      如果你愿意,你所有的模态对话框控件都经过验证,而关闭.. 可能你可以采用下面的方式.... 这肯定会触发文本框验证事件。

      在Form2中添加表单关闭事件并调用ValidateChildren()

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

      【讨论】:

        【解决方案4】:

        MSN Documentation

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

        通过导致 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
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多