次の方法で共有


依存関係プロパティ値の優先順位 (WPF .NET)

Windows Presentation Foundation (WPF) プロパティ システムの動作は、依存関係プロパティの値に影響します。 この記事では、WPF プロパティ システム内のさまざまなプロパティ ベースの入力の優先順位によって、依存関係プロパティの有効な値がどのように決定されるかについて説明します。

前提 条件

この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要読んだことを前提としています。 この記事の例に従うには、拡張アプリケーション マークアップ言語 (XAML) に慣れている場合や、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 を置き換えます。

依存関係プロパティの優先順位リスト

次の一覧は、ランタイム値を依存関係プロパティに割り当てるときにプロパティ システムが使用する優先順位の明確な順序です。 最も高い優先順位が最初に一覧表示されます。

  1. プロパティ システム強制型。 強制変換の詳細については、「強制変換とアニメーション」を参照してください。

  2. アクティブなアニメーション、または保留動作を持つアニメーション。 実際の効果を得るために、基本値がローカルに設定されている場合でも、アニメーション値は基本 (アニメーション化されていない) 値よりも優先される必要があります。 詳細については、「型の強制とアニメーション」を参照してください。

  3. ローカル値。 ローカル値は、"ラッパー" プロパティを使用して設定できます。これは、XAML での属性またはプロパティ要素の設定、または特定のインスタンスのプロパティを使用した SetValue API の呼び出しに相当します。 バインドまたはリソースによって設定されたローカル値は、直接設定される値と同じ優先順位を持ちます。

  4. TemplatedParent テンプレートプロパティ値。 要素がテンプレート (ControlTemplate または DataTemplate) によって作成された場合、要素には TemplatedParent があります。 詳細については、「TemplatedParent」を参照してください。 TemplatedParentで指定されたテンプレート内の優先順位は次のとおりです。

    1. トリガー。

    2. プロパティ セット 。通常は XAML 属性を使用します。

  5. 暗黙的なスタイル Style プロパティにのみ適用されます。 Style 値は、要素の種類に一致する TargetType 値を持つ任意のスタイル リソースです。 スタイル リソースは、ページまたはアプリケーション内に存在する必要があります。 暗黙的なスタイル リソースの検索は、テーマのスタイル リソースには拡張されません。

  6. スタイルはをトリガーします。 スタイル トリガーは、明示的または暗黙的なスタイル内のトリガーです。 スタイルは、ページまたはアプリケーション内に存在する必要があります。 既定のスタイルのトリガーの優先順位は低くなります。

  7. テンプレートは、をトリガーします。 テンプレート トリガーは、直接適用されたテンプレートまたはスタイル内のテンプレートからのトリガーです。 スタイルは、ページまたはアプリケーション内に存在する必要があります。

  8. スタイルセッターの値。 スタイル セッター値は、スタイル内の Setter によって適用される値です。 スタイルは、ページまたはアプリケーション内に存在する必要があります。

  9. 既定のスタイル(テーマ スタイルとも呼ばれます)。 詳細については、「既定の (テーマ) スタイルを参照してください。 既定のスタイル内では、優先順位は次のようになります。

    1. アクティブなトリガー。

    2. セッター。

  10. 継承. 子要素の一部の依存関係プロパティは、その値を親要素から継承します。 そのため、アプリケーション全体のすべての要素にプロパティ値を設定する必要がない場合があります。 詳細については、「プロパティ値の継承」を参照してください。

  11. 依存関係プロパティ メタデータの既定値 依存関係プロパティは、そのプロパティのプロパティ システムの登録時に既定値を設定できます。 依存関係プロパティを継承する派生クラスは、型ごとに依存関係プロパティメタデータ (既定値を含む) をオーバーライドできます。 詳細については、「依存関係プロパティのメタデータ 」を参照してください。 継承されたプロパティの場合、親要素の既定値が子要素の既定値よりも優先されます。 したがって、継承可能なプロパティが設定されていない場合は、子要素の既定値ではなく、ルートまたは親の既定値が使用されます。

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">MyButtonButtonから派生した場合でも、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 コントロールの既定のテンプレートには、BackgroundBorderThicknessなどのプロパティとテンプレート バインドを共有するさまざまな境界線プロパティがあります。 ただし、プロパティまたは視覚的配置の値がテンプレート内でハードコーディングされている場合、またはテーマから直接取得される値にバインドされている場合は、テンプレート全体を置き換えるだけでそれらの値を変更できます。 一般に、プロパティがテンプレート化された親から取得され、TemplateBindingによって公開されていない場合、プロパティ値はスタイルによって変更できません。これは、プロパティをターゲットにする便利な方法がないためです。 ただし、そのプロパティは、適用されたテンプレートのプロパティ値の継承または既定値の影響を受ける可能性があります。

