[WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その1

Pocket

ウィンドウ内にコントロールがたくさんあって、レイアウトが重くなってしまったので、リサイズすると凄まじくカクカクしてしまう。
そんなときに、ウィンドウのリサイズ中はコントロールの配置を変化させず、リサイズが終了してから再配置をさせる方法をご紹介。

方法

一言で言えば、Win32 API レベルで WM_SIZE イベントを抜き取ってやればいい。
幸い、ウィンドウのリサイズ前後にはそれぞれ、WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE のメッセージが飛んでくるので、その間だけは WM_SIZE を、WPF に処理させないようにする。

コード

直下にボタンが一つだけあるシンプルなウィンドウ。

<Window x:Class="LayoutAfterResize01.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Loaded="Window_Loaded">
    <Grid>
        <Button Content="Button"  Margin="10" Name="button1" />
    </Grid>
</Window>

そいつに、ウィンドウメッセージを処理するロジックを加えてやる。
(名前空間や、using ディレクティブは省略している)

/// <summary>MainWindow.xaml の相互作用ロジック</summary>
public partial class MainWindow : Window {
    // ウィンドウメッセージ
    const int WM_SIZE = 0x0005;
    const int WM_ENTERSIZEMOVE = 0x0231;
    const int WM_EXITSIZEMOVE = 0x0232;

    // リサイズ中かどうか
    bool IsSizing = false;

    // リサイズ終了後に投げる WM_SIZE メッセージのパラメータ
    IntPtr lastLParam;
    IntPtr lastWParam;

    // Win32API の PostMessage 関数のインポート
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern bool PostMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

    public MainWindow() {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        var hsrc = HwndSource.FromVisual(this) as HwndSource;
        hsrc.AddHook(WndProc);
    }

    // ウィンドウプロシージャ
    IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
        switch (msg) {
            case WM_ENTERSIZEMOVE:
                IsSizing = true;
                break;
            case WM_EXITSIZEMOVE:
                IsSizing = false;
                PostMessage(hwnd, WM_SIZE, lastWParam, lastLParam);
                break;
            case WM_SIZE:
                // サイズ変更中なら、ハンドルして WPF に WM_SIZE を渡さない
                if (IsSizing) {
                    handled = true;

                    // サイズ変更終了後に再度ポストするように、パラメータを保持
                    lastLParam = lParam;
                    lastWParam = wParam;
                }
                break;
        }
        return IntPtr.Zero;
    }
}

結果

このようにサイズ変更中は、中のボタンがもとのサイズのままになり、サイズが確定した後初めてレイアウトが変更される。

ただし、拡大する際は未描画領域が残ってしまうので、その部分が黒い状態になってしまう。

3 thoughts on “[WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その1

  1. ピンバック: [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2 | Aqua Ware つぶやきブログ

  2. ピンバック: [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2 | Aqua Ware つぶやきブログ

  3. ピンバック: Aqua Ware つぶやきブログ » [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください