Ответ 1
Некоторые перегрузки метода MessageBox.Show()
принимают в качестве первого аргумента параметр IWin32Window
. Если вы передадите форму в качестве первого аргумента, это должно помешать этому.
Некоторые из наших нетехнических пользователей сталкиваются с проблемами, когда диалог MessageBox в нашем приложении иногда может отображаться за основной формой, и приложение не принимает никаких ввода до тех пор, пока сообщение (которое они не видят) будет уволено.
Приложение написано на С#, а окна сообщений являются стандартными, например, код может быть таким же простым, как MessageBox.Show(сообщение, подпись) и сообщениями могут быть созданы с помощью основного потока пользовательского интерфейса (то есть не какого-либо фонового потока). Приложение не нужно запускать полноэкранным, но 90% наших пользователей запускают его на весь экран.
В большинстве случаев ((возможно, > 99%) сообщения отображаются правильно, и я никогда не видел, как это происходит неправильно, но я видел машину, когда она пошла не так.
Одна вещь, которую я заметил, это то, что если у вас есть приложение, которое отображает диалоговое окно, то при просмотре вашего диспетчера задач вы обычно видите только одну запись в списке приложений. Всякий раз, когда ящик сообщений скрыт, вы увидите две записи: одну для основного приложения и другую запись для этого окна сообщений.
Легко решить проблему, как только вы знаете, что произошло, но некоторые из наших нетехнических пользователей запутались в этом и в конечном итоге отключили свои компьютеры. (И те, кто использует Remote Desktop, еще более запутаны, если это не решает проблему).
Я не думаю, что это связано с операционной системой, поскольку я видел это в Vista, и мне сказали, что это также происходит в терминальном сеансе на сервере Windows 2003.
Знаете ли вы, почему это происходит, и что еще важнее, если что-то можно сделать, чтобы избежать этого?
Некоторые перегрузки метода MessageBox.Show()
принимают в качестве первого аргумента параметр IWin32Window
. Если вы передадите форму в качестве первого аргумента, это должно помешать этому.
Является ли это всегда одним и тем же полем сообщений (для одного и того же сообщения?), которое появляется в той же форме?
В идеале вы должны попытаться найти способ воспроизвести проблему по своему усмотрению или, по крайней мере, автоматически. Это упростит вашу отладку, и вы можете быть уверены, что ваши будущие изменения исправят ошибку, а не придется ждать нескольких недель для отзывов ваших пользователей.
Если это всегда одно и то же сообщение и в том же окне, в результате одного и того же действия, и если вызов MessageBox можно легко запускать с точки зрения пользователя, и если ваш пользовательский интерфейс является относительно стандартным, вы можете автоматизировать пользовательский интерфейс с AutoIT script и запустить его в цикле до тех пор, пока не возникнет проблема.
И/или вы могли бы создать "отладочную" -стройку своих приложений, которую вы могли бы дать ее некоторым пользователям (предпочтительно тем, которые чаще всего сталкиваются с проблемой), которые будут писать содержимое StackFrame объект в файл журнала или что-то подобное каждый раз перед вызовом MessageBox (вы можете создать обертку вокруг MessageBox, чтобы сделать это проще).
Затем, когда у одного из ваших пользователей возникнет проблема, вы можете посмотреть файл журнала и посмотреть, откуда он взялся (файл исходного кода, строка, стек вызовов и т.д.). Вы также можете сравнить это с журналами от других пользователей и посмотреть, если каждый раз MessageBox приходит из того же места или изменяется. Это покажет вам, откуда вызывается проблемный MessageBox и где.
Могут быть более простые решения (особенно если ваше приложение имеет множество сборок) с участием некоторого отладчика .Net, который вы присоедините к своему приложению, когда возникнет проблема, чтобы увидеть стек вызовов и т.д., но я сделал это только с собственными приложениями (с использованием OllyDbg) до сих пор, а не .Net. Другие могут еще больше расширить эту идею...
Подтвердите проблему. Что мы делаем, чтобы исправить это следующее:
ОБНОВЛЕНО 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;
}
Вы говорите: "ящики сообщений могут быть созданы с помощью основного потока пользовательского интерфейса", который, как я полагаю, означает, что они не всегда создаются основным потоком пользовательского интерфейса. Ваша проблема звучит так: MessageBox.Show
иногда вызывается из другого потока.
В родительской форме добавьте это до MessageBox.Show()
:
this.TopMost = false;