既定のスタイルでは、定義に TargetType を指定します。 ランタイム テーマの評価は、既定のスタイルの TargetType をコントロールの DefaultStyleKey プロパティと照合します。 これに対し、暗黙的なスタイルの参照動作では、コントロールの実際の型が使用されます。 DefaultStyleKey の値は派生クラスによって継承されるため、それ以外の場合はスタイルが関連付けられていない派生要素は、既定の外観になります。 たとえば、Buttonから MyButton を派生させる場合、MyButtonButtonの既定のテンプレートを継承します。 派生クラスは、依存関係プロパティメタデータの DefaultStyleKey の既定値をオーバーライドできます。 そのため、MyButtonに対して別の視覚的表現が必要な場合は、MyButtonDefaultStyleKey の依存関係プロパティメタデータをオーバーライドし、テンプレートを含む関連する既定のスタイルを定義し、MyButton コントロールでパッケージ化することができます。 詳細については、「コントロールの作成の概要」を参照してください。

動的リソース

動的リソース 参照とバインド操作には、設定されている場所の優先順位があります。 たとえば、ローカル値に適用される動的リソースは、優先順位リストの項目 3 と同じ優先順位。 別の例として、既定のスタイル内のプロパティ セッターに適用される動的リソース バインドは、優先順位リストの項目 9 と同じ優先順位を持ちます。 動的リソース参照とバインドは、アプリケーションのランタイム状態から値を取得する必要があるため、特定のプロパティのプロパティ値の優先順位を決定するプロセスはランタイムに拡張されます。

動的リソース参照は、技術的にはプロパティ システムの一部ではなく、優先順位リストと対話する独自の参照順序。 基本的に、動的リソース参照の優先順位は、要素からページへのルート、アプリケーション、テーマ、システムです。 詳細については、「XAML リソース」を参照してください。

動的リソース参照とバインドは、設定されている場所の優先順位を持ちますが、値は遅延されます。 その結果、動的リソースまたはバインドをローカル値に設定すると、ローカル値に対する変更によって動的リソースまたはバインディングが完全に置き換えられます。 ClearValue メソッドを呼び出してローカルに設定された値をクリアしても、動的リソースまたはバインドは復元されません。 実際、動的リソースまたはバインド (リテラル ローカル値なし) を持つプロパティに対して ClearValue を呼び出すと、動的リソースまたはバインドがクリアされます。

現在の値を設定

SetCurrentValue メソッドは、プロパティを設定するもう 1 つの方法ですが、優先順位リストには含まれません。 SetCurrentValue を使用すると、前の値のソースを上書きすることなく、プロパティの値を変更できます。 たとえば、プロパティがトリガーによって設定され、SetCurrentValueを使用して別の値を割り当てる場合、次のトリガー アクションはプロパティをトリガー値に戻します。 SetCurrentValue は、その値にローカル値の優先順位レベルを与えずにプロパティ値を設定する場合にいつでも使用できます。 同様に、SetCurrentValue を使用して、バインディングを上書きせずにプロパティの値を変更できます。

強制とアニメーション

