Ответ 1
РЕДАКТИРОВАТЬ: полный вопрос переписан, я неправильно понял оригинальный вопрос
Позвольте обобщить проблему: элемент управления или компонент, на который у вас нет контроля, может вызвать FlashWindow
(функцию API Win32), чтобы привлечь внимание пользователя. Вы этого не хотите.
Для этого обычно существуют два решения: использовать API-соединение или перехват сообщений. Поскольку API-соединение является сложным и привлекательным, я представлю решение для соединения с сообщениями.
FlashWindow
Microsoft не объясняет так много слов, что делает FlashWindow
. К сожалению, он не отправляет определенное сообщение (скажем WM_FLASH
или подобное), что облегчило бы захват и отмену этого поведения. Вместо этого FlashWindow
выполняет три функции:
- Он устанавливает системный таймер для интервалов мигания
- Он отправляет сообщение
WM_NCACTIVATE
для первой вспышки - Он отправляет сообщение
WM_NCACTIVATE
, когда таймер истекает (при приемеWM_SYSTIMER
)
В зависимости от того, как компонент вызывает FlashWindow, это может быть неопределенным, пока не произойдет другой тайм-аут, пока он не сфокусируется или только один раз. Каждое сообщение WM_NCACTIVATE активирует или деактивирует NC-зону (панель заголовка, кнопка на панели задач). Он не меняет вход фокуса.
Вызов
Любое решение для предотвращения мигания немного связано. Основные проблемы:
- событие
WM_SYSTIMER
отправляется асинхронно с PostMessage и не принимается методомWndProc
формы (он обрабатывает только синхронные сообщения) - Сообщения
WM_NCACTIVATE
также используются, когда пользователь нажимает кнопку заголовка или кнопку панели задач, чтобы установить фокус ввода, просто отмена этих сообщений будет иметь нежелательные побочные эффекты. - FlashWindow всегда будет мигать, по крайней мере, один раз, независимо от стрельбы
WM_SYSTIMER
или нет.
Сообщение WM_SYSTIMER
недокументировано. Он имеет значение 0x0118
и вовремя используется Windows во время таких вещей, как мигание каретки, задержка в открытии меню и т.д. Здесь он используется для времени между вспышками.
Решение
Решение, представленное здесь, является основой для дальнейшего развития. Это не полное решение, но оно решает проблему во многих случаях. В поле формы введите следующее:
protected override void WndProc(ref Message m)
{
bool messageHandled = false;
if (m.Msg == WM_NCACTIVATE)
{
// add logic here to determine user action, losing focus etc and set
// messageHandled and m.Result only when user action is not the cause
// of triggering WM_NCACTIVATE
m.Result = IntPtr.Zero;
messageHandled = true;
}
if(!messageHandled)
base.WndProc(ref m);
}
Вышеупомянутый код уже предотвращает полное мигание. Вам нужно будет добавить некоторую логику для изменения строки заголовка, потому что полное игнорирование WM_NCACTIVATE
означает, что заголовок будет выглядеть все активнее, даже если это не так.
Следующий код дает вам больше контроля. Вы можете использовать его, чтобы реагировать на мигание. Обычно основное окно не принимает события WM_SYSTIMER
так часто, но вам придется экспериментировать, следует ли делать исключения. Кажется, что для FlashWindow
параметр wParam
всегда установлен в 0xFFF8
, но экспериментируйте с ним, поскольку это нигде не документировано.
public class MyMessageFilter : IMessageFilter
{
// an application can have many windows, only filter for one window at the time
IntPtr FilteredHwnd = IntPtr.Zero;
public MyMessageFilter(IntPtr hwnd)
{
this.FilteredHwnd = hwnd;
}
public bool PreFilterMessage(ref Message m)
{
if (this.FilteredHwnd == m.HWnd && m.Msg == WM_SYSTIMER)
return true; // stop handling the message further
else
return false; // all other msgs: handle them
}
}
Чтобы активировать этот фильтр сообщений, просто добавьте следующую строку в событие загрузки формы:
Application.AddMessageFilter(new MyMessageFilter(this.Handle));
Следующие константы должны быть размещены на уровне класса. Они используются в обоих разделах кода выше:
public const UInt32 WM_SYSTIMER = 0x0118;
public const UInt32 WM_NCACTIVATE = 0x86;
Заключение
Хотя сама проблема разрешима, это далеко не просто. С помощью вышеуказанных ручек вы должны пройти довольно далеко. Используйте фильтр, чтобы предотвратить мигание, но тогда первая "вспышка" все еще происходит. Используйте опцию WinProc
для предотвращения первой, но добавьте некоторую логику, чтобы ваше приложение не проявлялось слишком странно (т.е.: всегда неактивная строка заголовка или всегда активна). У вас уже есть код, который вы можете комбинировать с этим, чтобы установить несколько булевых флагов.