2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【WPF】右クリックメニュー(ContextMenu)の表示制御と選択処理

Last updated at Posted at 2022-07-17

はじめに

前回は、ボタンにイメージを追加したカスタムコントロールの作成を行なった。

今回は、WineskinServerで動作するランチャー作成として参考にしている「CLaunch」のように右クリックメニュー(ContextMenu)を付けたい。

メニュー内容

ランチャー用なので起動するプログラムとアイコンを登録する必要がある。
今回は右クリックメニューとして下記の3つを用意して、有効/無効で表示制御する程度にしておく。

  • 登録
  • 削除
  • プロパティ

まだ未登録の場合、「登録」のみ有効表示とし、登録済みの場合、「登録」は無効表示にして「削除」と「プロパティ」は有効表示にする。

実装

今回は、XAMLは使用しないでコーディングで書いてみました。

ContextMenu contextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem();
MenuItem menuItem2 = new MenuItem();
MenuItem menuItem3 = new MenuItem();
menuItem1.Header = "登録";
menuItem1.Name = "Register";
menuItem1.Click += new RoutedEventHandler(MenuItem_Click);
menuItem2.Header = "削除";
menuItem2.Name = "Remove";
menuItem2.Click += new RoutedEventHandler(MenuItem_Click);
menuItem3.Header = "プロパティ";
menuItem3.Name = "Property";
menuItem3.Click += new RoutedEventHandler(MenuItem_Click);
contextMenu.Items.Add(menuItem1);
contextMenu.Items.Add(menuItem2);
contextMenu.Items.Add(menuItem3);

XAMLによる実装

【2022/07/19追記】
XAMLを使用した場合の実装も書いてみました。
コーディングによる実装より、XAMLにした方がスマートですね。

<Window.Resources>
    <ContextMenu x:Key="PopupMenu">
        <MenuItem Header="登録" Name="Register" Click="MenuItem_Click"/>
        <MenuItem Header="削除" Name="Remove" Click="MenuItem_Click"/>
        <MenuItem Header="プロパティ" Name="Property" Click="MenuItem_Click"/>
    </ContextMenu>
</Window.Resources>

FindResourceメソッドを使うことで、XAMLに定義したリソースにアクセスできます。

MyControl.ContextMenu = (ContextMenu)FindResource("PopupMenu"); 

ボタンに右クリックメニューの追加

今回は、先頭だけサクラエディタ用のアイコンを登録しました。
最終的には設定ファイルで制御するのですが、それはまだ次回とします。

実装

ボタンコントロールのContextMenuプロパティにをcontextMenuインスタンスをセットする。

gridMain.GridRowCount = 2;
gridMain.GridColumnCount = 4;
gridMain.ShowGridLines = true;

int count = 1;
for (int i = 0; i < 2; i++)
{
    for (int j = 0; j < 4; j++)
    {
        ImageButton MyControl = new ImageButton();
        MyControl.Name = "Button" + count.ToString();
        if(count == 1)
        {
            MyControl.ImageSource = new BitmapImage(new Uri("/Images/my_appicon.ico", UriKind.Relative));
            MyControl.Content = "サクラエディタ";
            MyControl.ImageHeight = 48;
            MyControl.ImageWidth = 48;
        }
        MyControl.Click += new RoutedEventHandler(Button_Click);
        MyControl.ContextMenuOpening += ContextMenu_Click;
        MyControl.ContextMenu = contextMenu;
        Grid.SetColumn(MyControl, j);
        Grid.SetRow(MyControl, i);
        gridMain.Children.Add(MyControl);
        count++;
    }
}

スクリーンショット 2022-07-18 1.09.19.png

メニューの表示前制御

開かれる前に編集したい場合、ContextMenuOpeningイベントを利用する。
未登録の場合は「登録」のみ有効表示とし、登録済みの場合は「登録」は無効表示にして「削除」と「プロパティ」は有効表示にする。

参照:【WPF】ContextMenuに表示される一部項目を、場合に応じて選択できなくする

実装

ボタンコントロールにContextMenuOpeningイベントを割り当てる。

MyControl.ContextMenuOpening += ContextMenu_Click;
private void ContextMenu_Click(object sender, ContextMenuEventArgs e)
{
    if (e.Source is Button)
    {
        Button b = (Button)e.Source;
        ContextMenu menu = b.ContextMenu;

        foreach(MenuItem item in menu.Items)
        {
            switch(item.Name)
            {
                case "Register":
                    item.IsEnabled = (b.Content == null);
                    break;
                default:
                    item.IsEnabled = (b.Content != null);
                    break;
            }
        }
    }
}

スクリーンショット 2022-07-18 1.15.36.png スクリーンショット 2022-07-18 1.12.16.png

メニューのクリック処理

ランチャーには複数のボタンがありますが、ContextMenuは1種類を使い回しています。
メニュー項目がクリックされた場合に コンテキストメニューが開かれた元のコントロールを知る必要があります。

コンテキストメニューが開かれた元のコントロールの取得方法を示す。
参照:コンテキストメニューが開かれたコントロールを取得する

ContextMenuにはPlacementTargetプロパティがある。これはContextMenuが表示される際の表示位置の基準となるオブジェクトを示すプロパティである。
ContextMenuを開く際にこのプロパティを意図的に設定しなければ、右クリックしたコントロールが格納される仕組みとなっている。このContextMenu.PlacementTargetプロパティが開かれた元のコントロールということになる。

実装

今回は、ボタン名+メニュー名をメッセージダイアログで表示する。
実際には、メニュー内容の処理を記述する。

menuItem1.Click += new RoutedEventHandler(MenuItem_Click);
menuItem2.Click += new RoutedEventHandler(MenuItem_Click);
menuItem3.Click += new RoutedEventHandler(MenuItem_Click);

メニューのイベントを1つにまとめて処理しています。

private void MenuItem_Click(object sender, RoutedEventArgs e)
{
    MenuItem m = (MenuItem)sender;

    var target = ((e.Source as MenuItem).Parent as ContextMenu).PlacementTarget;
    if (target is Button)
    {
        Button b = (Button)target;
        MessageBox.Show(b.Name + m.Header.ToString());
    }
}

2番目のボタンで右クリックメニューで「登録」をクリックした。
image.png

最後に

次はメニュー内容の実装処理として、登録画面やプロパティ画面などを作成して行きます。

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?