次の方法で共有


第 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 が派生します。 さらにこれを親として PageView が派生し、それは Layout に対する親クラスです。

クラス階層の共有のトリプル スクリーンショット

BindableObject と BindableProperty の詳細

BindableObject から派生したクラスでは、多くの CLR プロパティがバインド可能プロパティ "によってサポートされている" と言われます。 たとえば、Label クラスの Text プロパティは CLR プロパティですが、Label クラスでは、BindableProperty 型の TextProperty という名前のパブリックな静的読み取り専用フィールドも定義されています。

アプリケーションでは、普通に LabelText プロパティを設定または取得できます。または、Label.TextProperty 引数を使用して、BindableObject によって定義された SetValue メソッドを呼び出すことにより、Text を設定することもできます。 同様に、アプリケーションでは、やはり Label.TextProperty 引数を使用して、GetValue メソッドを呼び出すことにより、Text プロパティの値を取得できます。 これについては、PropertySettings サンプルを参照してください。

実際には、Text CLR プロパティは、BindableObjectLabel.TextProperty 静的プロパティの組み合わせによって定義された SetValue メソッドと GetValue メソッドを使用して、完全に実装されます。

BindableObjectBindableProperty では、以下に対するサポートが提供されます。

  • プロパティの既定値の指定
  • 現在の値の格納
  • プロパティ値を検証するためのメカニズムの提供
  • 1 つのクラスの関連するプロパティ間の整合性の維持
  • プロパティの変更への応答
  • プロパティが変更されようとしているとき、または変更されたときの通知のトリガー
  • データ バインディングのサポート
  • スタイルのサポート
  • 動的リソースのサポート

バインド可能プロパティによってサポートされるプロパティが変更されるたびに、BindableObject によって、変更されたプロパティを示す PropertyChanged イベントが生成されます。 プロパティが同じ値に設定されたときは、このイベントは生成されません。

一部のプロパティは、バインド可能プロパティによってサポートされていません。また、Span などの一部の Xamarin.Forms クラスは、BindableObject から派生していません。 BindableObjectSetValue メソッドと GetValue メソッドが定義されているため、BindableObject から派生したクラスのみがバインド可能プロパティをサポートできます。

SpanBindableObject から派生していないため、Text などのプロパティはどれも、バインド可能プロパティによってサポートされていません。 このため、SpanText プロパティで 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: プロパティの既定値

defaultValueobject 型であるため、コンパイラは既定値の型を決定できる必要があります。 たとえば、returnTypedouble である場合、defaultValue は単に 0 ではなく 0.0 のように設定する必要があります。そうしないと、型の不一致によって実行時に例外が発生します。

また、バインド可能プロパティに次のものが含まれるのもよくあることです。

  • propertyChanged: プロパティの値が変更されたときに呼び出される静的メソッド。 最初の引数は、プロパティが変更されたクラスのインスタンスです。

BindableProperty.Create に対する他の引数は、一般的ではありません。

  • defaultBindingMode: データ バインディングとの関係で使用されます (「第 16 章「データ バインディング」を参照)。
  • validateValue: 有効な値を確認するためのコールバック
  • propertyChanging: プロパティが変更されようとしていることを示すコールバック
  • coerceValue: set 値を別の値に強制的に変換するためのコールバック
  • defaultValueCreate: クラスのインスタンス間で共有できない既定値を作成するためのコールバック (たとえば、コレクション)

読み取り専用のバインド可能プロパティ

バインド可能プロパティは読み取り専用にできます。 読み取り専用のバインド可能プロパティを作成するには、静的メソッド BindableProperty.CreateReadOnly を呼び出して、BindablePropertyKey 型のプライベートな静的読み取り専用フィールドを定義する必要があります。

次に、BindablePropertyKey オブジェクトで SetValue のオーバーロードを呼び出すために、CLR プロパティの set アクセサーを private として定義します。 これにより、プロパティがクラスの外部で設定されるのを防ぐことができます。

これについては、BaskervillesCount サンプルで使用されている CountedLabel クラスで示されています。