Xamarin.Forms の相対的なバインディング
相対バインドには、バインド ターゲットの位置を基準としてバインドソースを設定する機能があります。 これらは RelativeSource
マークアップ拡張機能で作成され、バインド式の Source
プロパティとして設定されます。
RelativeSource
マークアップ拡張機能は、次のプロパティを定義する RelativeSourceExtension
クラスによってサポートされています。
RelativeBindingSourceMode
型のMode
。バインディング ターゲットの位置を基準とする相対的なバインド ソースの位置を記述します。int
型のAncestorLevel
。Mode
プロパティがFindAncestor
の場合、検索するオプションの先祖レベル。n
のAncestorLevel
は、AncestorType
のn-1
インスタンスをスキップします。Type
型のAncestorType
。Mode
プロパティがFindAncestor
の場合、検索する先祖の種類。
Note
XAML パーサーでは、RelativeSourceExtension
クラスを RelativeSource
に短縮できます。
Mode
プロパティは、RelativeBindingSourceMode
列挙型メンバーのいずれかに設定する必要があります。
TemplatedParent
は、テンプレート (バインド要素が存在する) が適用される要素を示します。 詳細については、「テンプレート化された親にバインドする」セクションを参照してください。Self
は、バインドが設定されている要素を示し、その要素の 1 つのプロパティを同じ要素の別のプロパティにバインドできます。 詳細については、「自己にバインドする」を参照してください。FindAncestor
は、バインドされた要素のビジュアル ツリーの先祖を示します。AncestorType
プロパティによって表される先祖コントロールにバインドするには、このモードを使用する必要があります。 詳細については、「先祖にバインドする」を参照してください。FindAncestorBindingContext
は、バインドされた要素のビジュアル ツリーの先祖のBindingContext
を示します。AncestorType
プロパティによって表される先祖のBindingContext
にバインドするには、このモードを使用する必要があります。 詳細については、「先祖にバインドする」を参照してください。
Mode
プロパティは、RelativeSourceExtension
クラスのコンテンツ プロパティです。 そのため、中かっこで囲まれた XAML マークアップ式では、式の Mode=
部分を削除できます。
Xamarin.Forms マークアップ拡張機能の詳細については、「XAML マークアップ拡張機能」を参照してください。
自己にバインドする
Self
の相対バインド モードは、要素のプロパティを同じ要素の別のプロパティにバインドするために使用されます。
<BoxView Color="Red"
WidthRequest="200"
HeightRequest="{Binding Source={RelativeSource Self}, Path=WidthRequest}"
HorizontalOptions="Center" />
この例では、BoxView
で WidthRequest
プロパティを固定サイズに設定し、HeightRequest
プロパティを WidthRequest
プロパティにバインドします。 したがって、両方のプロパティが等しいため、正方形が描画されます。
重要
要素のプロパティを同じ要素の別のプロパティにバインドする場合、プロパティは同じ型である必要があります。 または、バインドでコンバーターを指定して、値を変換することもできます。
このバインディング モードの一般的な用途は、オブジェクトの BindingContext
をそのプロパティに設定することです。 この例を次のコードに示します。
<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
...
</ListView>
</StackLayout>
</ContentPage>
この例では、ページの BindingContext
はその DefaultViewModel
プロパティに設定されています。 このプロパティは、ページの分離コードファイルで定義され、viewmodel インスタンスが用意されています。 ListView
は viewmodel の Employees
プロパティにバインドされます。
先祖にバインドする
FindAncestor
および FindAncestorBindingContext
の相対バインド モードは、ビジュアル ツリー内の特定の型の親要素にバインドするために使用されます。 FindAncestor
モードは、Element
型から派生した親要素にバインドするために使用されます。 FindAncestorBindingContext
モードは、親要素の BindingContext
にバインドするために使用されます。
警告
FindAncestor
および FindAncestorBindingContext
の相対バインド モードを使用する場合は、AncestorType
プロパティを Type
に設定する必要があります。それ以外の場合は、XamlParseException
がスローされます。
Mode
プロパティが明示的に設定されていない場合、AncestorType
プロパティを Element
から派生した型に設定すると、Mode
プロパティが暗黙的に FindAncestor
に設定されます。 同様に、AncestorType
プロパティを Element
から派生していない型に設定すると、Mode
プロパティは暗黙的に FindAncestorBindingContext
に設定されます。
Note
FindAncestorBindingContext
モードを使用する相対バインドは、先祖の BindingContext
が変更されたときに再適用されます。
次の XAML は、Mode
プロパティが暗黙的に FindAncestorBindingContext
に設定される例を示しています。
<ContentPage ...
BindingContext="{Binding Source={RelativeSource Self}, Path=DefaultViewModel}">
<StackLayout>
<ListView ItemsSource="{Binding Employees}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Fullname}"
VerticalOptions="Center" />
<Button Text="Delete"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:PeopleViewModel}}, Path=DeleteEmployeeCommand}"
CommandParameter="{Binding}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
この例では、ページの BindingContext
はその DefaultViewModel
プロパティに設定されています。 このプロパティは、ページの分離コードファイルで定義され、viewmodel インスタンスが用意されています。 ListView
は viewmodel の Employees
プロパティにバインドされます。 ListView
の各項目の外観を定義する DataTemplate
には、Button
が含まれています。 ボタンの Command
プロパティは、親の viewmodel の DeleteEmployeeCommand
にバインドされます。 Button
をタップすると、従業員が削除されます。
さらに、省略可能な AncestorLevel
プロパティは、ビジュアル ツリーにその型の先祖が複数存在する可能性があるシナリオで先祖検索を明確にするために役立ちます。
<Label Text="{Binding Source={RelativeSource AncestorType={x:Type Entry}, AncestorLevel=2}, Path=Text}" />
この例では、Label.Text
プロパティは、バインディングのターゲット要素から開始して、上方向へのパスで遭遇する 2 番目の Entry
のText
プロパティにバインドします。
Note
バインディング ターゲット要素に最も近い先祖を見つけるには、AncestorLevel
プロパティを 1 に設定する必要があります。
テンプレート化された親にバインドする
TemplatedParent
相対バインド モードは、コントロール テンプレート内から、テンプレートが適用されるランタイム オブジェクト インスタンス (テンプレート化された親と呼ばれます) にバインドするために使用されます。 このモードは、相対バインドがコントロール テンプレート内にある場合にのみ適用され、TemplateBinding
の設定に似ています。
次の XAML は、TemplatedParent
の相対バインド モードの例を示しています。
<ContentPage ...>
<ContentPage.Resources>
<ControlTemplate x:Key="CardViewControlTemplate">
<Frame BindingContext="{Binding Source={RelativeSource TemplatedParent}}"
BackgroundColor="{Binding CardColor}"
BorderColor="{Binding BorderColor}"
...>
<Grid>
...
<Label Text="{Binding CardTitle}"
... />
<BoxView BackgroundColor="{Binding BorderColor}"
... />
<Label Text="{Binding CardDescription}"
... />
</Grid>
</Frame>
</ControlTemplate>
</ContentPage.Resources>
<StackLayout>
<controls:CardView BorderColor="DarkGray"
CardTitle="John Doe"
CardDescription="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla elit dolor, convallis non interdum."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Jane Doe"
CardDescription="Phasellus eu convallis mi. In tempus augue eu dignissim fermentum. Morbi ut lacus vitae eros lacinia."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
<controls:CardView BorderColor="DarkGray"
CardTitle="Xamarin Monkey"
CardDescription="Aliquam sagittis, odio lacinia fermentum dictum, mi erat scelerisque erat, quis aliquet arcu."
IconBackgroundColor="SlateGray"
IconImageSource="user.png"
ControlTemplate="{StaticResource CardViewControlTemplate}" />
</StackLayout>
</ContentPage>
この例では、ControlTemplate
のルート要素である Frame
の BindingContext
には、テンプレートが適用されるランタイム オブジェクト インスタンスが設定されています。 そのため、Frame
とその子によって、各 CardView
オブジェクトのプロパティに対してバインディング式が解決されます。
コントロール テンプレートの詳細については、「Xamarin.Forms のコントロール テンプレート」を参照してください。