メモの日々


2022年01月17日(月) [長年日記]

[c#] WPFの依存関係プロパティ

WPFで独自のコントロールを作ろうとすると依存関係プロパティを扱うことになる。依存関係プロパティはドキュメントを読んでも説明が回りくどくてなかなか頭に入ってこない。

依存関係プロパティは次のようなものだと考えればいいだろうか。

  • DependencyObjectクラスのサブクラスに定義できる特殊なプロパティ
  • 依存関係プロパティに対してはXAMLから色々な操作(データバインディングとか)を行える

依存関係プロパティの作成方法

依存関係プロパティの作成方法は次のドキュメントで簡潔に説明されていた。

ここにあるコードをそのまま引用する。

public class Aquarium : DependencyObject
{
    public static readonly DependencyProperty HasFishProperty =
        DependencyProperty.Register(
            name: "HasFish",
            propertyType: typeof(bool),
            ownerType: typeof(Aquarium),
            typeMetadata: new FrameworkPropertyMetadata(defaultValue: false));

    public bool HasFish
    {
        get => (bool)GetValue(HasFishProperty);
        set => SetValue(HasFishProperty, value);
    }
}
  • DependencyProperty.Register()の戻り値を、publicなstatic readonlyフィールドとして公開する。
  • フィールド名は「<property name>Property」の形式である必要がある。
  • 上述の<property name>を通常のプロパティとして公開し、これを介して依存関係プロパティへアクセスできるようにする。
  • 必要に応じてメタデータ(上のコードではFrameworkPropertyMetadataオブジェクトにより指定している)を指定する。メタデータについては後述。

依存関係プロパティのメタデータ

メタデータは自分で定義することもできるが、標準で次の3つのクラスが用意されていて、それぞれ次のようなメタデータを扱える。

  • PropertyMetadata
    • プロパティのデフォルト値
    • 値を変更する前に呼び出される、値補正用のコールバック関数
    • 値が変更されたときに呼び出されるコールバック関数
  • UIPropertyMetadata
    • アニメーションを禁止するかどうかのフラグ。「プロパティのアニメーション」というのは値が設定値へ少しずつ近づいていくような振る舞いのようだ。
  • FrameworkPropertyMetadata
    • データバインディングに対応しているかどうかのフラグ
    • 双方向バインディングが可能かどうかのフラグ
    • 親要素の値を引き継ぐかどうかのフラグ
    • ほかにも色々