2017-02-16 38 views
2

我们创建了一个新表单,我们通过ShowDialog显示并添加了一个“取消”按钮。以下是我们从其父开放形式:为什么FormClosing在模态对话框中调用Hide()时会触发两次?

// _modalForm is a class-level instance of our ModalForm class 
var result = _modalForm.ShowDialog(this); 
MessageBox.Show(result.ToString()); 

这里的取消按钮的Click事件处理程序ModalForm

private void btnCancel_Click(object sender, EventArgs e) 
{ 
    Close(); 
} 

在我们FormClosing情况下,我们有这样的代码(基于this answer)。

private void ModalForm_FormClosing(object sender, FormClosingEventArgs e) 
{ 
     e.Cancel = true; 
     Hide(); 
     _parentForm.RefreshData(); 
} 

出人意料的是,当我们点击“取消”按钮(或在窗体的顶部使用“X”按钮),该FormClosing事件引发两次。 CloseReason两次都是UserClosing

我再次检查以确保InitializeComponent不会被调用两次,而且我们只订阅该事件一次。 btnCancel未在表格的CancelButton属性中设置。它也没有在设计器中设置DialogResult。当我检查返回值ShowDialog虽然,它被设置为DialogResult.Cancel

更改btnCancel_Click仅仅是DialogResult = DialogResult.Cancel而不是Close()并在FormClosing事件无所事事,除了_parentForm.Refresh()解决该事件的问题得到两次上调。

有没有人知道为什么在这种特殊情况下,FormClosing事件会重复两次?

+2

你在帮助太多。当你关闭它时,对话框已经隐藏起来,所以你不必调用Hide()并且不需要e.Cancel = true。你真正想要完成的是防止它被丢弃。没有需要帮助,它已经做到了。您可以简单地再次调用Show()以使其再次可见。相反,任何*确实*的对话需要完全消除需要明确的Dispose()调用。总是最容易用*使用*语句完成。 –

+0

@HansPassant好的。上面的代码是一个重现此问题的示例应用程序。遇到此问题的实际应用程序不使用“使用”块,而是在父表单的类级变量中保留对表单的引用。我修改了我的问题以删除'using'块。 –

回答

3

这是因为隐藏模式表单会导致它以DialogResult.Cancel作为对话结果关闭。因此,如果您在FormClosing事件中致电this.Hide(),事件将再次提高。

想象一下,如果它没有关闭窗体,你的应用程序就被隐藏的模态窗体阻止了!

注:答案描述了两次提高事件的原因。但是,如here和其他人所述,对于模态窗体(您使用ShowDialog显示),Dispose方法将不会被调用,窗体在关闭后存在,您可以使用其属性获取某些数据,或者可以再次显示它。所以你不需要调用隐藏方法。

欲了解更多信息,看一看:Do I need to Dispose a Form after the Form got Closed?

+1

另请参阅[我需要在表单关闭后处理表单吗?](http://stackoverflow.com/a/39501121/3110834) –

+1

答案描述了两次提升事件的原因。但正如上面提到的链接和其他人所述,*对于模态窗体(您使用ShowDialog显示的窗体),Dispose方法将不会被调用,并且窗体在关闭之后存在,您可以使用其属性获取某些数据,或者可以显示它再次。*所以你不需要调用隐藏方法。 –

1

你提到的解决方法是不必要的,因为在关闭时模式对话框没有布置。它们被设计为在关闭之后保留它们的数据(因为它是模态对话的调用者所要求的),并且在需要时被重用。

只要让它正确关闭即可。它不会对模态对话造成伤害:)

请注意,这也意味着,与常规形式不同,您必须手动处理模态对话框(如果它们不是持久的)。在你的场景中,这很可能意味着当父表单被处置时你想要抛弃对话框(如果你将对话框添加为组件,但是需要手动完成,则会自动发生)。

相关问题