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



我有几个带有网格的无模式窗体,用于在MDI Windows窗体应用程序中显示数据(Form1示例代码)。这些表单中的每一个都有一个按钮,该按钮使用ShowDialog打开另一个表单作为模态(在示例代码中Form2),这允许编辑Form1中显示的数据。这些模式表单有一个"取消"按钮,该按钮通过将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); 
}
}

我的目的是在form2.ShowDialog()返回并且btnEditData_Click方法完成后以某种方式安排调用Form1.Close(),这样就不会有使用已处理表单的危险。

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

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

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

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

最新更新