为什么 C# OpenFileDialogs 是在主 GUI 线程之外创建的

本文关键字:线程 创建 GUI OpenFileDialogs 为什么 | 更新日期: 2023-09-27 18:36:41

我有一个偶尔挂起的 c# winforms 应用程序,有人告诉我我们应该确保我们不会在主 GUI 线程上打开任何窗口。我启动了 Spy++ 并注意到,当我们在客户端会话开始时打开 OpenFileDialog 时,该对话框存在于另一个线程上,即使代码路径在主 GUI 线程上运行也是如此。

然后,在窗口关闭后,窗口仍显示在 Spy++ 中,显示为在工作线程上。即使我们将 OpenFileDialog 的使用包含在 using 语句中,也会发生这种情况。因此,处理对话似乎实际上并没有摆脱窗口,这很奇怪。

这是实际代码

                if (filename == String.Empty)
            {
                using (var openFileDialog = new OpenFileDialog
                    {
                        Filter = string.Format(MessageStrings["DialogFormat"]),
                        Title = MessageStrings["OpenDialogTitle"]
                    })
                {
                    if (openFileDialog.ShowDialog() != DialogResult.OK || openFileDialog.FileName == String.Empty)
                        return false;
                    filename = openFileDialog.FileName;
                }
            }

为什么 C# OpenFileDialogs 是在主 GUI 线程之外创建的

不,在正常使用中,对话框肯定归 UI 线程所有。 我没有看到您在使用 Spy++ 时报告的内容的证据。 我在 SO 这里写了几个答案,以使用对话框提取技巧,这些技巧只有在 UI 线程拥有对话框窗口时才能工作。 请注意,OpenFileDialog会创建大量窗口,因此很容易迷失在Spy++视图中。 关闭对话框后看到窗口仍然存在很容易解释,您必须使用窗口 + 刷新来强制 Spy++ 更新快照。

否则,查看由 UI 线程以外的其他线程拥有的对话框可以很好地解释您尝试调试的那种问题。 当您在非 STA 线程上运行 shell 对话框时,它们会变得片状。 有时您会收到异常,但它并不一致。 对话框只是没有出现确实是一种明显的可能性,我已经看到这种情况发生了。 使用调试器的调试 + 窗口 + 线程查看调用堆栈,找出发生这种情况的原因。

启用非托管调试可以让您看到更多内容,但请注意,shell 对话框本身会添加大量线程。 您将所有 shell 扩展加载到您的进程中,它们具有运行自己的线程的诀窍。 这些扩展本身就是一个长期的麻烦来源,使用SysInternals的自动运行通过禁用它们来诊断。