Альтернативное отображение / скрытие окна при нажатии на значок уведомления - PullRequest
3 голосов
/ 03 января 2011

Я реализую всплывающее приложение в области уведомлений в стиле 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 Ответ

1 голос
/ 03 января 2011

Это не то, как работает окно регулировки громкости. Он исчезает при нажатии в любом месте , включая значок уведомления. Значок не актуален. Это стандартный трюк Win32, он захватывает мышь, поэтому он может видеть щелчки за пределами своего окна.

Мышь. Захват в WPF. Это не так просто сделать, потому что для него требуется IInputElement вместо дескриптора окна.

...