0

我有 ac#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;
                }
            }
4

1 回答 1

3

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

看到对话框由另一个线程而不是您的 UI 线程拥有,这是您尝试调试的那种麻烦的一个很好的解释。当您在非 STA 线程上运行 shell 对话框时,它们会变得不稳定。有时您会遇到异常,但并不一致。只是未能出现的对话框确实是一种明显的可能性,我已经看到这种情况发生了。使用调试器的 Debug + Windows + Threads 查看调用堆栈,找出发生这种情况的原因。

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

于 2013-10-24T16:41:20.247 回答