依存関係プロパティの概要
Windows Presentation Foundation (WPF) には、common language runtime (CLR) プロパティの機能を拡張するために使用できる一連のサービスが用意されています。 通常、これらのサービスをまとめて WPF プロパティ システムと呼びます。 WPF プロパティ システムによってサポートされるプロパティは、依存関係プロパティと呼ばれています。ここでは、WPF プロパティ システムについて、および依存関係プロパティの機能について説明します。この説明では、既存の依存関係プロパティを XAML およびコードで使用する方法を示します。 また、依存関係プロパティ メタデータなどの依存関係プロパティの特殊な側面や、カスタム クラスで独自の依存関係プロパティを作成する方法についても説明します。
このトピックは、次のセクションで構成されています。
- 必要条件
- 依存関係プロパティおよび CLR プロパティ
- 依存関係プロパティによる CLR プロパティの補足
- プロパティ値の設定
- 依存関係プロパティによって提供されるプロパティ機能
- 依存関係プロパティ値の優先順位
- 依存関係プロパティの詳細情報
- 関連トピック
必要条件
ここでは、CLR およびオブジェクト指向プログラミングに関する基礎知識があることを前提にしています。 このトピックの例に従うには、XAML について理解し、WPF アプリケーションの作成方法に精通している必要があります。 詳細については、「チュートリアル: WPF の概要」を参照してください。
依存関係プロパティおよび CLR プロパティ
WPF では通常、プロパティはcommon language runtime (CLR) プロパティとして公開されます。 基本的なレベルでは、これらのプロパティと直接対話でき、これらのプロパティが依存関係として実装されることを認識することはありません。 ただし、WPF プロパティ システムの一部またはすべての機能を利用できるように、これらの機能に精通しておく必要があります。
依存関係プロパティの目的は、他の入力の値に基づいてプロパティの値を計算する方法を提供することです。 他の入力には、テーマやユーザー設定などのシステム プロパティ、データ バインディングやアニメーション/ストーリーボードなどのジャスト イン タイム プロパティ判定機構、リソースやスタイルなどの多目的のテンプレート、要素ツリー内の他の要素との親子のリレーションシップから判断される値などがあります。 また、依存関係プロパティを実装して、自己完結型の検証、既定値、他のプロパティに対する変更を監視するコールバック、およびランタイム情報の可能性がある情報に基づいてプロパティ値を強制するシステムを提供できます。 既存のプロパティの実際の実装をオーバーライドしたり新しいプロパティを作成したりするのではなく、依存関係プロパティ メタデータをオーバーライドすることによって、派生クラスで既存のプロパティの特定の特性を変更することもできます。
SDK リファレンスで、プロパティのマネージ リファレンス ページの「依存関係プロパティの情報」セクションの有無によって、どのプロパティが依存関係プロパティかを特定できます。 「依存関係プロパティの情報」セクションにはその依存関係プロパティの DependencyProperty 識別子フィールドへのリンクがあり、そのプロパティに設定されるメタデータ オプションのリスト、クラスごとのオーバーライド情報、およびその他の詳細も示されています。
依存関係プロパティによる CLR プロパティの補足
依存関係プロパティおよび WPF プロパティ システムは、プライベート フィールドでプロパティをサポートする標準パターンの代替実装として、プロパティをサポートする型を提供することによって、プロパティ機能を拡張します。 この型の名前は DependencyProperty です。 WPF プロパティ システムを定義するもう 1 つの重要な型は DependencyObject です。DependencyObject は、依存関係プロパティを登録および所有できる基本クラスを定義します。
依存関係プロパティについて説明するときにこのsoftware development kit (SDK) ドキュメントで使用する用語の概要を次に示します。
依存関係プロパティ : DependencyProperty によってサポートされるプロパティ。
依存関係プロパティの識別子: 依存関係プロパティの登録時に戻り値として取得され、クラスの静的メンバーとして格納される DependencyProperty インスタンス。 この識別子は、WPF プロパティ システムと対話する多くの APIs でパラメーターとして使用されます。
CLR "ラッパー" : プロパティの実際の get および set 実装。 これらの実装は、依存関係プロパティの識別子を GetValue および SetValue の呼び出しで使用し、WPF プロパティ システムを使用してプロパティの補足を提供することによって、その識別子を組み込みます。
次の例では、IsSpinning 依存関係プロパティを定義し、DependencyProperty 識別子とサポートされるプロパティの関係を示します。
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
DependencyProperty.Register("IsSpinning",
GetType(Boolean),
GetType(MyCode))
Public Property IsSpinning() As Boolean
Get
Return CBool(GetValue(IsSpinningProperty))
End Get
Set(ByVal value As Boolean)
SetValue(IsSpinningProperty, value)
End Set
End Property
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean),
...
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
プロパティとそれを補足する DependencyProperty フィールドの名前付け規則は重要です。 フィールドの名前は常にプロパティの名前であり、サフィックス Property が追加されます。 この規則とその理由の詳細については、「カスタム依存関係プロパティ」を参照してください。
プロパティ値の設定
コードまたは XAML でプロパティを設定できます。
XAML でのプロパティ値の設定
ボタンの背景色を赤に指定する方法を次の XAML の例に示します。 この例では、生成されたコードで XAML 属性の単純な文字列値が WPF XAML パーサーによって WPF 型 (SolidColorBrush を使用した Color) に型変換される場合を示します。
<Button Background="Red" Content="Button!"/>
XAML は、プロパティを設定するためのさまざまな構文形式をサポートします。 特定のプロパティに対してどの構文を使用するかは、プロパティで使用される値型、および型コンバーターの有無などのその他の要素によって決定されます。 プロパティ設定の XAML 構文の詳細については、「XAML の概要 (WPF)」および「XAML 構文の詳細」を参照してください。
属性以外の構文の例として、別のボタンの背景を次の XAML の例に示します。 今回は単純な純色を設定するのではなく、背景をイメージに設定し、そのイメージおよびそのイメージのソースを表す要素を、入れ子にした要素の属性として指定します。 これは、プロパティ要素構文の例です。
<Button Content="Button!">
<Button.Background>
<ImageBrush ImageSource="wavy.jpg"/>
</Button.Background>
</Button>
コードでのプロパティの設定
依存関係プロパティの値をコードで設定するには、通常、CLR "ラッパー" によって公開される set 実装を呼び出すだけで済みます。
Dim myButton As New Button()
myButton.Width = 200.0
Button myButton = new Button();
myButton.Width = 200.0;
プロパティ値を取得する場合も、基本的に get "ラッパー" 実装を呼び出します。
Dim whatWidth As Double
whatWidth = myButton.Width
double whatWidth;
whatWidth = myButton.Width;
また、プロパティ システム APIs GetValue および SetValue を直接呼び出すこともできます。 これは通常、既存のプロパティを使用する場合は不要ですが (ラッパーの方が便利で、開発者ツール用のより優れたプロパティが公開されます)、APIs を直接呼び出す方法は、特定のシナリオに適しています。
プロパティは、XAML で設定してから分離コードを介してコードでアクセスすることもできます。 詳細については、「WPF における分離コードと XAML」を参照してください。
依存関係プロパティによって提供されるプロパティ機能
依存関係プロパティは、フィールドによって補足されるプロパティとは対照的に、プロパティの機能を拡張する機能を提供します。 多くの場合、このような機能のそれぞれが、WPF 全体の機能セットの特定の機能を表したりサポートしたりします。
リソース
データ バインディング
スタイル
アニメーション
メタデータのオーバーライド
プロパティ値の継承
WPF デザイナーの統合
リソース
依存関係プロパティの値は、リソースを参照することによって設定できます。 リソースは通常、ページのルート要素またはアプリケーションの Resources プロパティ値として指定されます (これらの場所を使用することが、リソースにアクセスするのに最も便利な方法です)。 SolidColorBrush リソースを定義する方法を次の例に示します。
<DockPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>
リソースを定義すると、リソースを参照し、そのリソースを使用してプロパティ値を指定できるようになります。
<Button Background="{DynamicResource MyBrush}" Content="I am gold" />
この特定のリソースは、DynamicResource のマークアップ拡張機能 として参照されます (WPF XAML では、静的リソース参照または動的リソース参照を使用できます)。 動的リソース参照を使用するには、依存関係プロパティに設定している必要があるため、これは具体的には、WPF プロパティ システムによって有効になる動的リソース参照の使用方法になります。 詳細については、「リソースの概要」を参照してください。
メモ |
---|
リソースはローカル値として扱われます。つまり、別のローカル値を設定すると、リソース参照がなくなります。詳細については、「依存関係プロパティ値の優先順位」を参照してください。 |
データ バインディング
依存関係プロパティは、データ バインディングを介して値を参照できます。 データ バインドは、XAML で特定のマークアップ拡張機能構文を介して機能するか、コードで Binding オブジェクトを介して機能します。 データ バインディングを使用すると、プロパティ値の最終的な決定が、データ ソースから値が取得される実行時まで延期されます。
XAML で宣言されたバインディングを使用して、Button の Content プロパティを設定する例を次に示します。 バインディングでは、継承されたデータ コンテキストおよび XmlDataProvider データ ソース (この例には示されていません) が使用されます。 バインディング自体は、データ ソース内で XPath によって目的のソース プロパティを指定します。
<Button Content="{Binding XPath=Team/@TeamName}"/>
メモ |
---|
バインディングはローカル値として扱われます。つまり、別のローカル値を設定すると、バインディングがなくなります。詳細については、「依存関係プロパティ値の優先順位」を参照してください。 |
依存関係プロパティまたは DependencyObject クラスは、データ バインディング操作に対応する DependencyObject ソース プロパティ値の変更の通知を生成する INotifyPropertyChanged をネイティブ サポートしません。 データ バインディング ターゲットに対する変更を報告できる、データ バインディングで使用するためのプロパティを作成する方法の詳細については、「データ バインディングの概要」を参照してください。
スタイル
スタイルおよびテンプレートは、依存関係プロパティの使用に関する 2 つの主なシナリオです。 スタイルは、アプリケーション user interface (UI) を定義するプロパティを設定する際に特に役立ちます。 通常、スタイルは XAML のリソースとして定義されます。 スタイルには通常、特定のプロパティの "setter" および別のプロパティのリアルタイム値に基づいてプロパティ値を変更する "トリガー" が含まれるため、スタイルはプロパティ システムと対話します。
非常に単純なスタイル (Resources ディクショナリ内で定義されますが、この例には示されていません) を作成し、そのスタイルを Button の Style プロパティに直接適用する例を次に示します。 スタイル内の setter によって、スタイルが適用された Button の Background プロパティが緑色に設定されます。
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>
詳細については、「スタイルとテンプレート」を参照してください。
アニメーション
依存関係プロパティは、アニメーション化することができます。 アニメーションが適用されて実行されると、アニメーション化された値は、それ以外の場合のプロパティの値 (ローカル値など) よりも高い優先順位で動作します。
Button プロパティの Background をアニメーション化する例を次に示します (技術的には、Background はプロパティ要素構文を使用して空白の SolidColorBrush を Background として指定することでアニメーション化され、その SolidColorBrush の Color プロパティが、直接アニメーション化されるプロパティになります)。
<Button>I am animated
<Button.Background>
<SolidColorBrush x:Name="AnimBrush"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimBrush"
Storyboard.TargetProperty="(SolidColorBrush.Color)"
From="Red" To="Green" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
プロパティのアニメーション化の詳細については、「アニメーションの概要」および「ストーリーボードの概要」を参照してください。
メタデータのオーバーライド
依存関係プロパティの特定の動作は、依存関係プロパティを最初に登録したクラスから派生させるときにプロパティのメタデータをオーバーライドすることで変更できます。 メタデータのオーバーライドは、DependencyProperty 識別子に依存します。 メタデータのオーバーライドでは、プロパティを再実装する必要はありません。 メタデータの変更は、プロパティ システムでネイティブに処理されます。各クラスは、基本クラスから継承したすべてのプロパティに対して、型ごとに個別のメタデータを保持する可能性があります。
依存関係プロパティ DefaultStyleKey のメタデータをオーバーライドする例を次に示します。 この特定の依存関係プロパティ メタデータのオーバーライドは、テーマから既定のスタイルを使用できるコントロールを作成する実装パターンの一部です。
Public Class SpinnerControl
Inherits ItemsControl
Shared Sub New()
DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
End Sub
End Class
public class SpinnerControl : ItemsControl
{
static SpinnerControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(SpinnerControl),
new FrameworkPropertyMetadata(typeof(SpinnerControl))
);
}
}
プロパティ メタデータをオーバーライドまたは取得する方法の詳細については、「依存関係プロパティのメタデータ」を参照してください。
プロパティ値の継承
要素は、オブジェクト ツリー内の親から依存関係プロパティの値を継承できます。
メモ |
---|
プロパティ値の継承動作は、すべての依存関係プロパティにグローバルに有効にはなりません。これは、継承の計算時間がパフォーマンスに影響するからです。プロパティ値の継承は通常、特定のシナリオでプロパティ値の継承が適切であると示されるプロパティに対してのみ有効にします。SDK リファレンスで、依存関係プロパティの「依存関係プロパティの情報」セクションを調べて、依存関係プロパティで継承を行うかどうかを決定できます。 |
次の例ではバインディングを示し、前述のバインディングの例では示されていなかったバインディングのソースを指定する DataContext プロパティを設定します。 子オブジェクトの以降のバインディングではソースを指定する必要はなく、親 StackPanel オブジェクトの DataContext から継承された値を使用できます (または、子オブジェクトが独自の DataContext または Binding の Source を直接指定し、そのバインディングのデータ コンテキストに継承された値を意図的に使用しないようにすることもできます)。
<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
<Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>
詳細については、「プロパティ値の継承」を参照してください。
WPF デザイナーの統合
依存関係プロパティとして実装されるプロパティを使用するカスタム コントロールは、適切な WPF Designer for Visual Studio のサポートを受けます。 1 つの例として、[プロパティ] ウィンドウで、直接依存関係プロパティと添付依存関係プロパティを編集できる機能が挙げられます。 詳細については、「コントロールの作成の概要」を参照してください。
依存関係プロパティ値の優先順位
依存関係プロパティの値を取得する場合、WPF プロパティ システムに関係する他のプロパティに基づく入力のいずれかを介して、そのプロパティに設定された値を取得する可能性があります。 プロパティの値の取得方法に関するさまざまなシナリオが予測可能な方法で相互作用できるように、依存関係プロパティ値の優先順位が存在しています。
例を次に示します。 この例には、すべてのボタンおよびそれらの Background プロパティに適用されるスタイルが含まれていますが、Background 値がローカルに設定されているボタンも 1 つ指定されています。
メモ |
---|
SDK ドキュメントでは、依存関係プロパティについて説明するときに、"ローカル値" または "ローカルに設定された値" という用語が使用される場合があります。ローカルに設定された値は、コードでオブジェクト インスタンスに直接設定されたプロパティ値または XAML で要素の属性として設定されたプロパティ値です。 |
原則として、最初のボタンではプロパティが 2 回設定されますが、適用される値は 1 つだけで、優先順位が最も高い値が適用されます。 ローカルに設定された値の優先順位が最も高いため (実行中のアニメーションを除きますが、この例ではアニメーションは適用されていません)、最初のボタンの背景に対するスタイル setter の値ではなくローカルに設定された値が使用されます。 2 番目のボタンにはローカル値が設定されていないため (また、優先順位がスタイル setter より高い値が他にないため)、そのボタンの背景はスタイル setter に基づきます。
<StackPanel>
<StackPanel.Resources>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
</Style>
</StackPanel.Resources>
<Button Background="Green">I am NOT red!</Button>
<Button>I am styled red</Button>
</StackPanel>
依存関係プロパティの優先順位が存在する理由
通常、スタイルを常に適用し、個別の要素のローカルに設定された値を無効にすることは望ましくありません (また、一般に、スタイルまたは要素の使用は非常に困難です)。 そのため、スタイルに基づく値は、ローカルに設定された値よりも低い優先順位で動作します。 依存関係プロパティの詳細なリストおよび依存関係プロパティの有効値を決める要因については、「依存関係プロパティ値の優先順位」を参照してください。
メモ |
---|
WPF 要素で定義されるプロパティには、依存関係プロパティではないものが多数あります。概してプロパティは、プロパティ システムによって可能になる 1 つ以上のシナリオ (データ バインディング、スタイル設定、アニメーション、既定値のサポート、継承、添付プロパティ、または無効化) をサポートする必要がある場合にのみ依存関係プロパティとして実装されます。 |
依存関係プロパティの詳細情報
添付プロパティは、XAML で特殊な構文をサポートするプロパティの一種です。 多くの場合、添付プロパティはcommon language runtime (CLR) プロパティと 1 対 1 で対応せず、依存関係プロパティであるとは限りません。 添付プロパティの一般的な目的は、親要素と子要素がどちらも、クラス メンバー リストの一部としてそのプロパティを処理しない場合でも、子要素が親要素にプロパティ値を報告できるようにすることです。 主なシナリオは、子要素から親要素に UI でどのように表示するかを通知できるようにすることです。例については、Dock または Left を参照してください。 詳細については、「添付プロパティの概要」を参照してください。
コンポーネントまたはアプリケーションの開発者は、データ バインディングやスタイルのサポートなどの機能を有効にするために、または無効化および値の強制のサポートのために、独自の依存関係プロパティを作成できます。 詳細については、「カスタム依存関係プロパティ」を参照してください。
依存関係プロパティは通常、インスタンスにアクセスできる呼び出し元がアクセス可能か、少なくとも検出可能なパブリック プロパティと見なされます。 詳細については、「依存関係プロパティのセキュリティ」を参照してください。