強制とアニメーションの両方が、の基準値に作用します。 基本値は、最も優先順位の高い依存関係プロパティ値であり、項目 2 に達するまで 優先順位リストを介して上向きに評価することによって決定されます。

アニメーションで特定の動作に From プロパティ値と To プロパティ値の両方が指定されていない場合、またはアニメーションが完了したときに意図的に基本値に戻る場合は、基本値がアニメーション化された値に影響を与える可能性があります。 これを実際に確認するには、ターゲット値 サンプルアプリケーションを実行します。 このサンプルでは、四角形の高さについて、From 値とは異なる初期ローカル値を設定してみてください。 サンプル アニメーションは、基本値ではなく From 値を使用してすぐに開始されます。 StopFillBehaviorとして指定すると、アニメーションが完了すると、プロパティ値がその基本値にリセットされます。 通常の優先順位は、アニメーションが終了した後の基本値の決定に使用されます。

複数のアニメーションを 1 つのプロパティに適用でき、各アニメーションの優先順位は異なります。 WPF プレゼンテーション エンジンは、優先順位が最も高いアニメーションを適用するのではなく、アニメーションの定義方法とアニメーション化された値の種類に応じて、アニメーション値を合成する場合があります。 詳細については、「アニメーションの概要参照してください。

強制は、優先順位リストの先頭にあります。 実行中のアニメーションであっても、値強制の対象となります。 WPF の既存の依存関係プロパティの中には、強制型が組み込まれているものもあります。 カスタム依存関係プロパティの場合は、プロパティの作成時にメタデータの一部として渡す CoerceValueCallback を記述することで強制型変換の動作を定義できます。 派生クラスでそのプロパティのメタデータをオーバーライドすることで、既存のプロパティの強制型変換動作をオーバーライドすることもできます。 強制型変換は、強制型変換の制約がその時点で存在するとおりに適用されるように基本値と対話しますが、基本値は保持されます。 その結果、強制型変換の制約が後で解除されると、強制型変換は基本値に可能な限り最も近い値を返し、すべての制約が解除されると、プロパティに対する強制型変換の影響が停止する可能性があります。 強制動作の詳細については、「依存関係プロパティのコールバックと検証」を参照してください。

トリガーの動作

コントロールは、多くの場合、既定のスタイルの一部としてトリガー動作を定義します。 コントロールにローカル プロパティを設定すると、これらのトリガーと競合する可能性があるため、トリガーがユーザー主導のイベントに (視覚的または動作的に) 応答できなくなる可能性があります。 プロパティ トリガーの一般的な用途は、IsSelectedIsEnabledなどの状態プロパティを制御することです。 たとえば、既定では、Button を無効にすると、テーマ スタイル トリガー (IsEnabledfalse) によって Foreground 値が設定され、Button が灰色で表示されます。ローカル Foreground 値を設定した場合、Button が無効になっている場合でも、優先順位の高いローカル プロパティ値がテーマ スタイル Foreground 値よりも優先されます。 コントロールのテーマ レベルのトリガー動作をオーバーライドするプロパティ値を設定する場合は、そのコントロールの意図されたユーザー エクスペリエンスに過度に干渉しないように注意してください。

クリアバリュー

ClearValue メソッドは、要素の依存関係プロパティのローカルに適用された値をクリアします。 ただし、ClearValue を呼び出しても、プロパティの登録中にメタデータで確立された既定値が新しい有効な値であるとは限りません。 優先順位リスト の他のすべての参加者はアクティブであり、ローカルに設定された値のみが削除されます。 たとえば、テーマ スタイルを持つプロパティに対して ClearValue を呼び出すと、メタデータ ベースの既定値ではなく、テーマ スタイルの値が新しい値として適用されます。 登録されたメタデータの既定値にプロパティ値を設定する場合は、依存関係プロパティのメタデータに対してクエリを実行して既定のメタデータ値を取得し、SetValueを呼び出してプロパティ値をローカルに設定します。

関連項目