ウィンドウ内にコントロールがたくさんあって、レイアウトが重くなってしまったので、リサイズすると凄まじくカクカクしてしまう。
そんなときに、ウィンドウのリサイズ中はコントロールの配置を変化させず、リサイズが終了してから再配置をさせる方法をご紹介。
方法
一言で言えば、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;
}
}
ピンバック: [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2 | Aqua Ware つぶやきブログ
ピンバック: [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2 | Aqua Ware つぶやきブログ
ピンバック: Aqua Ware つぶやきブログ » [WPF] ウィンドウのリサイズが終了するまで、コントロールのリサイズを行わない方法 その2