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

特定のToolStripを指定したToolStripPanelにドッキングできないようにする

注意:ここで紹介している方法は、.NET Framework 2.0以降でのみ使用できます。

ToolStripは、同じフォーム内であれば、どこのToolStripPanel(ToolStripContainerの上下左右の部分)にも移動できてしまいます。例えば、上下のToolStripPanelには移動できるが、左右のToolStripPanelには移動できないようにできないものでしょうか?

基本的には、ToolStripPanelのControlAddedイベントで受け入れ可能なToolStripかを調べ、受け入れられなければToolStripPanelのControlsから削除し、元のToolStripPanelに戻すという方法になりそうです。しかし、ToolStripが元のToolStripPanelから削除される直前に発生するイベントがなく、削除されて始めて分かるため、元に戻すToolStripの位置をあらかじめ記憶しておかなければなりません。

しかも、たとえそのようなコードを書いたとしても、正常に動作しません。ControlAddedイベントが発生しても、この時ToolStripはドラッグ中なので、この時点でToolStripを戻してもうまくいかないようです。つまり、ToolStripがドロップされ、ToolStripの移動が完全に終了してから、ToolStripを元に戻さなければなりません。

ToolStripの移動が終了したことを知るための方法はないかと探したところ、.NET Framework 2.0から追加されたControl.MouseCaptureChangedイベントあたりが使えそうです。

以上のような方針で、ToolStripがToolStripContainer(toolStripContainer1)のBottomToolStripPanelに移動できないようにするコードを書いてみました。ここでは、ToolStripのLocationChangedイベントでToolStripの位置を記憶するようにしています。何回か試した範囲では、どうにかうまくいっているようです。

VB.NET
コードを隠すコードを選択
'ToolStripの位置
Private toolStripParent As ToolStripPanel = Nothing
Private toolStripLocation As Point = Point.Empty

'LocationChangedイベントハンドラ
Private Sub toolStrip1_LocationChanged(ByVal sender As Object, _
        ByVal e As EventArgs) Handles ToolStrip1.LocationChanged
    Dim ts As ToolStrip = CType(sender, ToolStrip)

    If ToolStripContainer1.BottomToolStripPanel.Equals(ts.Parent) _
        AndAlso Not (toolStripParent Is Nothing) Then
        'BottomToolStripPanelに移動させた時
        'ここでToolStripをもとに戻すことができればよいのだが...
    ElseIf Not (ts.Parent Is Nothing) _
        AndAlso TypeOf ts.Parent Is ToolStripPanel Then
        'ToolStripの位置を記憶する
        toolStripParent = CType(ts.Parent, ToolStripPanel)
        toolStripLocation = ts.Location
    End If
End Sub

'MouseCaptureChangedイベントハンドラ
Private Sub toolStrip1_MouseCaptureChanged(ByVal sender As Object, _
    ByVal e As EventArgs) Handles ToolStrip1.MouseCaptureChanged
    Dim ts As ToolStrip = CType(sender, ToolStrip)

    If ToolStripContainer1.BottomToolStripPanel.Equals(ts.Parent) _
            AndAlso Not (toolStripParent Is Nothing) Then
        'BottomToolStripPanelに移動させた時
        'ToolStripを元の位置に戻す
        toolStripParent.Join(ts, toolStripLocation)
    End If
End Sub
C#
コードを隠すコードを選択
//ToolStripの位置
private ToolStripPanel toolStripParent = null;
private Point toolStripLocation = Point.Empty;

//LocationChangedイベントハンドラ
private void toolStrip1_LocationChanged(object sender, EventArgs e)
{
    ToolStrip ts = (ToolStrip)sender;

    if (toolStripContainer1.BottomToolStripPanel.Equals(ts.Parent)
        && toolStripParent != null)
    {
        //BottomToolStripPanelに移動させた時
        //ここでToolStripをもとに戻すことができればよいのだが...
    }
    else if (ts.Parent != null && ts.Parent is ToolStripPanel)
    {
        //ToolStripの位置を記憶する
        toolStripParent = (ToolStripPanel)ts.Parent;
        toolStripLocation = ts.Location;
    }
}

//MouseCaptureChangedイベントハンドラ
private void toolStrip1_MouseCaptureChanged(object sender, EventArgs e)
{
    ToolStrip ts = (ToolStrip)sender;

    if (toolStripContainer1.BottomToolStripPanel.Equals(ts.Parent)
        && toolStripParent != null)
    {
        //BottomToolStripPanelに移動させた時
        //ToolStripを元の位置に戻す
        toolStripParent.Join(ts, toolStripLocation);
    }
}

もっと良い方法をご存知の方がいらっしゃれば、ぜひ教えてください。

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

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。