依存関係プロパティ値の優先順位 (WPF .NET)
Windows Presentation Foundation (WPF) プロパティ システムの動作は、依存関係プロパティの値に影響します。 この記事では、WPF プロパティ システム内のさまざまなプロパティ ベースの入力の優先順位によって、依存関係プロパティの有効な値がどのように決定されるかについて説明します。
前提 条件
この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要
WPF プロパティ システム
WPF プロパティ システムでは、さまざまな要因を使用して、リアルタイムプロパティ検証、遅延バインディング、関連プロパティのプロパティ変更通知など、依存関係プロパティの値を決定します。 依存関係プロパティの値の決定に使用される順序とロジックは複雑ですが、これを学習すると、不要なプロパティ設定を回避したり、依存関係プロパティを設定しようとして予期される値が発生しなかった理由を把握したりするのに役立ちます。
複数の場所に設定された依存関係プロパティ
次の XAML の例は、ボタンの Background プロパティに対する 3 つの異なる "set" 操作がその値に与える影響を示しています。
<StackPanel>
<StackPanel.Resources>
<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</StackPanel.Resources>
<Button Template="{StaticResource ButtonTemplate}" Background="Red">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Yellow" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
Which color do you expect?
</Button>
</StackPanel>
この例では、Background
プロパティはローカルで Red
に設定されています。 ただし、ボタンのスコープで宣言された暗黙的なスタイルは、Background
プロパティを Blue
に設定しようとします。 また、マウスがボタンの上にある場合、暗黙的なスタイルのトリガーは、Background
プロパティを Yellow
に設定しようとします。 強制型変換とアニメーションを除き、ローカルに設定されたプロパティ値の優先順位が最も高いため、マウスオーバー時でもボタンは赤になります。 ただし、ボタンからローカルに設定された値を削除すると、その Background
値がスタイルから取得されます。 スタイル内ではトリガーが優先されるため、ボタンはマウスオーバー時に黄色になり、それ以外の場合は青になります。 この例では、既定のテンプレートにハードコーディングされたマウスオーバー Background
値があるため、ボタンの既定の ControlTemplate を置き換えます。
依存関係プロパティの優先順位リスト
次の一覧は、ランタイム値を依存関係プロパティに割り当てるときにプロパティ システムが使用する優先順位の明確な順序です。 最も高い優先順位が最初に一覧表示されます。
プロパティ システム強制型。 強制変換の詳細については、「強制変換とアニメーション」を参照してください。
アクティブなアニメーション、または保留動作を持つアニメーション。 実際の効果を得るために、基本値がローカルに設定されている場合でも、アニメーション値は基本 (アニメーション化されていない) 値よりも優先される必要があります。 詳細については、「型の強制とアニメーション」を参照してください。
ローカル値。 ローカル値は、"ラッパー" プロパティを使用して設定できます。これは、XAML での属性またはプロパティ要素の設定、または特定のインスタンスのプロパティを使用した SetValue API の呼び出しに相当します。 バインドまたはリソースによって設定されたローカル値は、直接設定される値と同じ優先順位を持ちます。
TemplatedParent テンプレートプロパティ値。 要素がテンプレート (ControlTemplate または DataTemplate) によって作成された場合、要素には TemplatedParent があります。 詳細については、「TemplatedParent」を参照してください。
TemplatedParent
で指定されたテンプレート内の優先順位は次のとおりです。トリガー。
プロパティ セット 。通常は XAML 属性を使用します。
暗黙的なスタイル Style プロパティにのみ適用されます。
Style
値は、要素の種類に一致する TargetType 値を持つ任意のスタイル リソースです。 スタイル リソースは、ページまたはアプリケーション内に存在する必要があります。 暗黙的なスタイル リソースの検索は、テーマのスタイル リソースには拡張されません。スタイルはをトリガーします。 スタイル トリガーは、明示的または暗黙的なスタイル内のトリガーです。 スタイルは、ページまたはアプリケーション内に存在する必要があります。 既定のスタイルのトリガーの優先順位は低くなります。
テンプレートは、をトリガーします。 テンプレート トリガーは、直接適用されたテンプレートまたはスタイル内のテンプレートからのトリガーです。 スタイルは、ページまたはアプリケーション内に存在する必要があります。
スタイルセッターの値。 スタイル セッター値は、スタイル内の Setter によって適用される値です。 スタイルは、ページまたはアプリケーション内に存在する必要があります。
既定のスタイル(テーマ スタイルとも呼ばれます)。 詳細については、「既定の (テーマ) スタイル
を参照してください。 既定のスタイル内では、優先順位は次のようになります。 アクティブなトリガー。
セッター。
継承. 子要素の一部の依存関係プロパティは、その値を親要素から継承します。 そのため、アプリケーション全体のすべての要素にプロパティ値を設定する必要がない場合があります。 詳細については、「プロパティ値の継承
」を参照してください。 依存関係プロパティ メタデータの既定値 依存関係プロパティは、そのプロパティのプロパティ システムの登録時に既定値を設定できます。 依存関係プロパティを継承する派生クラスは、型ごとに依存関係プロパティメタデータ (既定値を含む) をオーバーライドできます。 詳細については、「依存関係プロパティのメタデータ 」を参照してください。 継承されたプロパティの場合、親要素の既定値が子要素の既定値よりも優先されます。 したがって、継承可能なプロパティが設定されていない場合は、子要素の既定値ではなく、ルートまたは親の既定値が使用されます。
TemplatedParent
TemplatedParent 優先順位は、標準のアプリケーション マークアップで直接宣言されている要素のプロパティには適用されません。 TemplatedParent
の概念は、テンプレートのアプリケーションを通じて存在するビジュアル ツリー内の子項目にのみ存在します。 プロパティ システムは、TemplatedParent
で指定されたテンプレートで要素のプロパティ値を検索するときに、要素を作成したテンプレートを検索します。 TemplatedParent
テンプレートのプロパティ値は、通常、要素の値がローカルに設定されているかのように動作しますが、テンプレートが共有される可能性があるため、実際のローカル値よりも優先順位が低くなります。 詳細については、TemplatedParentを参照してください。
Style プロパティ
Style プロパティを除くすべての依存関係プロパティに、同じ優先順位が適用されます。 Style
プロパティは、スタイルを設定できないという点で一意です。 Style
プロパティを強制またはアニメーション化することは推奨されません (Style
プロパティをアニメーション化するには、カスタム アニメーション クラスが必要です)。 その結果、すべての優先順位項目が適用されるわけではありません。 Style
プロパティを設定するには、次の 3 つの方法しかありません。
明示的なスタイル。 要素の
Style
プロパティは直接設定されます。Style
プロパティ値は、ローカル値として機能し、優先順位リストの項目3と同じ優先順位を持っています。 ほとんどのシナリオでは、明示的なスタイルはインラインで定義されず、代わりにリソースとして明示的に参照されます (Style="{StaticResource myResourceKey}"
など)。暗黙的なスタイル。 要素の
Style
プロパティは直接設定されません。 代わりに、スタイルがページまたはアプリケーション内のあるレベルに存在し、スタイルが適用される要素の種類に一致するリソース キー (たとえば、<Style TargetType="x:Type Button">
) がある場合に適用されます。 型は完全に一致する必要があります。たとえば、<Style TargetType="x:Type Button">
MyButton
がButton
から派生した場合でも、MyButton
型には適用されません。Style
プロパティの値は、優先順位リストの項目 5 と同じ優先順位を持ちます。 暗黙的なスタイル値を検出するには、DependencyPropertyHelper.GetValueSource メソッドを呼び出し、Style
プロパティを渡し、結果でImplicitStyleReference
を確認します。既定のスタイル(テーマ スタイルとも呼ばれます)。 要素の
Style
プロパティは直接設定されません。 代わりに、WPF プレゼンテーション エンジンによるランタイム テーマの評価に由来します。 ランタイムの前に、Style
プロパティの値はnull
です。Style
プロパティの値は、優先順位リストの項目 9 と同じ優先順位になります。
既定の (テーマ) スタイル
WPF に付属するすべてのコントロールには、テーマによって異なる既定のスタイルがあるため、既定のスタイルは
ControlTemplate は、コントロールの既定のスタイル内の重要な項目です。 ControlTemplate
は、スタイルの Template プロパティのセッター値です。 既定のスタイルにテンプレートが含まれていない場合、カスタム スタイルの一部としてカスタム テンプレートのないコントロールの外観は表示されません。 テンプレートはコントロールの視覚的な外観を定義するだけでなく、テンプレートのビジュアル ツリー内のプロパティと対応するコントロール クラス間の接続も定義します。 各コントロールは、テンプレートを置き換えずにコントロールの外観に影響を与えることができるプロパティのセットを公開します。 たとえば、ScrollBar コンポーネントである Thumb コントロールの既定の外観を考えてみましょう。
Thumb コントロールには、特定のカスタマイズ可能なプロパティがあります。 Thumb
コントロールの既定のテンプレートでは、いくつかの入れ子になった Border コンポーネントを含む基本構造またはビジュアルツリーが作成されます。これにより、面取りされた外観になります。 テンプレート内では、Thumb
クラスによってカスタマイズ可能であることを意図したプロパティは、TemplateBindingによって公開されます。 Thumb
コントロールの既定のテンプレートには、Background や BorderThicknessなどのプロパティとテンプレート バインドを共有するさまざまな境界線プロパティがあります。 ただし、プロパティまたは視覚的配置の値がテンプレート内でハードコーディングされている場合、またはテーマから直接取得される値にバインドされている場合は、テンプレート全体を置き換えるだけでそれらの値を変更できます。 一般に、プロパティがテンプレート化された親から取得され、TemplateBinding
によって公開されていない場合、プロパティ値はスタイルによって変更できません。これは、プロパティをターゲットにする便利な方法がないためです。 ただし、そのプロパティは、適用されたテンプレートのプロパティ値の継承または既定値の影響を受ける可能性があります。
既定のスタイルでは、定義に TargetType を指定します。 ランタイム テーマの評価は、既定のスタイルの TargetType
をコントロールの DefaultStyleKey プロパティと照合します。 これに対し、暗黙的なスタイルの参照動作では、コントロールの実際の型が使用されます。 DefaultStyleKey
の値は派生クラスによって継承されるため、それ以外の場合はスタイルが関連付けられていない派生要素は、既定の外観になります。 たとえば、Buttonから MyButton
を派生させる場合、MyButton
は Button
の既定のテンプレートを継承します。 派生クラスは、依存関係プロパティメタデータの DefaultStyleKey
の既定値をオーバーライドできます。 そのため、MyButton
に対して別の視覚的表現が必要な場合は、MyButton
の DefaultStyleKey
の依存関係プロパティメタデータをオーバーライドし、テンプレートを含む関連する既定のスタイルを定義し、MyButton
コントロールでパッケージ化することができます。 詳細については、「コントロールの作成の概要」を参照してください。
動的リソース
動的リソース 参照とバインド操作には、設定されている場所の優先順位があります。 たとえば、ローカル値に適用される動的リソースは、優先順位リストの項目 3 と同じ優先順位。 別の例として、既定のスタイル内のプロパティ セッターに適用される動的リソース バインドは、
動的リソース参照は、技術的にはプロパティ システムの一部ではなく、優先順位リストと対話する独自の参照順序。 基本的に、動的リソース参照の優先順位は、要素からページへのルート、アプリケーション、テーマ、システムです。 詳細については、「XAML リソース」を参照してください。
動的リソース参照とバインドは、設定されている場所の優先順位を持ちますが、値は遅延されます。 その結果、動的リソースまたはバインドをローカル値に設定すると、ローカル値に対する変更によって動的リソースまたはバインディングが完全に置き換えられます。 ClearValue メソッドを呼び出してローカルに設定された値をクリアしても、動的リソースまたはバインドは復元されません。 実際、動的リソースまたはバインド (リテラル ローカル値なし) を持つプロパティに対して ClearValue
を呼び出すと、動的リソースまたはバインドがクリアされます。
現在の値を設定
SetCurrentValue メソッドは、プロパティを設定するもう 1 つの方法ですが、優先順位リストには含まれません。 SetCurrentValue
を使用すると、前の値のソースを上書きすることなく、プロパティの値を変更できます。 たとえば、プロパティがトリガーによって設定され、SetCurrentValue
を使用して別の値を割り当てる場合、次のトリガー アクションはプロパティをトリガー値に戻します。 SetCurrentValue
は、その値にローカル値の優先順位レベルを与えずにプロパティ値を設定する場合にいつでも使用できます。 同様に、SetCurrentValue
を使用して、バインディングを上書きせずにプロパティの値を変更できます。
強制とアニメーション
強制とアニメーションの両方が、の基準値に作用します。
アニメーションで特定の動作に From プロパティ値と To プロパティ値の両方が指定されていない場合、またはアニメーションが完了したときに意図的に基本値に戻る場合は、基本値がアニメーション化された値に影響を与える可能性があります。 これを実際に確認するには、ターゲット値 サンプルアプリケーションを実行します。 このサンプルでは、四角形の高さについて、From
値とは異なる初期ローカル値を設定してみてください。 サンプル アニメーションは、基本値ではなく From
値を使用してすぐに開始されます。 Stop を FillBehaviorとして指定すると、アニメーションが完了すると、プロパティ値がその基本値にリセットされます。 通常の優先順位は、アニメーションが終了した後の基本値の決定に使用されます。
複数のアニメーションを 1 つのプロパティに適用でき、各アニメーションの優先順位は異なります。 WPF プレゼンテーション エンジンは、優先順位が最も高いアニメーションを適用するのではなく、アニメーションの定義方法とアニメーション化された値の種類に応じて、アニメーション値を合成する場合があります。 詳細については、「アニメーションの概要
強制は、優先順位リストの先頭にあります。 実行中のアニメーションであっても、値強制の対象となります。 WPF の既存の依存関係プロパティの中には、強制型が組み込まれているものもあります。 カスタム依存関係プロパティの場合は、プロパティの作成時にメタデータの一部として渡す CoerceValueCallback を記述することで強制型変換の動作を定義できます。 派生クラスでそのプロパティのメタデータをオーバーライドすることで、既存のプロパティの強制型変換動作をオーバーライドすることもできます。 強制型変換は、強制型変換の制約がその時点で存在するとおりに適用されるように基本値と対話しますが、基本値は保持されます。 その結果、強制型変換の制約が後で解除されると、強制型変換は基本値に可能な限り最も近い値を返し、すべての制約が解除されると、プロパティに対する強制型変換の影響が停止する可能性があります。 強制動作の詳細については、「依存関係プロパティのコールバックと検証」を参照してください。
トリガーの動作
コントロールは、多くの場合、既定のスタイルIsEnabled
が false
) によって Foreground 値が設定され、Button
が灰色で表示されます。ローカル Foreground
値を設定した場合、Button
が無効になっている場合でも、優先順位の高いローカル プロパティ値がテーマ スタイル Foreground
値よりも優先されます。 コントロールのテーマ レベルのトリガー動作をオーバーライドするプロパティ値を設定する場合は、そのコントロールの意図されたユーザー エクスペリエンスに過度に干渉しないように注意してください。
クリアバリュー
ClearValue メソッドは、要素の依存関係プロパティのローカルに適用された値をクリアします。 ただし、ClearValue
を呼び出しても、プロパティの登録中にメタデータで確立された既定値が新しい有効な値であるとは限りません。 優先順位リスト の他のすべての参加者はアクティブであり、ローカルに設定された値のみが削除されます。 たとえば、テーマ スタイルを持つプロパティに対して ClearValue
を呼び出すと、メタデータ ベースの既定値ではなく、テーマ スタイルの値が新しい値として適用されます。 登録されたメタデータの既定値にプロパティ値を設定する場合は、依存関係プロパティのメタデータに対してクエリを実行して既定のメタデータ値を取得し、SetValueを呼び出してプロパティ値をローカルに設定します。
関連項目
- DependencyObject
- DependencyProperty
- 依存関係プロパティの概要
- カスタム依存関係プロパティ の
- 依存関係プロパティのコールバックと検証
.NET Desktop feedback