[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 ディレクティブは省略している)

<ul>

/// <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 を使っています。コメントデータの処理方法の詳細はこちらをご覧ください