Menuクラス

MenuクラスはMainMenuやMenuItemの基本クラスですが、これらは.NET 2.0から新しいクラスに置き換えられています。

対応関係
 
MainMenu
MainMenu クラス (System.Windows.Forms) | MSDN
MenuStrip
MenuItem
MenuItem クラス (System.Windows.Forms) | MSDN
ToolStripMenuItem
ContextMenu
ContextMenu クラス (System.Windows.Forms) | MSDN
ContextMenuStrip

クラス階層

  • System.ComponentModel.Component
    • System.Windows.Forms.Control
      • System.Windows.Forms.ScrollableControl
        • System.Windows.Forms.ToolStrip … ツールバーのコンテナ
          • System.Windows.Forms.MenuStrip
          • System.Windows.Forms.ToolStripDropDown
            • System.Windows.Forms.ToolStripDropDownMenu
    • System.Windows.Forms.ToolStripItemToolStrip内に配置できる個々の項目
      • System.Windows.Forms.ToolStripControlHost
      • System.Windows.Forms.ToolStripButton
      • System.Windows.Forms.ToolStripDropDownItem
        • System.Windows.Forms.ToolStripMenuItem
        • System.Windows.Forms.ToolStripDropDownButton
        • System.Windows.Forms.ToolStripSplitButton
    • System.Windows.Forms.Menu
      • System.Windows.Forms.MainMenu
      • System.Windows.Forms.MenuItem
      • System.Windows.Forms.ContextMenu

MenuStrip

メニュー全体を管理します。このオブジェクトをFormのMainMenuStripプロパティに設定することで、フォームにメニューが表示されます。

プロパティ

Items

メニューの項目は、Itemsプロパティから取得できるToolStripItemCollectionクラスのメソッドを通して設定します。ToolStrip.Items プロパティ (System.Windows.Forms) | MSDN

menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
    toolStripMenuItem1,
    toolStripMenuItem2,
    toolStripMenuItem3});

Visible

メニューを自動で隠す。c# - Autohide MenuStrip - How to activate it when showing? - Stack Overflow Auto-hide menu in Windows Forms – Reza Aghaei

イベント

イベント 発生タイミング
EventHandler MenuActivate MenuStripがアクティブになったとき
EventHandler MenuDeactivate MenuStripが非アクティブになったとき
     

一般的に、MenuStripのGotFocus、LostFocus、EnterそれにLeaveイベントは、キーボードによってアクティブになったときには発生しないことがあります。そのような場合にはMenuActivateとMenuDeactivateを代わりに用います。Remarks - MenuStrip.MenuActivate Event (System.Windows.Forms) | Microsoft Learn

トラブル対処法

メニューからフォーカスを外せない

メニュー階層の最上位であるMenuStrip.Itemsにフォーカスがあるとき、フォーム上の他のコントロールへFocus()などでフォーカスを移動しようとしても、キー入力は引き続きメニューへ送られます。そもそもメニューにフォーカスを移動してもForm.ActiveControlはフォーム上のコントロールを示したままのため、メニューからフォーカスを外すことになりません。

よってメニューにフォーカスがあるならば入力を破棄し、ユーザーにフォーカスを外すように促します。そのときメニューの項目にフォーカスがあることは、ToolStripMenuItem.Selectedで判定できます。

bool HasFocus()
{
    foreach (ToolStripMenuItem item in menuStrip.Items)
    {
        if (item.Selected) return true;
    }
    return false;
}

ContextMenuStrip

コンテキストメニュー (context menu / ショートカットメニュー / shortcut menu) を表すクラスです。

表示方法

ControlのContextMenuStripプロパティに設定することで、そのコントロールを右クリックしたときに割り当てたContextMenuStripが表示されるようになります。Control.ContextMenuStrip プロパティ (System.Windows.Forms) | MSDN

Controlには同様のプロパティとしてContextMenuもありますが、両方に割り当てた場合にはContextMenuが優先されます。Remarks - Control.ContextMenuStrip Property (System.Windows.Forms) | MSDN

コンテキストメニューの表示を制御したいならばコントロールのプロパティには割り当てず、表示したい時機にContextMenuStripのShow()メソッドを呼びます。

