3

WPF で Windows 7/Vista スタイルの通知領域 (「システム トレイ」) ポップアップ アプリケーションを実装しています。ここまでの作業(通知アイコンの位置の決定、サイズ変更の無効化など)について書きました。

ただし、満足のいく解決には至っていない問題が 1 つあります。それは、通知アイコンを 2 回目にクリックしたときにウィンドウを非表示にすることです。たとえば、Vista/7 でボリューム アイコンをクリックしてボリューム コントロールを表示すると、アイコンを 2 回目にクリックすると再び非表示になることに注意してください。

ウィンドウの Deactivated イベントを処理してウィンドウを非表示にします。通知アイコンがクリックされると、ウィンドウは実際に非アクティブになります。ただし、もちろん、通知アイコンをクリックするとウィンドウが表示およびアクティブ化されるため、マウスが押されている間はウィンドウが消え、マウスが離されると再表示されます (マウス クリック イベントが完了します)。

私が最初に考えたのは、通知アイコンの MouseDown イベント (私は System.Windows.Forms.NotifyIcon を使用しています) を使用して、その時点でウィンドウが表示されているかどうかを確認することでした。表示されている場合は、ユーザーがクリックしたと解釈できます。通知アイコンをもう一度クリックしてウィンドウを非表示にします。残念ながら、MouseDown イベントは、マウスが実際にクリックされるまで発生しないようです (つまり、MouseClick イベントと同じように機能します)。その時点で、ウィンドウは既に非アクティブ化されて非表示になっています。これは、この解決策を除外しているようです。

私の次のアイデア (および私が最終的に使用したアプローチ) は、ウィンドウが非アクティブになったときにカーソル位置を取得し (GetCursorPos)、そのポイントが通知アイコンの境界内にあるかどうかを確認することでした。同時に、GetForegroundWindow を使用して現在アクティブなウィンドウを見つけます。通知アイコンが実際にクリックされる場合は、タスクバー (クラス名が Shell_TrayWnd の最上位ウィンドウ) または通知領域のフライアウトのいずれかである必要があります。 (クラス名が NotifyIconOverflowWindow の最上位ウィンドウ。Windows 7 以降のみ)。つまり、カーソルが通知アイコンの上にあり、通知領域がアクティブな場合、ユーザーが通知アイコンをマウスダウンしてウィンドウを非表示にしたと想定します。これらの条件が真の場合、次の MouseClick イベントによってウィンドウが表示/アクティブ化されることはありません。

ただし、このソリューションには少なくとも 1 つの問題があります。カーソルが通知アイコンの上にあり、ユーザーが Windows キーを押して [スタート] メニューを開く (または Windows キー + 数字のショートカットを使用してアプリケーションを開く) 場合、私のプログラムは間違って動作します。これは、通知アイコンへのマウスダウンと解釈されます (これらのキーボード ショートカットによってタスクバーがアクティブになるため)。これは、次にユーザーが実際に通知アイコンをクリックしたときに、ウィンドウが表示されないことを意味します。(通知アイコンをもう一度クリックすると表示されます。)

私が書いたことが何らかの意味を成すことを願っています。そうでない場合は、喜んで状況をさらに明確にします。

これを解決する方法について他のアイデアがあるかどうかを知りたいです。

それは不可能かもしれないと思います。Windows 7 のネイティブの通知領域のポップアップ アプリケーション自体は、単純なタイマーの実装を使用しているように思えます。たとえば、ボリューム コントロールが開いているときにボリューム アイコンをクリックすると、ウィンドウの非アクティブ化とマウス クリックの間の時間が約 2 秒未満の場合にのみ、ボリューム コントロールが閉じます。マウスをアイコン上で長時間押したままにしてから離すと、マウスを押す前に開いていた場合でも、ボリューム コントロールが再び表示されます。

4

1 に答える 1

1

これは、ボリューム コントロール ウィンドウがどのように機能するかではありません。通知アイコンを含む任意の場所をクリックすると消えます。アイコンは関係ありません。これは Win32 の標準的なトリックです。マウスをキャプチャして、ウィンドウの外でクリックを確認できるようにします。

WPF の Mouse.Capture。ウィンドウ ハンドルの代わりに IInputElement が必要なため、それほど簡単ではありません。

于 2011-01-03T14:56:12.400 に答える