Xamarin.Forms MenuItem

Download SampleDescargar el ejemplo

La clase Xamarin.FormsMenuItem define elementos de menú para menús como menús contextuales de elementos ListView y menús flotantes de aplicaciones de Shell.

En las capturas de pantalla siguientes se muestran objetos MenuItem en un menú contextual ListView en iOS y Android:

La clase MenuItem define las propiedades siguientes:

  • Command es un ICommand que permite enlazar acciones de usuario, como pulsaciones de dedo o clics, a los comandos definidos en un modelo de vista.
  • CommandParameteres un objeto object que especifica el parámetro que se debe pasar al Command.
  • IconImageSource es un valor ImageSource que define el icono de presentación.
  • IsDestructive es un valor bool que indica si el MenuItem quita su elemento de interfaz de usuario asociado de la lista.
  • IsEnabled es un valor bool que indica si este objeto responde a la entrada del usuario.
  • Text es un valor string que especifica el texto para mostrar.

Estas propiedades están respaldadas por objetos BindableProperty para que la instancia MenuItem pueda ser el destino de los enlaces de datos.

Crear un objeto MenuItem

Los objetos MenuItem se pueden usar en un menú contextual en los elementos de un objeto ListView. El patrón más común es crear objetos MenuItem dentro de una instancia ViewCell, que se usa como objeto DataTemplate para la ItemTemplate de ListView. Cuando se rellena el objeto ListView, creará cada elemento usando DataTemplate, exponiendo las opciones MenuItem cuando se active el menú contextual para un elemento.

En el ejemplo siguiente se muestra creación de instancias MenuItem dentro del contexto de un objeto ListView:

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

También se puede crear MenuItem en código:

// 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
};

Definición del comportamiento MenuItem con eventos

La clase MenuItem expone un evento Clicked. Un controlador de eventos se puede adjuntar a este evento para reaccionar ante pulsaciones o clics en la instancia MenuItem en XAML:

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

Un controlador de eventos también se puede adjuntar en el código:

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

En los ejemplos anteriores se hace referencia a un controlador de eventos OnItemClicked. En el siguiente código, se muestra un ejemplo de ejecución:

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
}

Definición del comportamiento MenuItem con MVVM

La clase MenuItem admite el patrón Model-View-ViewModel (MVVM) a través de objetos BindableProperty y la interfaz ICommand. El siguiente código XAML muestra MenuItem instancias enlazadas a comandos definidos en un modelo de vista:

<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>

En el ejemplo anterior, se definen dos objetos MenuItem con sus propiedades Command y CommandParameter enlazadas a comandos en el modelo de vista. El modelo de vista contiene los comandos a los que se hace referencia en 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}";
    });
}

La aplicación de ejemplo incluye una clase DataService usada para obtener una lista de elementos para rellenar los objetos ListView. Se crea una instancia de un modelo de vista, con elementos de la clase DataService y se establece como el BindingContext en el código subyacente:

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

Advertencia

Los objetos MenuItem solo muestran iconos en Android. En otras plataformas, solo se mostrará el texto especificado por la propiedad Text.

Los iconos se especifican mediante la propiedad IconImageSource. Si se especifica un icono, no se mostrará el texto especificado por la propiedad Text. En las capturas de pantalla siguientes se muestra un MenuItem con un icono en iOS y Android:

Para obtener más información sobre el uso de imágenes en Xamarin.Forms, consulte Imágenes en Xamarin.Forms.

Habilitar o deshabilitar un objeto MenuItem en tiempo de ejecución

Para habilitar la deshabilitación de un MenuItem en runtime, enlace su propiedad Command a una implementación ICommand y asegúrese de que un delegado canExecute habilita y deshabilita el ICommand según corresponda.

Importante

No enlace la propiedad IsEnabled a otra propiedad al usar la propiedad Command para habilitar o deshabilitar el MenuItem.

En el siguiente ejemplo se muestra un MenuItem cuya propiedad Command se enlaza a un ICommand denominado MyCommand:

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

La implementación ICommand requiere un delegado canExecute que devuelve el valor de una propiedad bool para habilitar y deshabilitar el 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);
    }
}

En este ejemplo, el MenuItem se deshabilita hasta que se establece la propiedad IsMenuItemEnabled. Cuando esto ocurre, se llama al método Command.ChangeCanExecute, lo que hace que el delegado canExecute para MyCommand se vuelva a evaluar.

Comportamiento del menú contextual multiplataforma

Se accede a los menús contextuales y se muestran de forma diferente en cada plataforma.

En Android, el menú contextual se activa presionando prolongadamente en un elemento de lista. El menú contextual reemplaza el área de título y barra de navegación y las opciones MenuItem se muestran como botones horizontales.

En iOS, el menú contextual se activa deslizando el dedo en un elemento de lista. El menú contextual se muestra en el elemento de lista y MenuItems se muestra como botones horizontales.

En UWP, el menú contextual se activa haciendo clic con el botón derecho en un elemento de lista. El menú contextual se muestra cerca del cursor como una lista vertical.