DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

フォームの移動が終了したことを知る

フォームが移動したことを知る方法は「フォームの位置や大きさが変更されたことを知る」で説明していますが、ここではユーザーがフォームを移動し終えたことを知る方法について説明します。

フォームのリサイズが終了するまでコントロールの大きさを変えない」ではユーザーがフォームのサイズを変更し終えたことをどうやって知るかについて説明しましたが、ここで紹介した方法が今回のケースでもほぼそのまま使えます。Application.Idleイベントを使った方法も使えますが、ここではそれ以外の方法について説明します。

Form.ResizeEndイベントを使用する方法

.NET Framework 2.0からは、Form.ResizeEndイベントが追加されました。このイベントはフォームのサイズをユーザーが変更した時だけでなく、フォームを移動させた時にも発生します。よってこのイベントが発生した時、それがサイズの変更ではなく、移動の終了であることを確認しなければなりません。その方法としては、フォームのMoveイベントハンドラでフラッグを立てる方法や、ResizeBeginイベントが発生した時のフォームの位置を覚えておき、ResizeEndイベントが発生した時の位置と異なるか調べる方法などがあります。ここでは、Moveイベントを使った方法を紹介します。

VB.NET
コードを隠すコードを選択
Private moving As Boolean = False

Protected Overrides Sub OnMove(ByVal e As EventArgs)
    MyBase.OnMove(e)

    'フォームが表示されている時のみ有効とする
    If Me.Visible Then
        Me.moving = True
    End If
End Sub

'フォームのResizeEndイベントハンドラ
Private Sub Form1_ResizeEnd(ByVal sender As Object, ByVal e As EventArgs) _
        Handles MyBase.ResizeEnd
    If Me.moving Then
        Console.WriteLine("移動が終了しました")
        Me.moving = False
    End If
End Sub
C#
コードを隠すコードを選択
private bool moving = false;

protected override void OnMove(EventArgs e)
{
    base.OnMove(e);

    //フォームが表示されている時のみ有効とする
    if (this.Visible)
        this.moving = true;
}

//フォームのResizeEndイベントハンドラ
private void Form1_ResizeEnd(object sender, EventArgs e)
{
    if (this.moving)
    {
        Console.WriteLine("移動が終了しました");
        this.moving = false;
    }
}

WM_EXITSIZEMOVEメッセージを待つ方法

.NET Framework 1.1以前の場合は、WM_EXITSIZEMOVEメッセージを使用する方法があります。ResizeEndイベントと同じで、これだけではフォームがリサイズされたのか移動させられたのかが分かりませんので、上記と同じ方法で判断する必要があります。なおフォームのリサイズ、移動の開始は、WM_ENTERSIZEMOVEメッセージで知ることができます。

VB.NET
コードを隠すコードを選択
'Imports System.Security.Permissions

Private moving As Boolean = False

Protected Overrides Sub OnMove(ByVal e As EventArgs)
    MyBase.OnMove(e)

    'フォームが表示されている時のみ有効とする
    If Me.Visible Then
        Me.moving = True
    End If
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 AndAlso Me.moving Then
        Console.WriteLine("移動が終了しました")
        Me.moving = False
    End If

    MyBase.WndProc(m)
End Sub
C#
コードを隠すコードを選択
//using System.Security.Permissions;

private bool moving = false;

protected override void OnMove(EventArgs e)
{
    base.OnMove(e);

    //フォームが表示されている時のみ有効とする
    if (this.Visible)
        this.moving = true;
}

private const int WM_EXITSIZEMOVE = 0x0232;

[SecurityPermission(SecurityAction.Demand,
    Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_EXITSIZEMOVE && this.moving)
    {
        Console.WriteLine("移動が終了しました");
        this.moving = false;
    }

    base.WndProc(ref m);
}
  • 履歴:
  • 2007/1/15 「.NET Framework 2.0以降で、Form.ResizeEndイベントを使用する方法」を追加。
  • 2010/6/30 WndProcにSecurityPermissionAttributeを付けた。
  • 2013/12/9 SecurityAction.LinkDemandの代わりにSecurityAction.Demandを使うようにした。
  • 2015/5/18 章の順序を変更。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。