我们的一些非技术用户遇到问题,我们的应用程序中的对话框有时会显示在主窗体后面,并且应用程序不接受任何输入,直到消息框(他们看不到)被取消。
应用程序是用C#编写的,消息框是标准的,例如代码可以像MessageBox.Show(消息,标题)一样简单,消息框可以由主UI线程创建(即不是某些后台线程)。应用程序不必全屏运行,但90%的用户都会全屏运行。
大多数时候((可能> 99%)消息框显示正确,我从未设法看到它出错了,但我看到机器出错了。
我注意到的一件事是,如果你有一个显示对话框的应用程序,那么当你查看你的任务管理器时,你只能看到应用程序列表中的一个条目。每当隐藏消息框时,您将看到两个条目,一个用于主应用程序,另一个用于此消息框。
一旦你知道发生了什么事情就很容易解决问题,但是我们的一些非技术用户对此感到困惑并最终关闭了他们的计算机。 (而那些使用远程桌面的人在解决问题时更加困惑。)
我不认为它与操作系统有关,因为我已经看到它发生在Vista中并且被告知它也发生在Windows 2003服务器上的终端会话中。
有什么事情可以知道为什么会发生这种情况,更重要的是,如果可以做任何事情来避免它吗?
答案 0 :(得分:20)
MessageBox.Show()
方法的一些重载采用IWin32Window
参数作为第一个参数。如果您将表单作为第一个参数传递,则应该防止这种情况发生。
答案 1 :(得分:1)
它是否始终是相同的消息框(对于相同的消息?)来自相同的形式?
理想情况下,您应该尝试找到一种方法来随意重现问题,或至少自动重现问题。这将使您的调试更容易,然后您可以确保您的未来更改将修复错误,而不必等待几周的时间来收集用户的反馈。
如果它始终是相同的消息并且在同一窗口中,由相同的操作产生,并且如果从用户的角度来看相当容易触发MessageBox调用,并且如果您的UI是相对标准的,那么您可以使用AutoIT脚本自动化UI,让它在循环中运行,直到问题发生。
和/或,你可以创建一个“调试” - 你的应用程序的构建,你可以把它给一些用户(最好是那些似乎最常遇到问题的用户)写一个{的内容{3}}在调用MessageBox之前每次对象都是一个日志文件或类似的东西(你可以在MessageBox周围创建一个包装器来使这更容易)。
然后,当您的某个用户遇到问题时,您可以查看日志文件并查看其来源(源代码文件,行,调用堆栈等)。您还可以将此与来自其他用户的日志进行比较,并查看每次MessageBox是来自同一位置还是来自不同。 这将显示调用有问题的MessageBox的位置和位置。
可能有更简单的解决方案(特别是如果你的应用程序有很多程序集)涉及一些.Net调试器,你会在出现问题时附加到你的应用程序,以便查看调用堆栈等,但我只是这样做了到目前为止使用本机应用程序(使用OllyDbg)而不是.Net。其他人可能会进一步扩展这个想法...
答案 2 :(得分:1)
确认问题。我们采取以下措施来解决这个问题:
2015-12-17更新。 转载问题yestarday。在我的情况下回购 - 最小化应用程序,"等待"弹出窗口(在我们的例子中它发生在一些空闲时间之后),然后在任务栏中单击主应用程序图标。这"隐藏"弹出窗口,因此无法将其带到屏幕上。下面的代码经过测试并解决了问题。但我仍然不明白它是什么/为什么会发生。
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;
}
答案 3 :(得分:0)
你说“消息框可以由主UI线程创建”,我认为这意味着它们并不总是由主UI线程创建。您的问题听起来似乎偶尔从另一个线程调用MessageBox.Show
。
答案 4 :(得分:-1)
在父窗体中,将其添加到MessageBox.Show()之前:
this.TopMost = false;