Подтвердить что ты не робот

Есть ли неблокирующая версия MessageBox.Show(или что-то в этом роде)?

Долгосрочное обновление

Я принимаю 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) и не блокирует. Но мне было просто интересно, существует ли что-то подобное, о котором я не знал.

4b9b3361

Ответ 1

Для выполнения этой задачи вам необходимо использовать многопоточность, в которой один поток (основной поток) будет выполнять обработку, а другой поток будет использоваться для отображения сообщения.

Ответ 2

Как насчет добавления NotifyIcon в ваше приложение и отображения наконечник шара? Нижняя сторона заключается в том, что уведомление исчезнет через короткое время, но, возможно, это будет лучше для ваших пользователей, если им не нужно предпринимать действия.

Есть больше предложений по этому вопросу.

Ответ 3

Что бы я попробовал, вызовите функцию MessageBox из Win32 API напрямую, например:

using System.Runtime.InteropServices;

[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);

Попробуйте использовать нулевой дескриптор и тип APPLMODAL. Это может сработать.

Ответ 4

Это старый вопрос, но nevertheles...

1) Импорт IWshShell ('Windows Script Модель объекта хоста')

Dim wsh As New IWshRuntimeLibrary.WshShell       msgstr "                                      Application.ExecutablePath), 0.75," Заголовок", MessageBoxButtons.OKCancel или MessageBoxIcon.Question)

Jens...