代码之家  ›  专栏  ›  技术社区  ›  Jordi

在Windows窗体中关闭模式窗体的计时器

  •  -1
  • Jordi  · 技术社区  · 6 年前

    我有几个带网格的无模式表单,可以在MDI Windows表单应用程序中显示数据( Form1 在示例代码中)。每个表单都有一个按钮,可以使用 ShowDialog ( Form2 在示例代码中),允许编辑中显示的数据 表格1 。这些模式表单有一个“取消”按钮,通过设置关闭表单而不保存更改 DialogResult Cancel

    我想实现一个计时器,在用户登录应用程序经过一定时间后关闭所有表单。如果在模式窗体打开时计时器触发,则会出现问题。

    public partial class Form1 : 
    { //Constructor ommited for brevity
        private void btnEditData_Click(object sender, EventArgs e)
        {
            var form2 = new Form2();
            timer1.Tick += (_, __) =>
            {
                form2.DialogResult = DialogResult.Cancel;
                this.Close(); // this executes before form2.ShowDialog returns
            };
            timer1.Interval = 5_000;
            timer1.Enabled = true;
            form2.ShowDialog();
            reloadData(); // here Form1 is already disposed because Close 
            // has been called on it. An exception is thrown as a consequence
        }
    
        private void reloadData()
        {
            if (this.IsDisposed)
                // simulate using a disposed form
                throw new ObjectDisposedException(this.Name); 
        }
    }
    

    我的目的是安排通话时间 Form1.Close() 之后 form2.ShowDialog() 已返回,并且 btnEditData_Click 方法已完成,因此不会有使用已处理表单的危险。

    1 回复  |  直到 6 年前
        1
  •  1
  •   CynicalSection    6 年前

    编辑 看到代码后,我建议在Tick事件处理程序中引入第三个选项,用于决定是否必须关闭表单。例如 Abort

     timer1.Tick += (_, __) =>
        {
            form2.DialogResult = DialogResult.Abort;
        };
    if (form2.ShowDialog() == DialogResult.Abort) Close();    
    else reloadData();
    

    第一个想法:保持简单,保持干净。您不必跟踪打开的表单,在MDI应用程序中 MdiChildren 将为您提供所有表单的父表单的属性。 然后,要处理结束部分,可以使用中的现有功能。网

    1. 一个困难的方法是使用 P/Invoke 。加载Windows DLL并使用其函数枚举所有窗体,然后关闭所需的窗体。您还可以模拟单击取消按钮。你必须从 EnumWindows 功能(识别表单)和 EnumChildWindows 为了form的孩子。我喜欢这个选项,因为您可以完全控制表单和控件,但如果不熟悉这个概念,可能会让您头疼。
    2. 您可以查看FormClosing事件并订阅它。此事件在关闭窗体之前激发,您可以使用它进行清理。
    3. 使用OOP-继承和重写。您可以创建一个带有自定义关闭函数的基本表单来进行清理(然后通过它继承所有表单),或者重写表单的关闭函数来实现您的目标。