表单在收听FormClosed事件后不立即关闭

时间:2014-02-12 05:24:02

标签: c# winforms events

我有两个窗体。我使用Form.Show()从第一个表单上单击按钮调用第二个表单。我希望在表单关闭后显示一个消息框。我订阅了FormClosed事件,但表单仅在显示消息框后关闭。

出现这种情况的原因是什么?

private void button1_Click(object sender, EventArgs e)
{
    Form2 fr2 = new Form2();
    fr2.FormClosed += new FormClosedEventHandler(fr2_FormClosed);
    fr2.Show(); 
}  

void fr2_FormClosed(object sender, FormClosedEventArgs e)
{
    MessageBox.Show("second form closed");
}

1 个答案:

答案 0 :(得分:2)

这是因为事件在表单从屏幕上移除之前触发,MessageBox.Show(阻塞,直到您按下确定按钮。

这是来自.NET框架的反编译源代码,用于处理表单关闭的私有函数WmClose

private void WmClose(ref Message m)
{
      //Snip...

      FormClosedEventArgs e3 = new FormClosedEventArgs(this.CloseReason);
      this.OnClosed((EventArgs) e3);
      this.OnFormClosed(e3);
      base.Dispose();
}

protected virtual void OnFormClosed(FormClosedEventArgs e)
{
  Application.OpenFormsInternalRemove(this);
  FormClosedEventHandler closedEventHandler = (FormClosedEventHandler) this.Events[Form.EVENT_FORMCLOSED];
  if (closedEventHandler == null)
    return;
  closedEventHandler((object) this, e); //This line is what calls fr2_FormClosed
}

在调用base.Dispose()之前,表单仍然可以在屏幕上显示,并且代码不会从this.OnFormClosed(e3);返回,直到您的代码从fr2_FormClosed返回。

最简单的解决方法是通过BeginInvoke(

将消息框放在消息队列中来推迟显示消息框
void fr2_FormClosed(object sender, FormClosedEventArgs e)
{
    this.BeginInvoke(new Action(() =>
    {
        MessageBox.Show("second form closed");
    }));
}

现在将显示消息框的操作放到消息泵队列上并继续关闭Form2的工作,一旦完成关闭它将在消息队列中查找更多工作要做然后显示消息框。