ListViewの中でBindingContext内の他のプロパティをバインディングするには
例えば以下のように,ListView(CollectionView,CarouselViewなど)にバインディングするListとその他のプロパティがあるとします.
public partial class MainPage : ContentPage { public int ImageWidth { get; set; } public int ImageHeight { get; set; } public List<Person> People { get; set; } public MainPage() { InitializeComponent(); People = new List<Person>(); for (int i = 0; i < 50; i++) { People.Add(new Person { FirstName = $"FirstName{i}", LastName = $"LastName{i}", AvatarUri = $"avatar_men_{i}", }); } ImageWidth = 10; ImageHeight = 10; BindingContext = this; } }
ListViewの項目の中でImageコントロールで画像を表示させるときに,画像の幅と高さを統一するためにImageWidth
とImageHeight
を使いたいとします.
<ListView HasUnevenRows="True" ItemsSource="{Binding People}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Image HeightRequest="{Binding ImageHeight}" HorizontalOptions="Center" Source="{Binding AvatarUri}" VerticalOptions="Center" WidthRequest="{Binding ImageWidth}" /> <Label Text="{Binding FirstName}" /> <Label Text="{Binding LastName}" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
それぞれ10
としているのでかなり小さく表示されるはずですが,ごらんのとおりバインディングはきいていません.
これは当然,ListViewにバインディングされているのはPerson型のオブジェクトなので,その中にImageWidthとかいうプロパティがないからです.
このようにListViewの中で他のプロパティをバインディングしたい場合は,RelativeSource
を使って先祖(親とか親の親とか)にバインディングされているオブジェクトまで遡ってプロパティを指定します.
<Image HeightRequest="{Binding ImageHeight, Source={RelativeSource AncestorType={x:Type ContentPage}}}" HorizontalOptions="Center" Source="{Binding AvatarUri}" VerticalOptions="Center" WidthRequest="{Binding ImageWidth, Source={RelativeSource AncestorType={x:Type ContentPage}}}" />
指定のバリエーションは色々あるので公式ドキュメントなどを参照するとして,今回の例で言えばContentPageのBindingContextにMainPageを入れているので,以下のようにContentPageまで遡ってImageWidth
とImageHeight
を参照しています.
Source={RelativeSource AncestorType={x:Type ContentPage}}
もう一つの方法
調べてみたら当然のようにかずきさんのブログが見つかって,こっちのほうが直感的でわかりやすいと感じました.
ContentPageに名前をつけて,そのBindingContextからプロパティを参照するという方法です.
<ContentPage x:Class="RelativeBindingTest.MainPage" xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms/design" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="Root" mc:Ignorable="d"> <ListView HasUnevenRows="True" ItemsSource="{Binding People}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Image HeightRequest="{Binding Source={x:Reference Root}, Path=BindingContext.ImageHeight}" HorizontalOptions="Center" Source="{Binding AvatarUri}" VerticalOptions="Center" WidthRequest="{Binding Source={x:Reference Root}, Path=BindingContext.ImageWidth}" /> <Label Text="{Binding FirstName}" /> <Label Text="{Binding LastName}" /> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
相対指定よりもわかりやすいのでおすすめです.