【问题标题】:Dialog MessageBox sometimes hidden behind the main form对话框 MessageBox 有时隐藏在主窗体后面
【发布时间】:2010-08-12 12:04:41
【问题描述】:

我们的一些非技术用户遇到的问题是,我们的应用程序中的对话框 MessageBox 有时会显示在主窗体后面,并且应用程序不接受任何输入,直到消息框(他们看不到)被关闭。

应用程序是用 C# 编写的,消息框是标准的,例如代码可以像 MessageBox.Show(message, caption) 一样简单,消息框可以由主 UI 线程(即不是一些后台线程)创建。应用程序不必全屏运行,但我们 90% 的用户确实会全屏运行。

大多数时候((可能 > 99%)消息框正确显示,我从来没有设法看到它是如何出错的,但我看到一台机器出错了。

我注意到的一件事是,如果您有一个显示对话框的应用程序,那么当您查看任务管理器时,您通常只会在应用程序列表中看到一个条目。每当消息框被隐藏时,您都会看到两个条目,一个用于主应用程序,另一个用于此消息框。

一旦您知道发生了什么,就很容易解决问题,但是我们的一些非技术用户对此感到困惑并最终关闭了他们的计算机。 (如果这不能解决问题,使用远程桌面的人会更加困惑)。

我不认为它与操作系统有关,因为我在 Vista 中看到过这种情况,并且被告知它也发生在 Windows 2003 服务器上的终端会话中。

有没有人知道为什么会发生这种情况,更重要的是是否可以采取任何措施来避免这种情况?

【问题讨论】:

  • 我在使用 WPF 时遇到了同样的问题。有些东西可以触发对话框和主窗口之间的关系,即使没有指定,这种关系通常存在,也会被破坏。提供一个 Window 作为第一个参数解决了这个问题。为了重新创建它,我在 VS 调试器中运行了应用程序。处于活动状态的调试器似乎经常破坏这种关系。您可以判断问题已经发生,因为该对话框将在任务栏上获得自己的条目。

标签: c# winforms messagebox


【解决方案1】:

MessageBox.Show() 方法的一些重载将IWin32Window 参数作为第一个参数。如果您将表单作为第一个参数传递,它应该可以防止这种情况发生。

【讨论】:

  • +1 用于指定父窗口。 OP 的问题很可能意味着消息框有一个 null 父级(即桌面窗口),有时这个窗口会在后台结束。
  • 有没有办法确定消息框的父级是什么(在运行时和在客户的机器上)?
【解决方案2】:

是否总是相同的消息框(对于相同的消息?)以相同的形式出现?

理想情况下,您应该尝试找到某种方法来随意重现问题,或者至少是自动重现。这将使您的调试更容易,然后您可以确保您未来的更改将修复该错误,而不必等待几周的用户反馈。

如果它始终是相同的消息并在相同的窗口中,由相同的操作产生,并且如果从用户的角度来看 MessageBox 调用相当容易触发,并且如果您的 UI 相对标准,您可以使用 AutoIT 脚本自动化 UI,并让它循环运行,直到问题发生。

并且/或者,您可以为您的应用程序创建一个“调试”版本,您可以将它提供给一些用户(最好是那些似乎最常遇到问题的用户),这些用户将编写 @ 的内容987654322@ 对象到日志文件或类似的东西每次调用 MessageBox 之前(您可以在 MessageBox 周围创建一个包装器以使这更容易)。

然后,当您的一位用户遇到问题时,您可以查看日志文件并查看它的来源(源代码文件、行、调用堆栈等)。您还可以将其与其他用户的日志进行比较,看看 MessageBox 是否每次都来自相同的位置或是否不同。 这将向您显示有问题的 MessageBox 是从哪里调用的以及从哪里调用的。

可能有更简单的解决方案(特别是如果您的应用程序有很多程序集)涉及一些 .Net 调试器,当问题发生时您可以将其附加到您的应用程序以查看调用堆栈等,但我只这样做了到目前为止,使用本机应用程序(使用 OllyDbg)而不是 .Net。其他人也许可以进一步扩展这个想法......

【讨论】:

  • 它并不总是相同的消息,并且可以从程序的不同部分创建消息框。但是,我最后一次看到该消息时,我从消息中知道它是从哪里调用的。尝试自动化的问题是我认为外部因素已经到位。当它第一次被报告时,我认为这可能是由于用户最小化应用程序以在另一个程序上工作以及在应用程序被最小化时创建的消息框引起的。但是如果我这样做,每当我切换回我的应用程序时,消息框也会显示在前面。
  • 如果您已经排除了线程假设,我认为您可能需要排除尽可能多的常见嫌疑人。您是否尝试在原始机器(或 VM)上运行您的应用程序?不确定它在您的环境中有多实用,但是,尽管很少见,但实用程序或其他软件在某些时候试图窃取焦点或导致 Windows 发生一些奇怪的事情并非不可能。此外,您似乎从未亲眼目睹过这个错误。
  • 另外,如果您的用户是内部员工,并且准备好接受它,您可以记录他们的屏幕,以便在下次出现问题时看到他们给您打电话时发生的情况。也就是说,他们被观察到的事实本身可能会引入一些奇怪的安慰剂效应(例如,如果用户在您的应用程序处理某些内容时访问网站,并且他们知道您可以观看录音就不再去了)。跨度>
【解决方案3】:

确认问题。我们要解决的问题如下:

  1. 运行新任务并显示消息框
  2. 在主 UI 线程中,当任务仍在运行时 - 在执行 DoEvents 的循环中等待。像这样的

2015 年 12 月 17 日更新。 昨天重现问题。在我的情况下回购 - 最小化应用程序,出现“等待”弹出窗口(在我们的例子中,它发生在一些空闲时间之后),然后在任务栏中单击主应用程序图标。这会“隐藏”弹出窗口,因此无法将其显示在屏幕上。下面的代码已经过测试并解决了问题。但我仍然不明白这是什么/为什么会发生。

    private static DialogResult ShowMessageBox(
        string message, 
        string caption, 
        MessageBoxButtons buttons, 
        MessageBoxIcon icon)
    {

        var showMessageBoxTask = new Task<DialogResult>(() =>
        {
            var form = new Form() {TopMost = true};

            var result = MessageBox.Show(
                form,
                PrepareMessage(message),
                caption,
                buttons,
                icon);

            form.Dispose();

            return result;
        });

        showMessageBoxTask.Start();

        while (!showMessageBoxTask.IsCompleted && !showMessageBoxTask.IsFaulted)
        {
            Application.DoEvents();
        }

        return showMessageBoxTask.Result;
    }

【讨论】:

    【解决方案4】:

    您说“消息框可以由主 UI 线程创建”,我认为这意味着它们并不总是由主 UI 线程创建。您的问题听起来像是偶尔从另一个线程调用MessageBox.Show

    【讨论】:

    • 不,我的意思是,虽然有时它发生在后台线程创建的消息框上,但它也发生在肯定由主 UI 线程创建的消息框上。跨度>
    • 你的表格中有没有什么时髦的东西?像 PInvoking SetWindowPos 或类似的东西?
    • 没有。唯一常见的事情是 ShowInTaskbar 在实际显示主窗体之前设置为 false,同时显示启动画面并初始化程序。 ShowInTaskbar 在 Mainform Load 事件结束时设置为 true。
    • 发生此问题时,您在任务管理器中看到两个条目这一事实意味着消息框未从您的 UI 线程中显示(或其他一些奇怪的事情正在发生)。跨度>
    • 我确定它是从我的 UI 线程调用的,但我同意你的看法,有些奇怪正在发生。我还怀疑消息框一开始是正确链接的,后来不知何故链接丢失了。我这么说是因为我认为(但不是 100% 肯定)当他们从使用另一个应用程序切换回我们的应用程序时会出现问题。
    【解决方案5】:

    在父表单中,在MessageBox.Show()之前添加:

    this.TopMost = false;
    

    【讨论】:

    • 请说明你的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多