![](/img/trans.png)
[英]window.ShowDialog stackoverflowexception reasons. WPF
[英]C# WPF Window.ShowDialog stack overflow exception
令人驚訝的是,通過重復異步調用Window.ShowDialog可能導致堆棧溢出異常。
public MainWindow()
{
InitializeComponent();
TheCallDelegate = TheCall;
_timer = new DispatcherTimer();
_timer.Tick += _timer_Tick;
_timer.Start();
}
DispatcherTimer _timer = null;
void _timer_Tick(object sender, EventArgs e)
{
_timer.Dispatcher.BeginInvoke(TheCallDelegate);
}
Action TheCallDelegate;
void TheCall()
{
Window win = new Window();
win.ShowDialog();
}
如您所見,這里沒有實際的遞歸(或者應該沒有),但是一旦發生異常,您可以看到調用堆棧確實已滿。 為什么? 也可以不使用計時器來實現,例如:
private async void Button_Click(object sender, RoutedEventArgs e)
{
while (true)
{
this.Dispatcher.BeginInvoke(TheCallDelegate);
await Task.Delay(1);
}
}
PS:您在此處看到的代碼是專門為說明問題而構造的,因此不要着重於為什么有人會這樣做。 該問題的目的是了解為什么ShowDialog會以這種方式運行。
正如您應該能夠看到堆棧跟蹤一樣,每次對ShowDialog()
調用都會將新幀推送到堆棧上。 由於您多次調用ShowDialog()
而不關閉,因此每次調用都會增加堆棧深度,並且堆棧最終會溢出。
發生這種情況是因為與Show()
方法不同, ShowDialog()
直到關閉顯示的窗口才返回。 這與任何其他方法調用一樣工作,因此會導致堆棧增長。 由於ShowDialog()
必須響應用戶輸入,因此它將啟動新的Dispatcher循環。 由於分派器仍在運行,因此計時器會不斷觸發並打開新的嵌套對話框。
因此,在很高的層次上,您的調用堆棧將如下所示:
...Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
隨着新對話框的打開,它將最終溢出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.