vorfee's Tech Blog

Just another tech blog

WPFの依存関係プロパティとは?添付プロパティとは?

注意:本記事は独学による個人的な備忘録のため、誤りが含まれる可能性があります。

依存関係プロパティ(DependencyProperty)

DependencyPropertyWPFプロパティシステム を構成する機能の一つである。

添付プロパティ(Attached Property)

添付プロパティWPFプロパティシステムにおける DependencyProperty の形態の一つである。

依存関係プロパティの概要

.NET 共通型システムには Property が定義されている。いわゆるC#の Property のことだが、ここでは区別のため CLR Property と表記する。

DependencyProperty は CLR Property をラッピングし、WPFプロパティシステム で利用される。平たく言うと、DependencyProperty とは WPF が外部拡張性を獲得し、コントロールをうまく制御するために作られた仕組みの一部のことだ。

WPFのコントロールは例外なく DependencyObject を基底クラスに持つ。これはオブジェクトがWPFプロパティシステムに参加したければ、必ず DependencyObject を基底クラスに持たなくてはいけないというルールがあるからだ。

添付プロパティの概要

添付プロパティは WPFプロパティシステムの機能の1つで、WPFのコントロールに備わっていないDependencyPropertyを、あたかも初めから備わっていたかのように振舞わせることができる機能である。

添付プロパティってどんなの?

WPFを使用するうえで意識することはないが、添付プロパティは普段から頻繁に利用している。例えば以下のようなXAMLも添付プロパティを利用している。どれが添付プロパティか分かるだろうか?

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100"/>
    <ColumnDefinition Width="300"/>
  </Grid.ColumnDefinitions>
  <TextBlock Grid.Column="0" Text="あいうえお"/>
  <TextBlock Grid.Column="1" Text="かきくけこ"/>
</Grid>

Grid.Column="0" の部分が添付プロパティである。しかし、TextBlock の定義を見ても Grid.Column というプロパティは存在しない*1。では次の例はどうだろうか?

<Canvas>
  <Rectangle Canvas.Top="20" Canvas.Left="55" Width="30" Height="100" Fill="Red"/>
</Canvas>

Canvas.Top="20"の部分が添付プロパティである。ところが Rectangle の定義を見ても Canvas.Top というプロパティは見当たらない。

このように、そのコントロール自体にプロパティが存在しないが、添付プロパティを使用することでコントロールに後付けで DependencyProperty を追加し、値を保持することができる。

先の例において、添付プロパティのCanvas.Top が Rectangle に指定されている。Canvas.Top は Canvas がRectangleを描画する際の絶対座標である。つまり、この値を利用するのはCanvasであり、Rectangle自身はこの値を使用しないが、値を保持できている。

添付プロパティが無かったら何がマズい?

勉強の理解を深めるときに逆転の発想をするのは良いことだ。だから、添付プロパティが無かったらどうなるか想像してみることにする。

もし 添付プロパティ がなかったら、Canvasの実装 はどうなるだろうか?

Canvasの機能要件(例)

  • Canvasは、子に複数個のコントロールを持つことができる
  • Canvasは、子のコントロールにLeft, Topの絶対座標を指定して並べることができる

添付プロパティ無しでこれらの要件を満たすためには、Canvasが子に持つことができるすべてのコントロールにTop、Leftプロパティを定義しなければいけないだろう。きっとMicrosoftの.NETチームはICanvasChildみたいな名前のインターフェースを用意して、Canvasに描画可能なコントロールすべてにこれを実装することになる。

では中心の絶対座標を指定して配置できるようなMyCanvasというコントロールを自作したとする。

MyCanvasの機能要件(例)

  • MyCanvasは、子に複数個のコントロールを持つことができる
  • MyCanvasは、子のコントロールにCenterの絶対座標を指定して並べることができる

このコントロールの子はCenterというプロパティが必要で、IMyCanvasChildを実装しなければならない。するとどうだろう、Microsoftの.NETチームはそんなものを知らないので、WPFのすべてのコントロールはIMyCanvasChildを実装していない。なのでWPFのコントロールはMyCanvasで一切利用できない。

これでは拡張性が無さ過ぎて使い物にならないのは明らかである。だから添付プロパティはWPFの柔軟な拡張性に大きく寄与していることがやんわりと理解できる。

添付プロパティの用途は?

そのうち時間ができたら追記予定・・・

*1:そもそも.NETではプロパティ名にピリオドは使用できないことからも、このプロパティが異質であることが見て取れる