Xamarin.Forms MenuItem

Xamarin.FormsMenuItem クラスは、ListView 項目のコンテキスト メニューやシェル アプリケーションのポップアップ メニューなどのメニューのメニュー項目を定義します。

次のスクリーンショットは、iOS と Android の ListView コンテキスト メニューの MenuItem オブジェクトを示しています。

MenuItem クラスには、次のプロパティが定義されています。

  • Command: 指のタップやクリックなどのユーザー アクションを、ビューモデルで定義されているコマンドにバインドできるようにする ICommand
  • CommandParameter: Command に渡すパラメーターを指定する object
  • IconImageSource は、表示アイコンを定義する ImageSource 値です。
  • IsDestructive は、MenuItem が関連付けられている UI 要素をリストから削除するかどうかを示す bool 値です。
  • IsEnabled は、このオブジェクトがユーザーによる入力に応答するかどうかを示す bool 値です。
  • Text は、表示テキストを指定する string 値です。

これらのプロパティは BindableProperty オブジェクトによってサポートされるため、MenuItem インスタンスをデータ バインディングの対象にすることができます。

MenuItem を作成する

MenuItem オブジェクトは、ListView オブジェクトの項目のコンテキスト メニュー内で使用できます。 最も一般的なパターンは、ViewCell インスタンス内に MenuItem オブジェクトを作成し、ListViews ItemTemplateDataTemplate オブジェクトとして使用することです。 ListView オブジェクトのデータが設定されると、DataTemplate を使用して各項目が作成され、項目のコンテキスト メニューがアクティブになったときに MenuItem 選択肢が表示されます。

次の例は、ListView オブジェクトのコンテキスト内での MenuItem のインスタンス化を示しています。

<ListView>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <ViewCell.ContextActions>
                    <MenuItem Text="Context Menu Option" />
                </ViewCell.ContextActions>
                <Label Text="{Binding .}" />
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

MenuItem はコードで作成することもできます。

// A function returns a ViewCell instance that
// is used as the template for each list item
DataTemplate dataTemplate = new DataTemplate(() =>
{
    // A Label displays the list item text
    Label label = new Label();
    label.SetBinding(Label.TextProperty, ".");

    // A ViewCell serves as the DataTemplate
    ViewCell viewCell = new ViewCell
    {
        View = label
    };

    // Add a MenuItem instance to the ContextActions
    MenuItem menuItem = new MenuItem
    {
        Text = "Context Menu Option"
    };
    viewCell.ContextActions.Add(menuItem);

    // The function returns the custom ViewCell
    // to the DataTemplate constructor
    return viewCell;
});

// Finally, the dataTemplate is provided to
// the ListView object
ListView listView = new ListView
{
    ...
    ItemTemplate = dataTemplate
};

イベントを使用して MenuItem の動作を定義する

MenuItem クラスは、Clicked イベントを公開します。 イベント ハンドラーをこのイベントにアタッチして、XAML の MenuItem インスタンスのタップまたはクリックに反応できます。

<MenuItem ...
          Clicked="OnItemClicked" />

コードでイベント ハンドラーをアタッチすることもできます。

MenuItem item = new MenuItem { ... }
item.Clicked += OnItemClicked;

前の例では、OnItemClicked イベント ハンドラーを参照しました。 次のコードは、実装例を示しています。

void OnItemClicked(object sender, EventArgs e)
{
    // The sender is the menuItem
    MenuItem menuItem = sender as MenuItem;

    // Access the list item through the BindingContext
    var contextItem = menuItem.BindingContext;

    // Do something with the contextItem here
}

MVVM を使用して MenuItem の動作を定義する

MenuItem クラスは、BindableProperty オブジェクトと ICommand インターフェイスを介して Model-View-ViewModel (MVVM) パターンをサポートします。 次の XAML は、ビューモデルで定義されコマンドにバインドされた MenuItem インスタンスを示しています。

<ContentPage.BindingContext>
    <viewmodels:ListPageViewModel />
</ContentPage.BindingContext>