public void Show(
    Control control, // 座標の基準となるコントロール
    Point position,  // 座標の基準となるコントロールからの、相対的な表示位置
    ToolStripDropDownDirection direction // 指定位置になる、コントロールの位置
)
ToolStripDropDown.Show メソッド (Control, Point, ToolStripDropDownDirection) (System.Windows.Forms) | MSDN

directionは既定でToolStripDropDownDirection.Defaultで、左から右へ記述する言語の環境では、コンテキストメニューの左上または左下が指定位置になるように表示されます。

コンストラクタ

public ContextMenuStrip (System.ComponentModel.IContainer container);
ContextMenuStrip(IContainer) - ContextMenuStrip コンストラクター (System.Windows.Forms) | Microsoft Learn

Formの子ではないためにContextMenuStripが破棄されないことがないように、ContextMenuStripのコンテナとなるIContainerを渡します。終了時にはこのIContainerのDispose()を呼ぶことで、それに格納されているContextMenuStripのDispose()が呼ばれます。

c# - When should we implement a constructor with the IContainer parameter for a Component? - Stack Overflow

イベント

イベント 発生タイミング
Opening メニューが開くとき
Opened メニューが開かれたとき
Closing メニューが閉じるとき
Closed メニューが閉じたとき
   
イベント - ContextMenuStrip クラス (System.Windows.Forms) | Microsoft Learn

Openingイベント

メニュー項目を動的に決定するには、Openingイベントのハンドラで処理します。

public event CancelEventHandler Opening
ToolStripDropDown.Opening イベント (System.Windows.Forms) | MSDN

Openingイベントはメニューが開かれるときに発生するため、キーの押下によって呼び出されるToolStripMenuItem.ShortcutKeysが割り当てられたメニュー項目の有効/無効は制御できません。

ToolStripMenuItem.Enabledをfalseにすることでメニュー項目を無効にできますが、その設定はメニューを閉じた後も維持されるため、ShortcutKeysによるキーの割り当ても無効なままとなります。このように変更が維持されることを期待しないならば、Closedイベントで既定の設定に戻します。

引数のCancelEventArgs.Cancelをtrueとすることで、メニューが開かれるのを阻止できます。

トラブル対処法

IMEがオンだと、アクセスキーでの操作が困難

IMEがオンの状態ではキー入力に対して変換の処理がされるため、意図した通りにアクセスキーで操作できません。たとえばメニューのTextプロパティが"&開く"ならば、IMEで「開」と変換することでこのメニューを実行できます。しかし実際にはアクセスキーは"開く(&O)"のように設定することが多く、この場合はoキーを押してもIMEによって「お」と解釈されるため、これを「o」に変換して確定しないとメニューを実行できません。

これに対処するにはContextMenuStripを拡張し、PreProcessMessage()でIMEが処理する前のキーを取得し、それをニーモニック文字としてコントロールへ送ります。

public class CustomContextMenuStrip : ContextMenuStrip
{
    public override bool PreProcessMessage(ref Message msg)
    {
        const int WM_KEYDOWN = 0x100;
        const int VK_PROCESSKEY = 0xE5; // IME PROCESS key

        if (msg.Msg == WM_KEYDOWN && (int)msg.WParam == VK_PROCESSKEY)
        {
            uint virtualKey = ImmGetVirtualKey(Handle);
            return ProcessMnemonic((char)virtualKey);
        }

        return base.PreProcessMessage(ref msg);
    }

    [DllImport("imm32.dll")]
    static extern uint ImmGetVirtualKey(IntPtr hWnd);
}
ContextMenuStripに関する各種Tips・その1 - hnx8のブログ Re[8]: IME入力中のキー入力を取得したい ImmGetVirtualKey function (imm.h) - Win32 apps | Microsoft Learn Virtual-Key Codes (Winuser.h) - Win32 apps | Microsoft Learn

ToolStripMenuItem

MenuStripまたはContextMenuStrip内に表示される、個々のメニューの項目です。一方でこれらの項目の区切りを表すセパレータには、ToolStripSeparatorを用います。

コンストラクタ
 
