次の方法で共有


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

Windows Presentation Foundation (WPF) には、型の プロパティの機能を拡張するために使用できる一連のサービスが用意されています。 これらのサービスをまとめて WPF プロパティ システムと呼びます。 WPF プロパティ システムによってサポートされるプロパティは、依存関係プロパティと呼ばれます。 この概要では、XAML とコードで既存の依存関係プロパティを使用する方法など、WPF プロパティ システムと依存関係プロパティの機能について説明します。 この概要では、依存関係プロパティメタデータなどの依存関係プロパティの特殊な側面と、カスタム クラスで独自の依存関係プロパティを作成する方法についても説明します。

[前提条件]

この記事では、.NET 型システムとオブジェクト指向プログラミングに関する基本的な知識を前提としています。 この記事の例に従うには、XAML を理解し、WPF アプリケーションを記述する方法を理解するのに役立ちます。 詳細については、「 チュートリアル: .NET を使用して新しい WPF アプリを作成する」を参照してください。

依存関係プロパティと CLR プロパティ

WPF プロパティは、通常、標準の .NET プロパティとして公開されます。 これらのプロパティを基本的なレベルで使用して、依存関係プロパティとして実装されていることを知らないかもしれません。 ただし、WPF プロパティ システムの一部またはすべての機能に関する知識は、これらの機能を利用するのに役立ちます。

依存関係プロパティの目的は、次のような他の入力の値に基づいてプロパティの値を計算する方法を提供することです。

  • テーマやユーザー設定などのシステム プロパティ。
  • データ バインディングやアニメーション/ストーリーボードなどの Just-In-Time プロパティ決定メカニズム。
  • リソースやスタイルなどの複数の使用テンプレート。
  • 要素ツリー内の他の要素との親子リレーションシップによって認識される値。

また、依存関係プロパティは次の機能を提供できます。

  • 自己完結型の検証。
  • 既定値。
  • 他のプロパティへの変更を監視するコールバック。
  • ランタイム情報に基づいてプロパティ値を強制できるシステム。

派生クラスでは、既存のプロパティの実際の実装をオーバーライドしたり、新しいプロパティを作成したりするのではなく、依存関係プロパティのメタデータをオーバーライドすることで、既存のプロパティのいくつかの特性を変更できます。

SDK リファレンスでは、そのプロパティの管理参照ページの [依存関係プロパティ情報] セクションが存在することで、依存関係プロパティを識別できます。 [依存関係プロパティ情報] セクションには、その依存関係プロパティの DependencyProperty 識別子フィールドへのリンクが含まれています。 また、そのプロパティのメタデータ オプション、クラスごとのオーバーライド情報、およびその他の詳細の一覧も含まれます。

依存関係プロパティを CLR プロパティに戻す

依存関係プロパティと WPF プロパティ システムは、プロパティをプライベート フィールドでバッキングする標準的なパターンの代わりに、プロパティをバックする型を提供することで、プロパティ機能を拡張します。 この型の名前は DependencyProperty。 WPF プロパティ システムを定義するもう 1 つの重要な型は、依存関係プロパティを登録して所有できる基底クラスを定義する 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 の XAMLXAML 構文の詳細を参照してください。

次の 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 GetValueSetValue を直接呼び出すこともできます。 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 として参照されます

リソースはローカル値として扱われます。つまり、別のローカル値を設定すると、リソース参照が削除されます。 詳細については、「 依存関係プロパティの値の優先順位」を参照してください。

データ バインディング

依存関係プロパティは、データ バインディングを使用して値を参照できます。 データ バインディングは、XAML の特定のマークアップ拡張構文、またはコード内の Binding オブジェクトを介して機能します。 データ バインディングでは、最終的なプロパティ値の決定は実行時まで延期され、その時点でデータ ソースから値が取得されます。

次の例では、XAML で宣言されたバインドを使用して、ContentButton プロパティを設定します。 バインドでは、継承されたデータ コンテキストと XmlDataProvider データ ソース (表示されません) が使用されます。 バインディング自体は、データ ソース内のソース プロパティを XPathによって指定します。

<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>

バインドはローカル値として扱われます。つまり、別のローカル値を設定すると、バインドは削除されます。 詳細については、「 依存関係プロパティの値の優先順位」を参照してください。

依存関係プロパティまたはDependencyObject クラスでは、データ バインディング操作のソース プロパティ値の変更を通知するためのINotifyPropertyChangedDependencyObjectネイティブでサポートされていません。 データ バインディング ターゲットに対する変更を報告できるデータ バインディングで使用するプロパティを作成する方法の詳細については、「データ バインディングの概要」を参照してください。

スタイル

スタイルとテンプレートは、依存関係プロパティを使用する魅力的な理由です。 スタイルは、アプリケーション UI を定義するプロパティを設定する場合に特に便利です。 スタイルは通常、XAML でリソースとして定義されます。 スタイルは、通常、特定のプロパティの "setter" と、別のプロパティのランタイム値に基づいてプロパティ値を変更する "トリガー" が含まれているため、プロパティ システムと対話します。

