読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Xamarin.FormsでListViewのItemTemplate内のボタンにPageにバインドされているVMにあるCommandをバインドする方法

Xamarin XAML

こういうの悩みますよね。例えば以下のようなViewModelがあるとします。こいつのAlertCommandに選択項目を渡したいというケースです。

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Xamarin.Forms;

namespace App52
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<string> Items { get; } = new ObservableCollection<string>(Enumerable.Range(1, 100)
            .Select(x => $"Item{x}"));

        public Command AlertCommand { get; }

        public MainPageViewModel()
        {
            this.AlertCommand = new Command<string>(x =>
            {
                Debug.WriteLine($"Execute: {x}");
            });
        }
    }
}

こういう感じのXAMLでいけます。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:App52="clr-namespace:App52;assembly=App52"
             x:Class="App52.MainPage"
             x:Name="Root">
  <ContentPage.BindingContext>
    <App52:MainPageViewModel />
  </ContentPage.BindingContext>
  <ListView ItemsSource="{Binding Items}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <StackLayout Orientation="Horizontal">
            <Label Text="{Binding}" />
            <Button Text="Alert"
                    Command="{Binding Source={x:Reference Root}, Path=BindingContext.AlertCommand}"
                    CommandParameter="{Binding}" />
          </StackLayout>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

x:Referenceでページ自体をSourceに指定して、そこからVMのCommandをPathで指定しています。あとは、CommandParameterに渡したい要素をBindingしてやるだけ。これで動くようになります。めでたしめでたし。