読者です 読者をやめる 読者になる 読者になる

からめもぶろぐ。

ワタシ SharePoint チョット デキル

続・WindowStyle を None にしてカスタムウィンドウを作ってみる

C# WPF

前回の記事の続きです。

Win32 API を駆使してカスタム ウィンドウの動作を制御していたのですが、実はまだ問題がありました。実は、最小化または最大化したときにアニメーションが行われないのですよね。文字だけだと伝えにくいのですが、パッと出てパッと消える感じ。細かいことですが、これは気になります。
いろいろ試してみると、ウィンドウ スタイル に WS_CAPTION を設定してあげればいいということがわかりました。さっそく前回のコードを修正してみます。

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        var handle = new WindowInteropHelper(this).Handle;
        if (handle == IntPtr.Zero)
        {
            return;
        }
        // ここから追加
        var style = Win32.GetWindowLong(handle, (int)Win32.GetWindowLongIndex.GWL_STYLE);
        style |= (int)Win32.WindowStyles.WS_CAPTION;
        Win32.SetWindowLong(handle, (int)Win32.GetWindowLongIndex.GWL_STYLE, style);
        // ここまで追加
        HwndSource.FromHwnd(handle).AddHook(this.WindowProc);
    }

これで完成と思いきや、今度は最大化したときのウィンドウ サイズがうまくいきません。タスク バーの領域は考慮されているものの、上下左右 8 ピクセルの余白ができています。どうも WM_GETMINMAXINFO で計算したロジックが無視されている模様で、いろいろ試してみたのですが、どうもうまくいきませんでした。結局、WM_GETMINMAXINFO で制御するのは諦めて、最大化時はウィンドウ内でマージンを取ることにしました。最大化されたかどうかは WM_SIZE で判断します。

    private IntPtr WindowProc(IntPtr handle, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg == (int)Win32.WindowMessages.WM_SIZE) {
            if ((Win32.ResizeMode)wParam == Win32.ResizeMode.SIZE_MAXIMIZED) {
                this.LayoutRoot.Margin = new Thickness(8);
            } else {
                this.LayoutRoot.Margin = new Thickness(0);
            }
        }
        return IntPtr.Zero;
    }

あまり好ましいやり方ではない気がしますが、仕方がありません。何はともあれ、これでアニメーションを有効にすることができました。