次の例では、単純なスタイルを作成します。これは、 Resources ディクショナリ内で定義されます (表示されません)。 そのスタイルは、StyleButton プロパティに直接適用されます。 スタイル内のセッターは、スタイル付きBackgroundButton プロパティを緑に設定します。

<Style x:Key="GreenButtonStyle">
    <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}" Content="I am green"/>

詳細については、「 スタイル設定とテンプレート」を参照してください。

アニメーション

依存関係プロパティはアニメーション化できます。 適用されたアニメーションを実行すると、アニメーション化された値は、ローカル値を含む他のプロパティ値よりも優先順位が高くなります。

次の例では、BackgroundButton プロパティをアニメーション化します。 技術的には、プロパティ要素の構文では、SolidColorBrushとして空白のBackgroundが設定され、ColorSolidColorBrushプロパティがアニメーション化されます。

<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 プロパティを含むバインディングを示しています。 そのため、子オブジェクトのバインドではソースを指定する必要がなく、親DataContext オブジェクトのStackPanelから継承された値を使用できます。 または、子オブジェクトは、継承された値を使用せず、DataContext内の独自のSourceまたはBindingを直接指定できます。

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource TestData}}">
    <Button Content="{Binding XPath=test[2]/@text}"/>
</StackPanel>

詳細については、「プロパティ値の継承」を参照してください。

WPF デザイナーの統合

依存関係プロパティとして実装されたプロパティを持つカスタム コントロールは、WPF Designer for Visual Studio とうまく統合されます。 1 つの例として、[ プロパティ ] ウィンドウで直接依存関係プロパティと添付依存関係プロパティを編集する機能があります。 詳細については、「コントロールの作成の概要」を参照してください。

依存関係プロパティ値の優先順位

WPF プロパティ システム内のプロパティ ベースの入力は、依存関係プロパティの値を設定できます。 依存関係プロパティ値の優先順位 が存在するため、プロパティが値を取得する方法に関するさまざまなシナリオが予測可能な方法で相互作用します。

SDK ドキュメントでは、依存関係プロパティについて説明するときに、"local value" または "locally set value" という用語を使用することがあります。 ローカルに設定された値は、コード内のオブジェクト インスタンスに直接設定されるプロパティ値、または XAML の要素属性として設定されるプロパティ値です。

次の例には、任意のボタンの Background プロパティに適用されるスタイルが含まれていますが、ローカルに設定された Background プロパティを持つ 1 つのボタンを指定します。 技術的には、そのボタンの Background プロパティは 2 回設定されますが、適用される値は 1 つだけです。つまり、優先順位が最も高い値です。 ローカルに設定された値は、実行中のアニメーションを除いて最も優先順位が高く、ここには存在しません。 そのため、2 番目のボタンでは、スタイル セッター値ではなく、 Background プロパティにローカルに設定された値が使用されます。 最初のボタンには、ローカル値、またはスタイル セッターよりも優先順位の高いその他の値がないため、 Background プロパティのスタイル セッター値が使用されます。

<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>

依存関係プロパティの優先順位が存在する理由

ローカル設定値は、要素プロパティのローカル制御をサポートするスタイル セッター値よりも優先されます。 詳細については、「 依存関係プロパティの値の優先順位」を参照してください。

依存関係プロパティは通常、WPF プロパティ システムの機能が必要な場合にのみ実装されるため、WPF 要素で定義されているプロパティの数は依存関係プロパティではありません。 機能には、データ バインディング、スタイル設定、アニメーション、既定値のサポート、継承、添付プロパティ、無効化が含まれます。

依存関係プロパティについてさらに学ぶ

  • コンポーネント開発者またはアプリケーション開発者は、独自の依存関係プロパティを作成して、データ バインディングやスタイルのサポート、無効化と値強制のサポートなどの機能を追加したい場合があります。 詳細については、「 カスタム依存関係プロパティ」を参照してください。

  • 依存関係プロパティは、インスタンスへのアクセス権を持つ呼び出し元がアクセス可能または検出可能なパブリック プロパティであると考えてください。 詳細については、「 依存関係プロパティのセキュリティ」を参照してください。

  • 添付プロパティは、XAML の特殊な構文をサポートするプロパティの型です。 添付プロパティは、多くの場合、共通言語ランタイム プロパティと 1 対 1 の対応関係を持たず、必ずしも依存関係プロパティであるとは限りません。 添付プロパティの主な目的は、親要素と子要素にそのプロパティがクラス メンバーリストの一部として含まれていない場合でも、子要素が親要素にプロパティ値を報告できるようにすることです。 主なシナリオの 1 つは、子要素が UI でそれらを表示する方法を親要素に通知できるようにすることです。 例については、「 DockLeft」を参照してください。 詳細については、「 添付プロパティの概要」を参照してください。

こちらも参照ください