Xamarin.Forms のバインド パス

Download Sampleサンプルのダウンロード

これまでのすべてのデータ バインディング例では、Binding クラスの Path プロパティ (または Binding マークアップ拡張の Path プロパティ) が単一のプロパティに設定されていました。 実際には、Pathサブ プロパティ (プロパティのプロパティ) またはコレクションのメンバーに設定することができます。

たとえば、ページに TimePicker が含まれるとします。

<TimePicker x:Name="timePicker">

TimePickerTime プロパティは TimeSpan 型ですが、その TimeSpan 値の TotalSeconds プロパティを参照するデータ バインディングを作成することが必要になる可能性があります。 次に、そのデータ バインディングを示します。

{Binding Source={x:Reference timePicker},
         Path=Time.TotalSeconds}

Time プロパティは TimeSpan 型で、TotalSeconds プロパティがあります。 Time プロパティと TotalSeconds プロパティは、ピリオドで連結されます。 Path 文字列内の項目は常にプロパティを参照し、これらのプロパティの型を参照しません。

Path Variations ページでは、その例といくつかのその他の例が示されます。

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:globe="clr-namespace:System.Globalization;assembly=netstandard"
             x:Class="DataBindingDemos.PathVariationsPage"
             Title="Path Variations"
             x:Name="page">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="Large" />
                <Setter Property="HorizontalTextAlignment" Value="Center" />
                <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <StackLayout Margin="10, 0">
        <TimePicker x:Name="timePicker" />

        <Label Text="{Binding Source={x:Reference timePicker},
                              Path=Time.TotalSeconds,
                              StringFormat='{0} total seconds'}" />

        <Label Text="{Binding Source={x:Reference page},
                              Path=Content.Children.Count,
                              StringFormat='There are {0} children in this StackLayout'}" />

        <Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
                              Path=DateTimeFormat.DayNames[3],
                              StringFormat='The middle day of the week is {0}'}" />

        <Label>
            <Label.Text>
                <Binding Path="DateTimeFormat.DayNames[3]"
                         StringFormat="The middle day of the week in France is {0}">
                    <Binding.Source>
                        <globe:CultureInfo>
                            <x:Arguments>
                                <x:String>fr-FR</x:String>
                            </x:Arguments>
                        </globe:CultureInfo>
                    </Binding.Source>
                </Binding>
            </Label.Text>
        </Label>

        <Label Text="{Binding Source={x:Reference page},
                              Path=Content.Children[1].Text.Length,
                              StringFormat='The second Label has {0} characters'}" />
    </StackLayout>
</ContentPage>

2 番目の Label では、ページそのものがバインディング ソースです。 Content プロパティは StackLayout 型で、IList<View> 型の Children プロパティがあり、このプロパティには、子の個数を示す Count プロパティがあります。

インデクサーを含むパス

Path Variations ページの 3 番目の Label 内のバインドは、System.Globalization 名前空間内の CultureInfo クラスを参照します。

<Label Text="{Binding Source={x:Static globe:CultureInfo.CurrentCulture},
                      Path=DateTimeFormat.DayNames[3],
                      StringFormat='The middle day of the week is {0}'}" />

ソースは、静的な CultureInfo.CurrentCulture プロパティに設定されます。これは、CultureInfo 型のオブジェクトです。 そのクラスは DateTimeFormat という名前の DateTimeFormatInfo 型で、DayNames コレクションが含まれます。 インデックスは 4 番目の項目を選択します。

4 番目の Label も同様のことを実行しますが、フランスに関連付けられたカルチャ用です。 バインドの Source プロパティは、コンストラクターを持つ CultureInfo オブジェクトに設定されます。

<Label>
    <Label.Text>
        <Binding Path="DateTimeFormat.DayNames[3]"
                 StringFormat="The middle day of the week in France is {0}">
            <Binding.Source>
                <globe:CultureInfo>
                    <x:Arguments>
                        <x:String>fr-FR</x:String>
                    </x:Arguments>
                </globe:CultureInfo>
            </Binding.Source>
        </Binding>
    </Label.Text>
</Label>

XAML でコンストラクター引数を指定する方法の詳細については、「コンストラクター引数の受け渡し」を参照してください。

最後に、最後の例は 2 番目の例とよく似ています。ただし、この例では、StackLayout の子の 1 つを参照します。

<Label Text="{Binding Source={x:Reference page},
                      Path=Content.Children[1].Text.Length,
                      StringFormat='The first Label has {0} characters'}" />

その子は Label で、String 型の Text プロパティがあり、そのプロパティには Length プロパティがあります。 最初の LabelTimePicker 内の TimeSpan 設定を報告するので、テキストが変更されると、最後の Label も変更されます。

実行中のプログラムを次に示します。

Path Variations

複雑なパスのデバッグ

複雑なパスの定義は、作成が困難になる場合があります。つまり、次のサブ プロパティを正しく追加するには、各サブ プロパティの型またはコレクション内の項目の型を知る必要がありますが、型自体はパスに表示されません。 1 つの適切な手法は、パスを 1 つずつ増分して構築しながら、その間の結果を観察することです。 この最後の例では、Path 定義のないパスから開始します。

<Label Text="{Binding Source={x:Reference page},
                      StringFormat='{0}'}" />

これは、バインド ソース型または DataBindingDemos.PathVariationsPage を表示します。 PathVariationsPageContentPage から派生することがわかっているので、これには Content プロパティがあります。

<Label Text="{Binding Source={x:Reference page},
                      Path=Content,
                      StringFormat='{0}'}" />

これで、Content プロパティの型は Xamarin.Forms.StackLayout であることが明らかになります。 Childrenプロパティを Path に追加すると、型は Xamarin.Forms.ElementCollection'1[Xamarin.Forms.View] です。これは、Xamarin.Forms 内部のクラスですが、明らかにコレクション型です。 これにインデックスを追加すると、型は Xamarin.Forms.Label です。 この方法で続行します。

Xamarin.Forms は、バインド パスを処理するので、INotifyPropertyChanged インターフェイスを実装するパス内のいずれかのオブジェクトに PropertyChanged ハンドラーをインストールします。 たとえば、Text プロパティが変更されるため、最後のバインドは最初の Label の変更に対応します。

バインド パス内のプロパティが INotifyPropertyChanged を実装しない場合、そのプロパティに対する変更は無視されます。 一部の変更はバインド パスを完全に無効にするため、プロパティおよびサブ プロパティの文字列が絶対に無効にならない場合にのみ、この手法を使用する必要があります。