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