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

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

必須コンポーネント

ここでは、.NET 型システムおよびオブジェクト指向プログラミングに関する基礎知識があることを前提にしています。 このトピックの例について理解するには、XAML および WPF アプリケーションの記述方法について知っておく必要もあります。 詳細については、「チュートリアル:初めての WPF デスクトップ アプリケーション」を参照してください。

依存関係プロパティおよび CLR プロパティ

WPF では通常、プロパティは通常、標準の .NET プロパティとして公開されます。 基本的なレベルでは、これらのプロパティと直接対話でき、これらのプロパティが依存関係として実装されることを認識することはありません。 ただし、WPF プロパティ システムの一部またはすべての機能を利用できるように、これらの機能に精通しておく必要があります。

依存関係プロパティの目的は、他の入力の値に基づいてプロパティの値を計算する方法を提供することです。 他の入力には、テーマやユーザー設定などのシステム プロパティ、データ バインディングやアニメーション/ストーリーボードなどのジャスト イン タイム プロパティ判定機構、リソースやスタイルなどの多目的のテンプレート、要素ツリー内の他の要素との親子のリレーションシップから判断される値などがあります。 また、依存関係プロパティを実装して、自己完結型の検証、既定値、他のプロパティに対する変更を監視するコールバック、およびランタイム情報の可能性がある情報に基づいてプロパティ値を強制するシステムを提供できます。 既存のプロパティの実際の実装をオーバーライドしたり新しいプロパティを作成したりするのではなく、依存関係プロパティ メタデータをオーバーライドすることによって、派生クラスで既存のプロパティの特定の特性を変更することもできます。

SDK リファレンスで、プロパティのマネージド リファレンス ページの「依存関係プロパティの情報」セクションの有無によって、どのプロパティが依存関係プロパティかを特定できます。 「依存関係プロパティの情報」セクションにはその依存関係プロパティの DependencyProperty 識別子フィールドへのリンクがあり、そのプロパティに設定されるメタデータ オプションのリスト、クラスごとのオーバーライド情報、およびその他の詳細も示されています。

依存関係プロパティによる CLR プロパティの補足

依存関係プロパティおよび WPF プロパティ システムは、プライベート フィールドでプロパティをサポートする標準パターンの代替実装として、プロパティをサポートする型を提供することによって、プロパティ機能を拡張します。 この型の名前は DependencyProperty です。 WPF プロパティ システムを定義するその他の重要な型は DependencyObject です。 DependencyObject は、依存関係プロパティを登録および所有できる基本クラスを定義します。

依存関係プロパティで使用される用語を次に示します。

  • 依存関係プロパティ:DependencyProperty によって補助されているプロパティ。

  • 依存関係プロパティの識別子: 依存関係プロパティの登録時に戻り値として取得され、クラスの静的メンバーとして格納される DependencyProperty インスタンス。 この識別子は、WPF プロパティ システムと対話する多くの API でパラメーターとして使用されます。

  • CLR "ラッパー": プロパティの実際の get および set 実装。 これらの実装では、GetValueSetValue の呼び出しで使用することにより依存関係プロパティ識別子を組み込んで、WPF プロパティ システムを使用するプロパティを補助します。

次の例では、IsSpinning 依存関係プロパティを定義し、DependencyProperty 識別子とサポートされるプロパティの関係を示します。

public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
    DependencyProperty.Register("IsSpinning",
                                GetType(Boolean),
                                GetType(MyCode))

Public Property IsSpinning() As Boolean
    Get
        Return CBool(GetValue(IsSpinningProperty))
    End Get
    Set(ByVal value As Boolean)
        SetValue(IsSpinningProperty, value)
    End Set
End Property

プロパティとそれを補足する DependencyProperty フィールドの名前付け規則は重要です。 フィールドの名前は常にプロパティの名前であり、サフィックス Property が追加されます。 この規則とその理由の詳細については、「カスタム依存関係プロパティ」を参照してください。

プロパティ値の設定

コードまたは XAML でプロパティを設定できます。

XAML でのプロパティ値の設定

ボタンの背景色を赤に指定する方法を次の XAML の例に示します。 この例では、生成されたコードで XAML 属性の単純な文字列値が WPF XAML パーサーによって WPF 型 (SolidColorBrush を使用したColor) に型変換される場合を示します。

<Button Background="Red" Content="Button!"/>

XAML は、プロパティを設定するためのさまざまな構文形式をサポートします。 特定のプロパティに対してどの構文を使用するかは、プロパティで使用される値型、および型コンバーターの有無などのその他の要素によって決定されます。 プロパティ設定の XAML 構文の詳細については、「WPF の XAML」および「XAML 構文の詳細」を参照してください。

属性以外の構文の例として、別のボタンの背景を次の XAML の例に示します。 今回は単純な純色を設定するのではなく、背景をイメージに設定し、そのイメージおよびそのイメージのソースを表す要素を、入れ子にした要素の属性として指定します。 これは、プロパティ要素構文の例です。

<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

コードでのプロパティの設定

依存関係プロパティの値をコードで設定するには、通常、CLR "ラッパー" によって公開される set 実装を呼び出すだけで済みます。

Button myButton = new Button();
myButton.Width = 200.0;
Dim myButton As New Button()
myButton.Width = 200.0

プロパティ値を取得する場合も、基本的に get "ラッパー" 実装を呼び出します。

double whatWidth;
whatWidth = myButton.Width;
Dim whatWidth As Double
whatWidth = myButton.Width

プロパティ システムの API である GetValueSetValue を直接呼び出すこともできます。 これは通常、既存のプロパティを使用する場合は不要ですが (ラッパーの方が便利で、開発者ツール用のより優れたプロパティが公開されます)、API を直接呼び出す方法は、特定のシナリオに適しています。

