Альтернативное отображение / скрытие окна при нажатии на значок уведомления
Я реализую всплывающее приложение в области уведомлений в стиле Windows 7/Vista ("системный трей") в WPF. До сих пор я писал о своей работе (определение положения значка уведомления, отключение изменения размера и т. Д.).
Однако есть одна проблема, которую я не решил, к своему удовлетворению: скрытие окна при повторном нажатии значка уведомления. Если вы щелкнете (например) по значку громкости в Vista/7, чтобы отобразить регулятор громкости, обратите внимание, что он снова скрыт при повторном щелчке по значку.
Я обрабатываю событие "Деактивировано" окна, чтобы скрыть окно, и окно действительно деактивируется при нажатии на значок уведомления. Тем не менее, нажатие на значок уведомления, конечно, показывает и активирует окно, так что в итоге происходит то, что окно исчезает, когда мышь не работает, и вновь появляется, когда мышь отпущена (завершение события щелчка мыши).
Сначала я подумал, что могу использовать событие MouseDown значка уведомления (я использую System.Windows.Forms.NotifyIcon) и проверить, является ли окно видимым в это время - если бы оно было, я мог бы интерпретировать его как нажатие пользователем значок уведомления во второй раз, чтобы скрыть окно. К сожалению, событие MouseDown, по-видимому, не срабатывает до тех пор, пока мышь не будет фактически нажата (иными словами, она работает аналогично событию MouseClick), когда окно уже деактивировано и, следовательно, скрыто. Это, кажется, исключает это решение.
Моя следующая идея (и подход, который я использовал в итоге) состояла в том, чтобы получить положение курсора, когда окно деактивировано (GetCursorPos), и проверить, находится ли эта точка в пределах границ значка уведомления. В то же время я также использую GetForegroundWindow, чтобы найти текущее активное окно - если действительно нужно щелкнуть значок уведомления, это должна быть либо панель задач (окно верхнего уровня с именем класса Shell_TrayWnd), либо выпадающая область уведомлений (окно верхнего уровня с именем класса NotifyIconOverflowWindow; только для Windows 7+). Короче говоря, если курсор находится над значком уведомления и область уведомлений активна, я предполагаю, что пользователь щелкнул мышью значок уведомления, чтобы скрыть окно. Если эти условия выполняются, то следующее событие MouseClick не приведет к отображению / активации окна.
Это решение имеет по крайней мере одну проблему: если курсор находится над значком уведомления, и пользователь нажимает клавишу Windows, чтобы открыть меню "Пуск" (или использует клавишу Windows + сочетание клавиш для открытия приложения), моя программа будет ошибочно интерпретируйте это как нажатие мыши на значок уведомления (потому что панель задач активируется этими сочетаниями клавиш). Это означает, что в следующий раз, когда пользователь действительно щелкнет значок уведомления, окно не будет отображаться. (Нажав на значок уведомления еще раз, вы увидите его.)
Я надеюсь, что то, что я написал, имеет какой-то смысл; если нет, я с удовольствием постараюсь прояснить ситуацию дальше.
Мне интересно узнать, есть ли у кого-нибудь еще идеи о том, как решить эту проблему.
Я подозреваю, что это может быть невозможно: мне кажется, что собственные всплывающие приложения области уведомлений Windows 7 используют простую реализацию таймера. Если щелкнуть (например) значок громкости при открытом регуляторе громкости, регулятор громкости закроется только в том случае, если время между деактивацией окна и щелчком мыши составляет менее 2 секунд. Если удерживать мышь на значке в течение более длительного периода времени, а затем отпустить, регулятор громкости снова отобразится, даже если он был открыт до нажатия мыши.
1 ответ
Это не то, как работает окно регулировки громкости. Он исчезает, когда вы щелкаете в любом месте, включая значок уведомления. Значок не актуален. Это стандартный трюк Win32, он захватывает мышь, поэтому он может видеть щелчки за пределами своего окна.
Мышь. Захват в WPF. Это не так просто сделать, потому что он требует IInputElement вместо дескриптора окна.