ToolStripMenuItem()
ToolStripMenuItem(Image)
ToolStripMenuItem(String)
ToolStripMenuItem(String, Image)
ToolStripMenuItem(String, Image, EventHandler)
ToolStripMenuItem(String, Image, EventHandler, Keys)
ToolStripMenuItem(String, Image, EventHandler, String)
ToolStripMenuItem(String, Image, ToolStripItem[])
コンストラクター - ToolStripMenuItem クラス (System.Windows.Forms) | Microsoft Learn

imageを設定する必要がなければ、その引数にはnullを渡します。

EventHandlerのonClickをコンストラクタで指定しない場合には、後からClickイベントに設定できます。

プロパティ

プロパティ  
string Text 項目のテキスト
string Name 項目の名前。これはToolStripItemCollectionのキーとして使用できる
Keys ShortcutKeys 項目のショートカットキー
string ShortcutKeyDisplayString 項目のショートカットキーのテキスト
Font Font 項目のテキストのフォント
bool Checked trueならば、項目が選択されている
bool CheckOnClick trueならば、クリックで項目が自動的にチェックされる。そのときCheckedの値が変更され、CheckedChangedイベントが発生する
bool Available trueならば、ToolStripに配置される

※表示されるかどうかを示すもので、表示状態を示すVisibleとは異なる Remarks - ToolStripItem.Available Property (System.Windows.Forms) | MSDN

bool Visible trueならば、表示されている
bool Enabled trueならば、有効
プロパティ - ToolStripMenuItem クラス (System.Windows.Forms) | Microsoft Learn

Text

項目に表示されるテキストです。ToolStripItem.Text プロパティ (System.Windows.Forms) | MSDN

文字の直前に「&」をつけることでそれがアクセスキー (access key) となり、Altキーと同時に押すことでその項目を選択できるようになります。

コード アプリケーションでの表示
"&File" File
"ファイル(&F)" ファイル(F)
方法 : Windows フォーム コントロールのアクセス キーを作成する | MSDN

ShortcutKeys

ショートカットキーを設定することで、そのキーの押下でこの項目のClickイベントのハンドラを呼び出せるようになります。ToolStripMenuItem.ShortcutKeys Property (System.Windows.Forms) | Microsoft Learn

ToolStripManager.IsValidShortcut()がfalseを返すキーは無効であり、「引数値 'value' (***) は列挙型 'Keys' に対して無効です。」としてInvalidEnumArgumentExceptionが投げられます。 ShortcutKeys - ToolStripMenuItem.cs IsValidShortcut - ToolStripManager.cs

無効とされるキーでも、KeyDownなどのイベントを用いればキーに応答することは可能です。そのときはShortcutKeyDisplayStringでそのキーをメニューに表示できます。

Visibleがfalseでもショートカットキーは有効ですが、Enabledがfalseならば無効になります。

設定したショートカットキーが機能しないときには、フォーム上のコントロールによって入力が捕捉され破棄されていないか確認します。

メソッド

メソッド 機能
PerformClick() Clickイベントを発生できる
   

PerformClick()

EnabledやVisibleがfalseでクリックできない状態になっていると、このメソッドを呼び出してもClickイベントは発生しません。

イベント

イベント 発生タイミング
Click 項目がクリックされたとき
DropDownOpening 項目のDropDownが開くとき
   
イベント - ToolStripMenuItem クラス (System.Windows.Forms) | Microsoft Learn

メニュー デザイナ (Menu Designer)

Visual Studioのビュー デザイナーからは、実際の構造を確認しながらメニューを作成できます。

  1. メニューを追加するフォームを、ビュー デザイナーで開く。
  2. ツールボックスで[MenuStrip]の項目をダブルクリックし、フォームに追加する。
  3. [ここへ入力]に項目名を入力する。これが表示されていない場合はデザイナー下部のMenuStripコンポーネントをクリックし、アクティブにする。
  4. 他のトップレベルの項目やサブメニュー項目も、同様に[ここへ入力]から追加する。

追加したメニュー項目の詳細は、デザイナー下部のMenuStripコンポーネントのコンテキストメニューの[項目の編集]から確認できます。

Microsoft Learnから検索