プロパティは、XAML で設定してから分離コードを介してコードでアクセスすることもできます。 詳細については、「WPF における分離コードと XAML」を参照してください。

依存関係プロパティによって提供されるプロパティ機能

依存関係プロパティは、フィールドによって補足されるプロパティとは対照的に、プロパティの機能を拡張する機能を提供します。 しばしば、そのような関数では、次の特定の機能を表すかサポートします。

リソース

依存関係プロパティの値は、リソースを参照することによって設定できます。 リソースは通常、ページのルート要素またはアプリケーションの Resources プロパティ値として指定されます (これらの場所を使用することが、リソースにアクセスするのに最も便利な方法です)。 次の例では、SolidColorBrush リソースを定義する方法を示します。

<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

リソースを定義すると、リソースを参照し、そのリソースを使用してプロパティ値を指定できるようになります。

<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

この特定のリソースは、DynamicResource マークアップ拡張機能として参照されます (WPF XAML では、静的リソース参照または動的リソース参照を使用できます)。 動的リソース参照を使用するには、依存関係プロパティに設定している必要があるため、これは具体的には、WPF プロパティ システムによって有効になる動的リソース参照の使用方法になります。 詳細については、「XAML リソース」を参照してください。

注意

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

データ バインディング

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

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

<Button Content="{Binding XPath=Team/@TeamName}"/>

注意

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

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

スタイル

スタイルおよびテンプレートは、依存関係プロパティの使用に関する 2 つの主なシナリオです。 スタイルは、アプリケーション ユーザー インターフェイス (UI) を定義するプロパティを設定する際に特に役立ちます。 通常、スタイルは XAML のリソースとして定義されます。 スタイルには通常、特定のプロパティの "setter" および別のプロパティのリアルタイム値に基づいてプロパティ値を変更する "トリガー" が含まれるため、スタイルはプロパティ システムと対話します。

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

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

詳しくは、「 スタイルとテンプレート」をご覧ください。

Animations

依存関係プロパティは、アニメーション化することができます。 アニメーションが適用されて実行されると、アニメーション化された値は、それ以外の場合のプロパティの値 (ローカル値など) よりも高い優先順位で動作します。

次の例は、Button プロパティ上の Background をアニメーション化します (技術的には、空白の SolidColorBrushBackground として指定するために、プロパティ要素構文を使用して Background がアニメーション化されます。すると、その SolidColorBrushColor プロパティが直接アニメーション化されるプロパティになります)。

<Button>I am animated
  <Button.Background>
    <SolidColorBrush x:Name="AnimBrush"/>
  </Button.Background>
  <Button.Triggers>
    <EventTrigger RoutedEvent="Button.Loaded">
      <BeginStoryboard>
        <Storyboard>
          <ColorAnimation
            Storyboard.TargetName="AnimBrush" 
            Storyboard.TargetProperty="(SolidColorBrush.Color)"
            From="Red" To="Green" Duration="0:0:5" 
            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 または SourceBinding に指定するよう選択して、意図的に継承値をそのバインディング内のデータ コンテキストで使用しないようにできます)。

<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

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

WPF デザイナーの統合

依存関係プロパティとして実装されるプロパティを使用するカスタム コントロールは、Visual Studio の WPF デザイナーによって適切にサポートされます。 1 つの例として、 [プロパティ] ウィンドウで、直接依存関係プロパティと添付依存関係プロパティを編集できる機能が挙げられます。 詳しくは、「コントロールの作成の概要」を参照してください。

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

依存関係プロパティの値を取得する場合、WPF プロパティ システムに関係する他のプロパティに基づく入力のいずれかを介して、そのプロパティに設定された値を取得する可能性があります。 プロパティの値の取得方法に関するさまざまなシナリオが予測可能な方法で相互作用できるように、依存関係プロパティ値の優先順位が存在しています。

例を次に示します。 この例には、すべてのボタンとその Background プロパティに適用され、しかし次いで 1 つのボタンをローカルに設定されている Background値にも指定するスタイルが含まれています。

注意

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

原則として、最初のボタンではプロパティが 2 回設定されますが、適用される値は 1 つだけで、優先順位が最も高い値が適用されます。 ローカルに設定された値の優先順位が最も高いため (実行中のアニメーションを除きますが、この例ではアニメーションは適用されていません)、最初のボタンの背景に対するスタイル setter の値ではなくローカルに設定された値が使用されます。 2 番目のボタンにはローカル値が設定されていないため (また、優先順位がスタイル setter より高い値が他にないため)、そのボタンの背景はスタイル setter に基づきます。

<StackPanel>
  <StackPanel.Resources>
    <Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
     <Setter Property="Background" Value="Red"/>
    </Style>
  </StackPanel.Resources>
  <Button Background="Green">I am NOT red!</Button>
  <Button>I am styled red</Button>
</StackPanel>

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

通常、スタイルを常に適用し、個別の要素のローカルに設定された値を無効にすることは望ましくありません (また、一般に、スタイルまたは要素の使用は困難です)。 そのため、スタイルに基づく値は、ローカルに設定された値よりも低い優先順位で動作します。 依存関係プロパティの詳細なリストおよび依存関係プロパティの有効値を決める要因については、「依存関係プロパティ値の優先順位」を参照してください。

注意

WPF 要素で定義されるプロパティには、依存関係プロパティではないものが多数あります。 概してプロパティは、プロパティ システムによって可能になる 1 つ以上のシナリオ (データ バインディング、スタイル設定、アニメーション、既定値のサポート、継承、添付プロパティ、または無効化) をサポートする必要がある場合にのみ依存関係プロパティとして実装されます。

依存関係プロパティの詳細情報

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

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

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

関連項目