ContextMenuStripをタスクバー上に表示する

投稿者: shuichi, タグ: ,,,, 投稿日時: 2006/10/28 04:38

.NET Framework 2.0では.NET Framework 1.xのContextMenuの代わりにContextMenuStripというコントロールが追加されました。このContextMenuStripは多機能で便利ですが、タスクバー上に表示させようとするとうまく表示できません(タスクバーに重ならないように表示される)。SHAppBarMessageでデスクトップツールバーを作成したときなどは困るんじゃないかと。ということでContextMenuStripをタスクバー上に表示させるためにいろいろと調べてみました。

最初に注目したのはNotifyIcon。NotifyIconにContextMenuStripを設定すると正常にタスクバー上に表示されます。MSIL逆アセンブラでNotifyIconを覗いてみると、ContextMenuStripのShowInTaskbarというプライベートメソッドを呼び出していることが分かります。とりあえず、

contextMenuStrip.GetType().InvokeMember(
    "ShowInTaskbar",
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.InvokeMethod |
    System.Reflection.BindingFlags.Instance,
    null,
    contextMenuStrip,
    new Object[] { Cursor.Position.X, Cursor.Position.Y } );

とすることでcontextMenuStripをタスクバー上に表示させることができました。

ただし、この方法では何故かメニューが常にマウスポインタの右上に表示されるようです。いまいちスッキリしないのでShowInTaskbarメソッドの中をさらに覗いてみると、ToolStripDropDownにWorkingAreaConstrainedプロパティが存在するらしい。強制的に作業領域に表示させるという意味なので、

contextMenuStrip.GetType().InvokeMember(
    "WorkingAreaConstrained",
    System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.SetProperty |
    System.Reflection.BindingFlags.Instance,
    null,
    contextMenuStrip,
    new Object[] { false } );
contextMenuStrip.Show( Cursor.Position );

としてみるとうまく表示させることができました。ただし、メニューが表示されるとWorkingAreaConstrainedがtrueに設定されるようなので、表示させる前に毎回WorkingAreaConstrainedをfalseに設定しないと駄目なようです。

これらの方法は本来アクセスできないメソッドやプロパティに強引にアクセスしているわけで、実際はこのような方法は好ましくありません。とりあえずこのような方法もあるというだけです。