C# WPF Window.ShowDialog 堆栈溢出异常

标签 c# wpf stack-overflow showdialog

令人惊讶的是,重复异步调用 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);
        }
    }

附言您在此处看到的代码是专门为说明问题而构建的,因此不要关注为什么有人会这样做。该问题的目的是了解为什么 ShowDialog 会以这种方式运行。

最佳答案

您应该能够看到堆栈跟踪,每次调用 ShowDialog() 都会将新帧插入堆栈。由于您在没有关闭的情况下多次调用 ShowDialog(),因此每次调用都会增加堆栈深度,并且堆栈最终会溢出。

发生这种情况是因为与 Show() 方法不同,ShowDialog() 在它显示的窗口关闭之前不会返回。这与任何其他方法调用一样工作,因此它会导致堆栈增长。由于 ShowDialog() 必须响应用户输入,因此它会启动一个新的 Dispatcher 循环。由于 Dispatcher 仍在运行,您的计时器会不断触发并打开新的嵌套对话框。

因此,在非常高的层次上,您的调用堆栈将如下所示:

...Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...
TheCall
ShowDialog
... Dialog Dispatcher Loop...

随着新对话框的打开,它最终会溢出。

关于C# WPF Window.ShowDialog 堆栈溢出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33110195/

相关文章:

c# - WPF 中的预测键入功能

java - 适用于 Android 的 Canny 边缘检测器——关于递归函数的 StackOverflow

c# - Unity Networking : Unity crashes when I call the NetworkManager. singleton.StopClient() 函数

c# - Linq 2 Sql DateTime 格式为字符串 yyyy-MM-dd

c# - 如何在 .NET 库中读取从 VB6 IDE 传递的命令行参数?

c# - 什么会导致 Application_Error 不被调用?

c# - 如果属性值没有变化,是否可以从 IValueConverter 进行 "cancel"依赖属性赋值?

javascript - 如何使用asp.net c#将使用jsPDF生成的PDF附加到邮件中

c# - 运算符 '=='不能应用于 'Thickness'和 'string'类型的操作数

java - Java 正则表达式中的堆栈溢出