<StackLayout>
    <Label Text="{Binding Message}" ... />
    <ListView ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <ViewCell.ContextActions>
                        <MenuItem Text="Edit"
                                    IconImageSource="icon.png"
                                    Command="{Binding Source={x:Reference contentPage}, Path=BindingContext.EditCommand}"
                                    CommandParameter="{Binding .}"/>
                        <MenuItem Text="Delete"
                                    Command="{Binding Source={x:Reference contentPage}, Path=BindingContext.DeleteCommand}"
                                    CommandParameter="{Binding .}"/>
                    </ViewCell.ContextActions>
                    <Label Text="{Binding .}" />
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

前の例では、ビューモデル上のコマンドにバインドされた CommandCommandParameter プロパティを使用して、2 つの MenuItem オブジェクトが定義されています。 ビューモデルには、XAML で参照されるコマンドが含まれています。

public class ListPageViewModel : INotifyPropertyChanged
{
    ...

    public ICommand EditCommand => new Command<string>((string item) =>
    {
        Message = $"Edit command was called on: {item}";
    });

    public ICommand DeleteCommand => new Command<string>((string item) =>
    {
        Message = $"Delete command was called on: {item}";
    });
}

サンプル アプリケーションには、ListView オブジェクトを設定するための項目の一覧を取得するために使用する DataService クラスが含まれています。 ビューモデルは、DataService クラスの項目を使用してインスタンス化され、コードビハインドで BindingContext として設定されます。

public MenuItemXamlMvvmPage()
{
    InitializeComponent();
    BindingContext = new ListPageViewModel(DataService.GetListItems());
}

警告

Android では、MenuItem オブジェクトはアイコンのみを表示します。 他のプラットフォームでは、Text プロパティで指定されたテキストのみが表示されます。

アイコンは、IconImageSource プロパティを使用して指定します。 アイコンを指定した場合、Text プロパティで指定されたテキストは表示されません。 次のスクリーンショットは、Android でのアイコン付きの MenuItem を示しています。

Xamarin.Forms でのイメージの使用の詳細については、「Xamarin.Forms での画像」を参照してください。

MenuItem を実行時に有効または無効にする

実行時に MenuItem を無効にするには、その Command プロパティを ICommand 実装にバインドし、canExecute デリゲートが必要に応じて ICommand を有効および無効にするようにします。

重要

Command プロパティを使用して MenuItem を有効または無効にする場合は、IsEnabled プロパティを別のプロパティにバインドしないでください。

次の例は、Command プロパティが MyCommand という名前の ICommand にバインドされる MenuItem を示しています。

<MenuItem Text="My menu item"
          Command="{Binding MyCommand}" />

ICommand 実装では、MenuItem を有効または無効にする bool プロパティの値を返す canExecute デリゲートが必要です。

public class MyViewModel : INotifyPropertyChanged
{
    bool isMenuItemEnabled = false;
    public bool IsMenuItemEnabled
    {
        get { return isMenuItemEnabled; }
        set
        {
            isMenuItemEnabled = value;
            MyCommand.ChangeCanExecute();
        }
    }

    public Command MyCommand { get; private set; }

    public MyViewModel()
    {
        MyCommand = new Command(() =>
        {
            // Execute logic here
        },
        () => IsMenuItemEnabled);
    }
}

この例では、IsMenuItemEnabled プロパティが設定されるまで、MenuItem は無効になります。 これが発生すると、Command.ChangeCanExecute メソッドが呼び出され、MyCommandcanExecute デリゲートが再評価されます。

クロスプラットフォームのコンテキスト メニューの動作

コンテキスト メニューへのアクセスと表示は、プラットフォームごとに異なります。

Android では、リスト項目を長押しすると、コンテキスト メニューがアクティブになります。 コンテキスト メニューがタイトルとナビゲーション バーの領域に置き換わり、MenuItem オプションが水平ボタンとして表示されます。

iOS では、リスト項目をスワイプすると、コンテキスト メニューがアクティブになります。 コンテキスト メニューがリスト項目に表示され、MenuItems が水平ボタンとして表示されます。

UWP では、リスト アイテムを右クリックするとコンテキスト メニューがアクティブになります。 コンテキスト メニューは、カーソルの近くに垂直リストとして表示されます。