Xamarin.Forms MenuItem

Download Sample下载示例

Xamarin.FormsMenuItem 类定义菜单的菜单项,例如 ListView 项上下文菜单和 Shell 应用程序浮出控件菜单。

以下屏幕截图显示了 iOS 和 Android 上的 ListView 上下文菜单中的 MenuItem 对象:

MenuItem 类定义以下属性:

  • Command 是一个 ICommand,允许将用户操作(如手指点击或单击)绑定到 viewmodel 上定义的命令。
  • CommandParameter 是一个 object,用于指定应传递给 Command 的参数。
  • IconImageSource 是定义显示图标的 ImageSource 值。
  • IsDestructive 是指示 MenuItem 是否从列表中删除其关联的 UI 元素的 bool 值。
  • IsEnabled 是指示此对象是否响应用户输入的 bool 值。
  • Text 是指定显示文本的 string 值。

这些属性由 BindableProperty 对象提供支持,因此 MenuItem 实例可以是数据绑定的目标。

创建 MenuItem

MenuItem 对象可在 ListView 对象项的上下文菜单中使用。 最常见的模式是在 ViewCell 实例中创建 MenuItem 对象,该实例用作 ListViewItemTemplateDataTemplate 对象。 填充 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 接口支持模型-视图-视图模型 (MVVM) 模式。 以下 XAML 显示绑定到在 viewmodel 上定义的命令的 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>

在前面的示例中,定义了两个 MenuItem 对象,其 CommandCommandParameter 属性绑定到 viewmodel 上的命令。 viewmodel 包含 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}";
    });
}

示例应用程序包括一个 DataService 类,用于获取填充 ListView 对象的项列表。 viewmodel 已实例化,其项来自 DataService 类,并设置为代码隐藏的 BindingContext

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

警告

MenuItem 对象仅在 Android 上显示图标。 在其他平台上,将仅显示 Text 属性指定的文本。

使用 IconImageSource 属性指定图标。 如果指定了图标,则不会显示由 Text 属性指定的文本。 以下屏幕截图显示了 Android 上带有图标的 MenuItem

有关在 Xamarin.Forms 中使用图像的详细信息,请参阅 Xamarin.Forms 中的图像

在运行时启用或禁用 MenuItem

若要在运行时启用或禁用 MenuItem,请将其 Command 属性绑定到 ICommand 实现,并确保 canExecute 委托根据需要启用或禁用 ICommand

重要

使用 Command 属性启用或禁用 MenuItem 时,请勿将 IsEnabled 属性绑定到另一个属性。

以下示例演示了其 Command 属性绑定到 ICommand(名为 MyCommand)的 MenuItem

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

ICommand 实现需要一个 canExecute 委托来返回 bool 属性的值以启用和禁用 MenuItem

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 上,通过右键单击列表项来激活上下文菜单。 上下文菜单在光标附近显示为垂直列表。