Windowsの設定によっては、ユーザーがフォームの境界線をマウスでドラッグしてフォームのサイズを変えている間中絶え間なくフォームのResizeやLayoutイベントが発生し、コントロールの再配置(レイアウト)が行われます。これではパフォーマンスが低下してしまいますので、フォームのリサイズ中は何もしてほしくないというケースもあるでしょう。ここでは、フォームのリサイズ中は何もせず、リサイズが完了してマウスボタンを放したときに初めてコントロールの再配置が行われるようにする方法を紹介します。
ユーザーがフォームのリサイズを開始した時にForm.ResizeBeginイベントが、終了した時にForm.ResizeEndイベントが発生します。これらのイベントは、.NET Framework 2.0以降で使用できます。
なおこれらのイベントは、ユーザーがフォームを移動させた時にも発生します。
以下の例では、フォームのOnResizeメソッドをオーバーライドすることでリサイズ中は何もしないようにして、ResizeEndイベントでコントロールの再配置をしています。このコードは、フォームのクラス内に記述してください。
'リサイズ中は、何もしない Protected Overrides Sub OnResize(ByVal e As EventArgs) End Sub 'フォームのResizeEndイベントハンドラ Private Sub Form1_ResizeEnd(ByVal sender As Object, ByVal e As EventArgs) _ Handles MyBase.ResizeEnd 'リサイズ終了後、再描画とレイアウトロジックを実行する Me.Invalidate() Me.PerformLayout() End Sub
//リサイズ中は、何もしない protected override void OnResize(EventArgs e) { } //フォームのResizeEndイベントハンドラ private void Form1_ResizeEnd(object sender, EventArgs e) { //リサイズ終了後、再描画とレイアウトロジックを実行する this.Invalidate(); this.PerformLayout(); }
または、Control.SuspendLayoutメソッドでレイアウトロジックを中断して、Control.ResumeLayoutメソッドで再開するという方法もあります。この方法の例は、以下のようになります。ただしこの方法では、リサイズ中フォームのResizeイベントは発生します。
[VB.NET] VB.NETのコードは現在準備中です。 Convert C# to VB.NET により、 下記のC#のコードをVB.NETに変換したものを参考にしてください。
//フォームのResizeBeginイベントハンドラ private void Form1_ResizeBegin(object sender, EventArgs e) { //レイアウトロジックを中断する this.SuspendLayout(); } //フォームのResizeEndイベントハンドラ private void Form1_ResizeEnd(object sender, EventArgs e) { //レイアウトロジックを再開する this.ResumeLayout(); }
.NET Framework 1.1以前で、ResizeBeginとResizeEndイベントが使用できない場合は、工夫が必要になります。
まずは、Application.Idleイベントを使用する方法を考えてみます。フォームのサイズを変更している最中はApplication.Idleイベントが発生せず、変更完了してから発生するという特徴を利用します。
この方法によるコードは次のようになります。
'OnResizeのEventArgsを保持する Dim resizeEA As EventArgs = Nothing 'フォームのサイズが変更した時 Protected Overrides Sub OnResize(ByVal e As EventArgs) If resizeEA Is Nothing Then resizeEA = e AddHandler Application.Idle, AddressOf OnIdle End If End Sub 'アプリケーションがアイドル状態になった時 Private Sub OnIdle(ByVal s As Object, ByVal e As EventArgs) If Not (resizeEA Is Nothing) Then '基本クラスのOnResizeを呼び出す MyBase.OnResize(resizeEA) resizeEA = Nothing RemoveHandler Application.Idle, AddressOf OnIdle End If End Sub
//OnResizeのEventArgsを保持する EventArgs resizeEA = null; //フォームのサイズが変更した時 protected override void OnResize(EventArgs e) { if (resizeEA == null) { resizeEA = e; Application.Idle += new EventHandler(OnIdle); } } //アプリケーションがアイドル状態になった時 private void OnIdle(object s, EventArgs e) { if (resizeEA != null) { //基本クラスのOnResizeを呼び出す base.OnResize(resizeEA); resizeEA = null; Application.Idle -= new EventHandler(OnIdle); } }
フォームのWndProcをオーバーライドし、WM_EXITSIZEMOVEメッセージを待ち、送られてきた時にコントロールを配置するという方法もあります。なおWM_EXITSIZEMOVEメッセージは、ResizeEndイベントと同様に、ユーザーがフォームを移動させた時にも送られてきます。この方法は、ニュースグループの投稿(リンク切れ)を参考にさせていただきました。
'Imports System.Security.Permissions 'OnResizeをオーバーライドし、何もしない Protected Overrides Sub OnResize(ByVal e As EventArgs) End Sub Private Const WM_EXITSIZEMOVE As Integer = &H232 <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Protected Overrides Sub WndProc(ByRef m As Message) If m.Msg = WM_EXITSIZEMOVE Then 'リサイズ終了後、再描画とレイアウトロジックを実行する Me.Invalidate() Me.PerformLayout() End If MyBase.WndProc(m) End Sub
//using System.Security.Permissions; //OnResizeをオーバーライドし、何もしない protected override void OnResize(EventArgs e) { } private const int WM_EXITSIZEMOVE = 0x232; [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { if (m.Msg == WM_EXITSIZEMOVE) { //リサイズ終了後、再描画とレイアウトロジックを実行する this.Invalidate(); this.PerformLayout(); } base.WndProc(ref m); }
(この記事は、「.NETプログラミング研究 第42号」で紹介したものです。)