Xamarin – реализация меню

Автор:

learn.microsoft.com

Класс Xamarin.Forms MenuItem определяет элементы для контекстных меню элементов ListView и всплывающих меню для приложений Shell.

На следующих скриншотах показаны объекты MenuItem в контекстном меню ListView на iOS и Android:

объекты MenuItem в контекстном меню ListView

Класс MenuItem определяет следующие свойства:

  • Command – ICommand, позволяющий привязывать действия пользователя, такие как касания пальцем или щелчки, к командам, определенным на вью-модели.
  • CommandParameter – объект, определяющий параметр, который должен быть передан команде.
  • IconImageSource – значение ImageSource, определяющее иконку дисплея.
  • IsDestructive – bool-значение, указывающее, удаляет ли данный MenuItem связанный с ним элемент пользовательского интерфейса из списка.
  • IsEnabled – bool-значение, указывающее, реагирует ли данный объект на ввод пользователя.
  • Text – строковое значение, задающее текст отображения.

Эти свойства поддерживаются объектами BindableProperty, поэтому экземпляр MenuItem может быть объектом привязки данных.

Создание MenuItem

Объекты MenuItem могут использоваться в контекстном меню Xamarin для элементов объекта ListView. Чаще всего такие объекты создаются в экземпляре ViewCell, который используется в качестве объекта DataTemplate для шаблона элементов ListView. Когда объект ListView заполняется, он создает каждый элемент с использованием шаблона DataTemplate, раскрывая возможности выбора MenuItem при активации контекстного меню для элемента.

Следующий пример показывает реализацию MenuItem в контексте объекта ListView:

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

MenuItem также может быть создан в коде:

C#

// 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. К этому событию может быть присоединен хэндлер, реагирующий на нажатия или клики на элемент MenuItem в XAML:

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

Обработчик события также может быть вложен в код:

C#

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

В предыдущих примерах упоминался обработчик события OnItemClicked. В следующем коде показан пример его реализации:

C#

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
}

Определение поведения MenuItem с помощью MVVM

Класс MenuItem поддерживает паттерн Model-View-ViewModel (MVVM) с помощью объектов BindableProperty и интерфейса ICommand. Следующий XAML показывает экземпляры MenuItem, привязанные к командам, определенным на ViewModel:

<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, свойства которых Command и CommandParameter привязаны к командам на модели представления. Модель представления содержит команды, на которые ссылается XAML:

public class ListPageViewModel : INotifyPropertyChanged
{
   ...
 
   public ICommand EditCommand => new Command((string item) =>
   {
       Message = $"Edit command was called on: {item}";
   });
 
   public ICommand DeleteCommand => new Command((string item) =>
   {
       Message = $"Delete command was called on: {item}";
   });
}

Пример приложения включает класс DataService, который используется для получения списка элементов для заполнения объектов ListView. Реализуется ViewModel с элементами из класса DataService и устанавливается в качестве BindingContext в код:

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

Иконки MenuItem

Предупреждение. Объекты MenuItem отображают значки только на Android. На других платформах будет отображаться только текст, заданный свойством Text.

Иконки указываются с помощью свойства IconImageSource. Если задан значок, то текст, указанный в свойстве Text, отображаться не будет. На следующем снимке экрана показан MenuItem с иконкой на Android:

Иконки MenuItem

Включение и отключение пункта меню во время выполнения программы

Чтобы включить или выключить элемент меню во время выполнения, привяжите его свойство Command к реализации ICommand и убедитесь, что canExecute включает и выключает ICommand в зависимости от ситуации.

Важно. Не связывайте свойство IsEnabled с другим свойством при использовании свойства Command для включения или выключения MenuItem.

В следующем примере показан MenuItem, свойство Command которого связывается с ICommand с именем MyCommand:

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

В данном примере элемент MenuItem отключен до тех пор, пока не будет установлено свойство IsMenuItemEnabled. Когда это происходит, вызывается метод Command.ChangeCanExecute, который приводит к переоценке делегата canExecute для MyCommand.

Кроссплатформенное поведение контекстного меню

Доступ к контекстному меню и его отображение на каждой платформе осуществляется по-разному.

На Android контекстное меню активируется долгим нажатием на элемент списка. Контекстное меню заменяет область заголовка и навигационной панели, а опции MenuItem отображаются в виде горизонтальных кнопок.

Android контекстное меню

В iOS контекстное меню активируется при проведении пальцем по элементу списка. Контекстное меню отображается на элементе списка, а MenuItems отображаются в виде горизонтальных кнопок.

iOS контекстное меню

В UWP контекстное меню активируется щелчком правой кнопки мыши на элементе списка. Контекстное меню отображается рядом с курсором в виде вертикального списка.

UWP контекстное меню

Материалы по теме