Xamarin.Forms DataTemplate内でViewModelのプロパティをBindする方法

Xamarn.FormsのListViewなどを使用している際、ViewModel内のプロパティをBindしたい時があったりするかと思います。ItemsSourceのモデル内にBind用のプロパティを持たせ、1つ1つに値を入れていくといったやり方だとスマートではありません。

そういった実装をしなくてもViewModelのプロパティを直接Bindする方法があるので、今回はその方法について説明します。

例えばテキストとボタンがあるリストを例とすると、データバインドしてリストを表示するとなると、Viewはこのような感じで、

<ContentPage
  xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  x:Class="Test.Hoge">
  <ListView
    HorizontalOptions="FillAndExpand"
    VerticalOptions="FillAndExpand"
    ItemsSource="{Binding Persons}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <StackLayout
            HorizontalOptions="FillAndExpand"
            HeightRequest="50">
            <Label
              Text="{Binding Name}"/>
            <Button
              WidthRequest="100"
              HeightRequest="20"
              Text="Click"
              Command="{Binding ClickCommand}"/>
          </StackLayout>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

下記のようなデータバインド用のモデルを準備し、

public class Person {
    public string Name {get; set;}
    public string ClickCommand {get; set;}
}

ViewModelは

public class HogeViewModel {
    public ObservableCollection<Person> Persons { get; set; }

    public Command ListClickCommand => new Command(() => { System.Diagnostics.Debug.Write("Click!"); });
    public HogeViewModel() {
        Persons = new ObservableCollection<Person>() {
            new Person() { Name = "田中", ClickCommand = ListClickCommand },
            new Person() { Name = "山田", ClickCommand = ListClickCommand },
            new Person() { Name = "佐藤", ClickCommand = ListClickCommand }
        };
    }
}

↑のような感じになります。

PersonクラスのClickCommandにViewModelのListClickCommandを1つ1つ代入していますが、ListClickCommandをそのままBindできたら楽ですよね。

それを実現する方法が下記です。

<ContentPage
  xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  x:Class="Test.Hoge"
  x:Name="This">
  <ListView
    HorizontalOptions="FillAndExpand"
    VerticalOptions="FillAndExpand"
    ItemsSource="{Binding Persons}">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <StackLayout
            HorizontalOptions="FillAndExpand"
            HeightRequest="50">
            <Label
              Text="{Binding Name}"/>
            <Button
              WidthRequest="100"
              HeightRequest="20"
              Text="Click"
              Command="{Binding Source={x:Reference This}, Path=BindingContext.ListClickCommand}"/>
          </StackLayout>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>

ViewのContentPageにx:Nameで名前をつけ、
{Binding Source={x:Reference This}, Path=BindingContext.ListClickCommand}
↑このようにしてつけた名前を参照し、PathをBindingContext.プロパティ名で指定してあげると、ViewModelのプロパティを直でBindすることが可能になります。

タイトルとURLをコピーしました