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

Замедленное обновление

Я принимаю ответ MUG4N на этот вопрос, и я также хочу ответить на некоторые критические замечания, которые были повышены против него.

ChrisF заявил:

... Вы не можете выполнить вызовы UI непосредственно от фоновых потоков.

Это - общий оператор и не на 100% верно. Позвольте мне просто указать на несколько фактов:

  1. Можно на самом деле выполнить вызовы UI все, что Вы хотите, если Вы устанавливаете Control.CheckForIllegalCrossThreadCalls = false. "Ack!" Я слышу, что Вы говорите. "Никогда не делайте этого!" Да, Да - но почему? Ответ: потому что иногда это будет повреждать память.

    Классы управления в System.Windows.Forms не записаны, чтобы быть ориентированным на многопотоковое исполнение, поэтому иногда обновление их от фоновых потоков может повредить память. Но если это только иногда происходит и не всегда, что это говорит мне, то, что это не вызов кода UI по сути, а скорее потенциально небезопасная коллизия кода UI, который может вызвать исключения.

  2. Для подтверждения точки зрения 1 рассмотрите это: "безопасный" способ вызвать код UI от фонового потока состоит в том, чтобы сделать настолько использующий Control.Invoke или Control.BeginInvoke, право? Но это - вызов UI; это - просто вызов UI, который мы, как предполагается, выполняем, если мы обновляем GUI от потока не-GUI. То, что я имею в виду, ясно, это просто не вызывает метода на a Control объект от внешнего потока, это собирается вызвать хаос (если бы это имело место, то мы не могли даже звонить Invoke и мы застряли бы полностью). Снова, это - потенциальная коллизия отдельных вызовов UI, которые не могут безопасно произойти одновременно, который окажется разрушительным.

  3. При хранении вышеупомянутых двух точек в памяти, спросите себя: почему было бы небезопасно звонить MessageBox.Show от потока не-GUI? Абсолютно отдельное Form создан и отображен; его свойства ни в коем случае не взаимодействуют ни с каким другим существующим объектом GUI; на самом деле к этому нельзя получить доступ нигде никаким способом, за исключением одного: от вызывающего потока, который получает доступ к DialogResult свойство (и только это через Show возвращаемое значение метода).

Прохождение. Conrad Albrecht сказал:

... учитывая утверждение, которое Шоу () настраивает свой собственный насос сообщения в ref'd теме Dan, (который не был доказан, но который я не могу опровергнуть)...

Это - полностью справедливое замечание (хотя я лично сдерживаюсь, Jared Par достаточно высоко уважают это, я обычно не был бы склонен сомневаться относительно того, что он говорит). В любом случае, быстрый взгляд на MessageBox.Show метод через Отражатель показывает этот отрывок:

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 низшего уровня, чтобы полностью понять этот код, но это, кажется, мне доказательство точно, что Jared говорил в ответе, на который я сослался в своем старом комментарии (для любопытных читателей: Делает MessageBox. Показать () автоматически Маршалл к Потоку UI?).

Так, да. Я полностью в согласии с MUG4N на этом.

(Если кто-либо может убедительно утверждать, что я все еще ошибаюсь здесь, говорите. Хотя я чувствую, что сделал довольно хороший случай для того, почему я полагаю, что MUG4N является правильным, я, очевидно, не на 100% уверен.)


Исходный вопрос

Часто Вы просто хотите уведомить пользователя, что что-то произошло, но нет действительно никакой потребности ни в каком входе от них. В этом общем сценарии я иногда вижу код как это:

MessageBox.Show("Something has occurred", "Something", MessageBoxButtons.OK);

Этот код, как все мы знаем, заставляет немного всплывающего окна появляться только с кнопкой OK. Теперь вот вещь: это блоки кода (поток UI). Но в подавляющем большинстве случаев, мне, кажется, если у Вас только есть кнопка OK, существует очень мало потребности заблокироваться. (Не цель заблокироваться обычно для получения некоторого входа от пользователя? И если единственный выбор пользователя "в порядке" в этом типичном случае, разве блокирование не довольно бессмысленно?)

Очевидно, я мог просто записать свою собственную небольшую форму, которая делает в основном точно что MessageBox.Show делает, за исключением того, что это ничего не возвращает (нет DialogResult) и не блокируется. Но я просто задавался вопросом, существует ли что-то вроде этого уже, что я не знал о.

31
задан Community 23 May 2017 в 10:31
поделиться

3 ответа

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

11
ответ дан 27 November 2019 в 22:49
поделиться

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

using System.Runtime.InteropServices;

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

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

2
ответ дан 27 November 2019 в 22:49
поделиться

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

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

7
ответ дан 27 November 2019 в 22:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: