WPF:所有者窗口被程序关闭后ShowDialog()不返回致应用挂起
WPF应用挂起原因分析
先把你的代码贴出来方便梳理:
private void MainWindow_Loaded(object sender, RoutedEventArgs e) { var window1 = new TestWindow(); window1.Show(); var timer = new Timer(); timer.Interval = TimeSpan.FromSeconds(3).TotalMilliseconds; timer.Elapsed += (s, e1) => Application.Current.Dispatcher.BeginInvoke((Action) (() => window1.Close())); timer.Start(); var window2 = new TestWindow(); window2.Owner = window1; window2.ShowDialog(); }
咱们一步步拆解导致应用挂起的核心问题:
执行流程的冲突点:
你启动window1(非模态窗口)后,又创建了window2并把window1设为它的Owner,随后调用window2.ShowDialog()——这个方法会阻塞当前的UI线程,直到window2被关闭。同时你设置了3秒后关闭window1的定时器。Owner窗口关闭的连锁反应:
3秒后定时器触发,通过Dispatcher异步调用关闭window1。在WPF中,当一个窗口的Owner被关闭时,系统会自动关闭所有以它为Owner的子窗口,也就是window2会被自动关闭。挂起的根源:
window2.ShowDialog()在MainWindow的UI线程上处于阻塞等待状态,但window2的关闭操作是通过异步的Dispatcher调用触发的。当window2被强制关闭时,它需要完成ShowDialog()的收尾逻辑(比如返回DialogResult、释放相关资源),但此时UI线程的消息循环因为“阻塞等待”和“异步关闭”的冲突,陷入了无法正常推进的状态,最终导致整个应用挂起。
如果要验证这个结论,你可以做两个小测试:
- 把
window2.ShowDialog()改成window2.Show()(非模态),挂起现象会消失 - 调整定时器逻辑,先关闭
window2再关闭window1,也能避免挂起
内容的提问来源于stack exchange,提问作者adrian h.




