第 11 章の概要: バインド可能なインフラストラクチャ
Note
この本は 2016 年春に発行されて以降、改訂されていません。 多くの情報はまだ価値がありますが、一部の資料は古くなっており、トピックの中にはまったく正しくないものまたは不完全なものもあります。
すべての C# プログラマは、C# の "プロパティ" について理解しています。 プロパティには、set アクセサーと get アクセサーのどちらか一方または両方が含まれます。 それらは、共通言語ランタイムの "CLR プロパティ" と呼ばれることがよくあります。
Xamarin.Forms では、BindableProperty
クラスによってカプセル化され、BindableObject
クラスによってサポートされる、"バインド可能プロパティ" と呼ばれる拡張プロパティ定義が定義されています。 これらのクラスは関連していますが、全く異なるものです。BindableProperty
は、プロパティ自体を定義するために使用されます。BindableObject
は、バインド可能プロパティを定義するクラスの基底クラスであるという点で object
に似ています。
Xamarin.Forms のクラス階層
ClassHierarchy サンプルでは、リフレクションを使用して Xamarin.Forms のクラス階層が表示され、この階層において BindableObject
によって果たされる重要な役割が示されています。 BindableObject
は、Object
から派生し、それを親クラスとする Element
から、VisualElement
が派生します。 さらにこれを親として Page
と View
が派生し、それは Layout
に対する親クラスです。
BindableObject と BindableProperty の詳細
BindableObject
から派生したクラスでは、多くの CLR プロパティがバインド可能プロパティ "によってサポートされている" と言われます。 たとえば、Label
クラスの Text
プロパティは CLR プロパティですが、Label
クラスでは、BindableProperty
型の TextProperty
という名前のパブリックな静的読み取り専用フィールドも定義されています。
アプリケーションでは、普通に Label
の Text
プロパティを設定または取得できます。または、Label.TextProperty
引数を使用して、BindableObject
によって定義された SetValue
メソッドを呼び出すことにより、Text
を設定することもできます。 同様に、アプリケーションでは、やはり Label.TextProperty
引数を使用して、GetValue
メソッドを呼び出すことにより、Text
プロパティの値を取得できます。 これについては、PropertySettings サンプルを参照してください。
実際には、Text
CLR プロパティは、BindableObject
と Label.TextProperty
静的プロパティの組み合わせによって定義された SetValue
メソッドと GetValue
メソッドを使用して、完全に実装されます。
BindableObject
と BindableProperty
では、以下に対するサポートが提供されます。
- プロパティの既定値の指定
- 現在の値の格納
- プロパティ値を検証するためのメカニズムの提供
- 1 つのクラスの関連するプロパティ間の整合性の維持
- プロパティの変更への応答
- プロパティが変更されようとしているとき、または変更されたときの通知のトリガー
- データ バインディングのサポート
- スタイルのサポート
- 動的リソースのサポート
バインド可能プロパティによってサポートされるプロパティが変更されるたびに、BindableObject
によって、変更されたプロパティを示す PropertyChanged
イベントが生成されます。 プロパティが同じ値に設定されたときは、このイベントは生成されません。
一部のプロパティは、バインド可能プロパティによってサポートされていません。また、Span
などの一部の Xamarin.Forms クラスは、BindableObject
から派生していません。 BindableObject
で SetValue
メソッドと GetValue
メソッドが定義されているため、BindableObject
から派生したクラスのみがバインド可能プロパティをサポートできます。
Span
は BindableObject
から派生していないため、Text
などのプロパティはどれも、バインド可能プロパティによってサポートされていません。 このため、Span
の Text
プロパティで DynamicResource
を設定すると、前の章の DynamicVsStatic サンプルで例外が発生します。 DynamicVsStaticCode サンプルでは、Element
によって定義された SetDynamicResource
メソッドを使用して、コードで動的リソースを設定する方法が示されています。 最初の引数は BindableProperty
型のオブジェクトです。
同様に、BindableObject
で定義された SetBinding
メソッドの最初の引数は、BindableProperty
型です。
バインド可能プロパティの定義
静的メソッド BindableProperty.Create
を使用して BindableProperty
型の静的読み取り専用フィールドを作成し、独自のバインド可能プロパティを定義できます。
これについては、Xamarin.FormsBook.Toolkit ライブラリの AltLabel
クラスで示されています。 そのクラスは Label
から派生し、フォント サイズをポイント単位で指定できます。 PointSizedText サンプルを参照してください。
BindableProperty.Create
メソッドの 4 つの引数は必須です。
propertyName
: プロパティのテキスト名 (CLR プロパティ名と同じ)returnType
: CLR プロパティの型declaringType
: プロパティを宣言するクラスの型defaultValue
: プロパティの既定値
defaultValue
は object
型であるため、コンパイラは既定値の型を決定できる必要があります。 たとえば、returnType
が double
である場合、defaultValue
は単に 0 ではなく 0.0 のように設定する必要があります。そうしないと、型の不一致によって実行時に例外が発生します。
また、バインド可能プロパティに次のものが含まれるのもよくあることです。
propertyChanged
: プロパティの値が変更されたときに呼び出される静的メソッド。 最初の引数は、プロパティが変更されたクラスのインスタンスです。
BindableProperty.Create
に対する他の引数は、一般的ではありません。
defaultBindingMode
: データ バインディングとの関係で使用されます (「第 16 章「データ バインディング」を参照)。validateValue
: 有効な値を確認するためのコールバックpropertyChanging
: プロパティが変更されようとしていることを示すコールバックcoerceValue
: set 値を別の値に強制的に変換するためのコールバックdefaultValueCreate
: クラスのインスタンス間で共有できない既定値を作成するためのコールバック (たとえば、コレクション)
読み取り専用のバインド可能プロパティ
バインド可能プロパティは読み取り専用にできます。 読み取り専用のバインド可能プロパティを作成するには、静的メソッド BindableProperty.CreateReadOnly
を呼び出して、BindablePropertyKey
型のプライベートな静的読み取り専用フィールドを定義する必要があります。
次に、BindablePropertyKey
オブジェクトで SetValue
のオーバーロードを呼び出すために、CLR プロパティの set
アクセサーを private
として定義します。 これにより、プロパティがクラスの外部で設定されるのを防ぐことができます。
これについては、BaskervillesCount サンプルで使用されている CountedLabel
クラスで示されています。