今更ながらWPFに置き換えてみる(13)


クリック透過ON/OFFの機能追加

アイコンモードで表示する際、秒とかアナログ時計とかののイメージだけをWindow化して画面に出します。アプリにはWindow透過設定を持ってます(Window Opacity利用)。そもそも地味機能ツールなんで、透過させて目立たない表示にできるという意図なんですが、どうせなら設定でクリックイベントを透過させたほうがいいんではと思い、んで方法を検索するとQiita内のページにありがたい記述がありました「→WPF で オーバーレイ表示をする
クリック透過にすると当然対象Window上のコントロール操作ができなくなるので、NotifyIcon上のコンテキストメニューでON/OFF切り替え可能に。

メインウインドウひらっきっぱなし→ずっとWinハンドラ値は変わらないので、最初にグローバルにクリック受けと無視のそれぞれの値を保存しておきます。
WindowのTOPMOSTも変更可能にしてるので、コンテキストメニューでのクリック透過のON/OFFの判定時にはTOPMOST値も考慮してスイッチしてます。


    public class G
    {
        //・・・略
        public static int catch_extendStyle;    //拡張WINDOW イベント受け用の保存変数
        public static int through_extendStyle;  //      イベント透過用の保存変数
    }

//・・・中略・・・
        //Icon mode Ignore click event
        protected const int GWL_EXSTYLE = (-20);
        protected const int WS_EX_TRANSPARENT   = 0x00000020; //透過時の値
        protected const int WS_EX_TOPMOST       = 0x00000008; //topmost時の値
        [DllImport("user32")]
        protected static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32")]
        protected static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwLong);
//・・・中略・・・
        protected override void OnSourceInitialized(EventArgs e)
        {
            //Icon Mode時のクリックEventの受け・スルー切り替え

            base.OnSourceInitialized(e);

            //WindowHandle(Win32) を取得
            var handle = new WindowInteropHelper(this).Handle;
            //クリックをキャッチする場合の値を算出して保存
            int extendStyle = GetWindowLong(handle, GWL_EXSTYLE);
            G.catch_extendStyle = extendStyle;
            //クリックをスルーする場合の値を算出して保存
            extendStyle |= WS_EX_TRANSPARENT; //フラグの追加
            G.through_extendStyle = extendStyle;
            //初期はキャッチで設定
            SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle);

        }
//・・・中略・・・
        private void NotifyIcon_MenuItem_Click(object sender, RoutedEventArgs e)
        {
            //ノティファイアイコン上でのコンテキストメニュー全般の処理
            MenuItem selectedItem = (MenuItem)sender;
            switch (selectedItem.Tag.ToString())
            {
                case "0":   //show/hide
                   //・・・中略・・・
                case "8":   //Icon Mode click ignore on/off
                    if (G.MODE == 2)    //ICONモードの場合のみ許可
                    {
                        var handle = new WindowInteropHelper(this).Handle;
                        int extendStyle = GetWindowLong(handle, GWL_EXSTYLE);
                        if (this.Topmost == false)
                        {
                            extendStyle ^= WS_EX_TOPMOST;  //TopMostでない場合はその分の値を減算
                        }
                        if (extendStyle == G.catch_extendStyle)
                        {
                            SetWindowLong(handle, GWL_EXSTYLE, G.through_extendStyle);
                            this.IgnoreEvent.IsChecked = true;
                        }
                        else
                        {
                            SetWindowLong(handle, GWL_EXSTYLE, G.catch_extendStyle);
                            this.IgnoreEvent.IsChecked = false;
                        }
                    }
                    else this.IgnoreEvent.IsChecked = false;
                    break;
                  //・・・中略・・・
            }
        }

こんな感じになります。
(クリック受+TOPMOST→クリック無視→TOPMOST解除→クリック受けで変化させています)

時報お知らせ表示

こんな感じの体裁で実装。