次の方法で共有


Xamarin.Forms の相対的なバインディング

相対バインドには、バインド ターゲットの位置を基準としてバインドソースを設定する機能があります。 これらは RelativeSource マークアップ拡張機能で作成され、バインド式の Source プロパティとして設定されます。

RelativeSource マークアップ拡張機能は、次のプロパティを定義する RelativeSourceExtension クラスによってサポートされています。

  • RelativeBindingSourceMode 型の Mode。バインディング ターゲットの位置を基準とする相対的なバインド ソースの位置を記述します。
  • int 型の AncestorLevelMode プロパティが FindAncestor の場合、検索するオプションの先祖レベル。 nAncestorLevel は、AncestorTypen-1 インスタンスをスキップします。
  • Type 型の AncestorTypeMode プロパティが 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" />

この例では、BoxViewWidthRequest プロパティを固定サイズに設定し、HeightRequest プロパティを WidthRequest プロパティにバインドします。 したがって、両方のプロパティが等しいため、正方形が描画されます。

iOS および Android 上のセルフ モードの相対バインドのスクリーンショット

重要

要素のプロパティを同じ要素の別のプロパティにバインドする場合、プロパティは同じ型である必要があります。 または、バインドでコンバーターを指定して、値を変換することもできます。

このバインディング モードの一般的な用途は、オブジェクトの 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 をタップすると、従業員が削除されます。

iOS および Android 上の FindAncestor モードの相対バインドのスクリーンショット

さらに、省略可能な AncestorLevel プロパティは、ビジュアル ツリーにその型の先祖が複数存在する可能性があるシナリオで先祖検索を明確にするために役立ちます。

<Label Text="{Binding Source={RelativeSource AncestorType={x:Type Entry}, AncestorLevel=2}, Path=Text}" />

この例では、Label.Text プロパティは、バインディングのターゲット要素から開始して、上方向へのパスで遭遇する 2 番目の EntryText プロパティにバインドします。

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 のルート要素である FrameBindingContext には、テンプレートが適用されるランタイム オブジェクト インスタンスが設定されています。 そのため、Frame とその子によって、各 CardView オブジェクトのプロパティに対してバインディング式が解決されます。

iOS および Android 上の TemplatedParent モードの相対バインドのスクリーンショット

コントロール テンプレートの詳細については、「Xamarin.Forms のコントロール テンプレート」を参照してください。