问题
Some of our non-technical users are having problems where a dialog MessageBox in our application can sometimes be displayed behind the main form and the application does not accept any input until the messagebox (which they can't see) is dismissed.
The application is written in C# and the message boxes are standard eg the code can be as simple as MessageBox.Show(message, caption) and the messageboxes can be created by the main UI thread (ie not some background thread). The Application does not have to be run full-screen, but 90% of our users do run it full-screen.
Most of the time ((maybe > 99%) the messageboxes display correctly and I have never managed to see how it goes wrong, but I have seen a machine when it has gone wrong.
One thing I did notice is that if you have an application which displays a dialog box, then when you look at your taskmanager, you normal only see one entry in the application list. Whenever the messagebox is hidden, you will see two entries, one for the main application and another entry for this message box.
It is easy enough to fix the problem once you know what has happened, but some of our non-technical users are confused by it and end up switching off their computers. (And the ones who are using Remote Desktop are even more confused when that doesn't solve the problem).
I do not think it is related to the operating system as I have seen it happen in Vista and have been told it also happens in a terminal session on a Windows 2003 server.
Does anything know why this is happening and more importantly if anything can be done to avoid it?
回答1:
Some overloads of the MessageBox.Show()
method take an IWin32Window
parameter as the first argument. If you pass in your Form as that first argument it should prevent this from happening.
回答2:
Is it always the same message box (for the same message?) coming the same form?
Ideally, you should try to find some way to reproduce the problem at will, or at least automatically. This will make your debugging easier and you can then be sure that your future change will have fixed the bug, rather than have to wait for a few weeks for the feedback from your users.
If it is always the same message and in the same window, resulting from the same action, and if the MessageBox call is reasonably easy to trigger from an user point-of-view and if your UI is relatively standard, you could automate the UI with an AutoIT script and have it run in a loop until the problem happens.
And/or, you could create a "debug"-build of your applications that you could give it to some users (preferably the ones that seem to run into the problem the most often) that would write the contents of a StackFrame object to a log file or something similar everytime before calling a MessageBox (you could create a wrapper around the MessageBox to make this easier).
Then, when one of your users gets the problem, you can look at the log file and see where it came from (source code file, line, calls stack etc). You could also compare this to the logs from other users and see if, everytime, the MessageBox comes from the same location or if it varies. This would show you where the problematic MessageBox is called from and where.
There may be easier solutions (especially if your application has a lot of assemblies) involving some .Net debugger that you would attach to your application when the problem occurs in order to see the call stack, etc, but I only did this with native applications (using OllyDbg) so far and not .Net. Others may be able to expand further on this idea...
回答3:
Confirm the problem. What we do to fix it is following:
- Run new Task and display the message box
- In the main UI thread while task is still running - wait in the loop that does DoEvents. Something like this
UPDATED 2015-12-17. Reproduced problem yestarday. To repo in my case - minimize the app, "wait" popup occures (in our case it happens after some idle time), then in the task bar click on the main app icon. This "hides" the popup so it is not possible to bring it on the screen. The code below was tested and solves the problem. But I still do not understand what/why it happens.
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:
You say "the messageboxes can be created by the main UI thread", which I assume means they aren't always created by the main UI thread. Your problem sounds like MessageBox.Show
is occasionally called from another thread.
回答5:
In the parent form, add this before MessageBox.Show()
:
this.TopMost = false;
来源:https://stackoverflow.com/questions/3467403/dialog-messagebox-sometimes-hidden-behind-the-main-form