Ответ 1
Для выполнения этой задачи вам необходимо использовать многопоточность, в которой один поток (основной поток) будет выполнять обработку, а другой поток будет использоваться для отображения сообщения.
Я принимаю MUG4N ответ на этот вопрос, и я также хочу ответить на некоторые из критических замечаний, которые были высказаны против него.
ChrisF сказал:
... вы не можете делать UI-вызовы непосредственно из фоновых потоков.
Это пустой оператор и не является 100% истинным. Позвольте мне указать на несколько фактов:
Фактически вы можете сделать UI-вызовы, если вы установите Control.CheckForIllegalCrossThreadCalls = false
. "Ack!" Я слышу, как ты говоришь. "Не никогда делать это!" Да, да - но почему? Ответ: поскольку иногда это приведет к повреждению памяти.
Контрольные классы в System.Windows.Forms
не записываются в потокобезопасные, поэтому иногда их обновление из фоновых потоков может привести к повреждению памяти. Но если это случается иногда и не всегда, то это говорит о том, что это не вызов кода пользовательского интерфейса как такового, а скорее потенциально опасное столкновение кода пользовательского интерфейса, которое может вызывать исключения.
Чтобы укрепить точку 1, рассмотрите это: "безопасный" способ вызвать код пользовательского интерфейса из фонового потока - это сделать с помощью Control.Invoke
или Control.BeginInvoke
, правильно? Но это вызов пользовательского интерфейса; это просто вызов пользовательского интерфейса, который мы должны сделать, если мы обновляем графический интерфейс из потока, отличного от GUI. Я имею в виду, что это не просто вызов "любого" метода для объекта Control
из внешнего потока, который может вызвать хаос (если это так, то мы не могли даже позвонить Invoke
, и мы полностью застрял). Опять же, это потенциальное столкновение отдельных вызовов пользовательского интерфейса, которые не могут безопасно происходить одновременно, что окажется деструктивным.
Удерживая вышеуказанные две точки, спросите себя: почему было бы небезопасно вызывать MessageBox.Show
из потока без GUI? Создается и отображается полностью отдельный Form
; его свойства никоим образом не взаимодействуют с каким-либо другим существующим объектом GUI; на самом деле он не может быть доступен нигде каким-либо образом, кроме одного: из вызывающего потока, который обращается к свойству DialogResult
(и только это через возвращаемое значение метода Show
).
Перемещение. Конрад Альбрехт сказал:
... учитывая утверждение, что Show() устанавливает свой собственный насос сообщений в теме Dan ref'd (что не было обосновано, но которое я не могу опровергнуть)...
Это совершенно справедливый вопрос (хотя я лично лично занимаю Джареда Пар с достаточно высоким уважением, что я, как правило, не склонен сомневаться в том, что он говорит). В любом случае, просмотр в MessageBox.Show
методе Reflector показывает этот фрагмент:
Application.BeginModalMessageLoop();
try
{
result = Win32ToDialogResult(SafeNativeMethods.MessageBox(new HandleRef(owner, zero), text, caption, type));
}
finally
{
Application.EndModalMessageLoop();
UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
}
Еще один взгляд на метод Application.BeginModalMessageLoop
показывает это:
ThreadContext.FromCurrent().BeginModalMessageLoop(null);
И это ThreadContext.FromCurrent
, в свою очередь:
// [Reflector shows that currentThreadContext is a ThreadStatic member. -Dan]
if (currentThreadContext == null)
{
currentThreadContext = new Application.ThreadContext();
}
return currentThreadContext;
Я не знаю достаточно об этих конструкциях Windows нижнего уровня, чтобы полностью понять этот код, но это, как мне кажется, является доказательством того, что Джаред говорил в ответ, на который я ссылался в своем старом комментарии (для любопытных читателей: Создает ли MessageBox.Show() автоматически маршалл для потока пользовательского интерфейса?).
Итак, да. Я полностью согласен с MUG4N на этом.
(Если кто-то может убедительно утверждать, что я все еще ошибаюсь здесь, пожалуйста, сообщите об этом. Хотя я чувствую, что сделал довольно хороший аргумент в пользу того, почему я считаю, что MUG4N прав, я, очевидно, не на 100% уверен.)
Часто вы просто хотите уведомить пользователя о том, что что-то произошло, но на самом деле нет необходимости в их вводе. В этом распространенном сценарии я иногда вижу такой код:
MessageBox.Show("Something has occurred", "Something", MessageBoxButtons.OK);
Этот код, как мы все знаем, вызывает появление небольшого всплывающего окна только с кнопкой ОК. Теперь вот что: этот код блокирует (поток пользовательского интерфейса). Но в подавляющем большинстве случаев мне кажется, что если у вас есть кнопка ОК, очень мало нужно блокировать. (Не является ли целью блокировки обычно получать некоторый ввод от пользователя? И если выбор пользователя только "ОК" в этом типичном случае не блокирует довольно бессмысленно?)
Очевидно, я мог бы написать свою собственную небольшую форму, которая в основном выполняет именно то, что делает MessageBox.Show
, за исключением того, что он ничего не возвращает (no DialogResult
) и не блокирует. Но мне было просто интересно, существует ли что-то подобное, о котором я не знал.
Для выполнения этой задачи вам необходимо использовать многопоточность, в которой один поток (основной поток) будет выполнять обработку, а другой поток будет использоваться для отображения сообщения.
Как насчет добавления NotifyIcon в ваше приложение и отображения наконечник шара? Нижняя сторона заключается в том, что уведомление исчезнет через короткое время, но, возможно, это будет лучше для ваших пользователей, если им не нужно предпринимать действия.
Есть больше предложений по этому вопросу.
Что бы я попробовал, вызовите функцию MessageBox из Win32 API напрямую, например:
using System.Runtime.InteropServices;
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
Попробуйте использовать нулевой дескриптор и тип APPLMODAL. Это может сработать.
Это старый вопрос, но nevertheles...
1) Импорт IWshShell ('Windows Script Модель объекта хоста')
Dim wsh As New IWshRuntimeLibrary.WshShell msgstr " Application.ExecutablePath), 0.75," Заголовок", MessageBoxButtons.OKCancel или MessageBoxIcon.Question)
Jens...