次の方法で共有


依存関係プロパティの概要 (WPF .NET)

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です。

一般的に使用される用語を次に示します。

  • Dependency プロパティ。これは、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 型は SolidColorBrushを通じて Colorです。

<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

GetValue および SetValue のプロパティ システム API を直接呼び出すこともできます。 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 で宣言されたバインドを使用して、ButtonContent プロパティを設定します。 バインディングでは、継承されたデータ コンテキストと XmlDataProvider データ ソース (表示されません) が使用されます。 バインディング自体は、XPathによってデータ ソース内のソース プロパティを指定します。

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

手記

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

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

スタイル

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

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

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

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

アニメーション

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

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

<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 から継承された値を使用できます。 または、子オブジェクトは、継承された値を使用せず、Bindingで独自の DataContext または Source を直接指定できます。

<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」を参照してください。 詳細については、「添付プロパティの概要 を参照してください。

参照