次の方法で共有


XAML の読み込みと依存関係のプロパティ (WPF .NET)

Windows Presentation Foundation (WPF) の拡張アプリケーション マークアップ言語 (XAML) プロセッサの実装は、本質的に依存関係プロパティに対応しています。 そのため、XAML プロセッサでは、WPF プロパティ システム メソッドを使用して XAML を読み込み、依存関係プロパティ属性を処理し、GetValueSetValueなどの WPF プロパティ システム メソッドを使用して依存関係プロパティ ラッパーを完全にバイパスします。 そのため、カスタム依存関係プロパティのプロパティ ラッパーにカスタム ロジックを追加した場合、XAML でプロパティ値が設定されている場合、XAML プロセッサによって呼び出されることはありません。

前提 条件

この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要読んだことを前提としています。 この記事の例に従うには、拡張アプリケーション マークアップ言語 (XAML) に慣れている場合や、WPF アプリケーションを記述する方法を理解している場合に役立ちます。

WPF XAML ローダーのパフォーマンス

WPF XAML プロセッサが依存関係プロパティのプロパティ ラッパーを使用するのではなく、SetValue を直接呼び出して依存関係プロパティの値を設定することは、計算コストが低くなります。

XAML プロセッサでプロパティ ラッパーを使用した場合は、マークアップで示されている型とメンバーのリレーションシップのみに基づいて、バッキング コードのオブジェクト モデル全体を推論する必要があります。 型は、xmlns 属性とアセンブリ属性の組み合わせを使用してマークアップから識別できますが、メンバーを識別し、属性として設定できるメンバーを決定し、サポートされているプロパティ値の型を解決するには、PropertyInfoを使用して広範なリフレクションが必要になります。

WPF プロパティ システムは、特定の DependencyObject 派生型に実装された依存関係プロパティのストレージ テーブルを保持します。 XAML プロセッサは、そのテーブルを使用して、依存関係プロパティの依存関係プロパティ識別子を推論します。 たとえば、規則により、ABC という名前の依存関係プロパティの依存関係プロパティ識別子が ABCPropertyされます。 XAML プロセッサは、依存関係プロパティ識別子を使用して、その包含型に対して SetValue メソッドを呼び出すことによって、依存関係プロパティの値を効率的に設定できます。

依存関係プロパティ ラッパーの詳細については、「カスタム依存関係プロパティ」を参照してください。

カスタム依存関係プロパティに対する影響

WPF XAML プロセッサは、プロパティ ラッパーをバイパスし、依存関係プロパティ値を設定するために SetValue を直接呼び出します。 そのため、カスタム依存関係プロパティの set アクセサーに追加のロジックを配置することは避けてください。これは、XAML でプロパティ値が設定されている場合にそのロジックが実行されないためです。 set アクセサーには、SetValue 呼び出しのみを含める必要があります。

同様に、プロパティ値を取得する WPF XAML プロセッサの側面は、プロパティ ラッパーをバイパスし、GetValueを直接呼び出します。 そのため、カスタム依存関係プロパティの get アクセサーに追加のロジックを配置することは避けてください。これは、XAML でプロパティ値を読み取ったときにそのロジックが実行されないためです。 get アクセサーには、GetValue 呼び出しのみを含める必要があります。

ラッパー付き依存プロパティの例

次の例は、プロパティ ラッパーを使用して推奨される依存関係プロパティ定義を示しています。 依存関係プロパティ識別子は public static readonly フィールドとして格納され、get アクセサーと set アクセサーには、依存関係プロパティ値をサポートするのに必要な WPF プロパティ システムメソッドを超えるコードは含まれていません。 依存関係プロパティの値が変更されたときに実行する必要があるコードがある場合は、依存関係プロパティの PropertyChangedCallback にそのコードを配置することを検討してください。 詳細については、「プロパティ変更コールバック」を参照してください。

// Register a dependency property with the specified property name,
// property type, owner type, and property metadata. Store the dependency
// property identifier as a public static readonly member of the class.
public static readonly DependencyProperty AquariumGraphicProperty =
    DependencyProperty.Register(
      name: "AquariumGraphic",
      propertyType: typeof(Uri),
      ownerType: typeof(Aquarium),
      typeMetadata: new FrameworkPropertyMetadata(
          defaultValue: new Uri("http://www.contoso.com/aquarium-graphic.jpg"),
          flags: FrameworkPropertyMetadataOptions.AffectsRender,
          propertyChangedCallback: new PropertyChangedCallback(OnUriChanged))
    );

// Property wrapper with get & set accessors.
public Uri AquariumGraphic
{
    get => (Uri)GetValue(AquariumGraphicProperty);
    set => SetValue(AquariumGraphicProperty, value);
}

// Property-changed callback.
private static void OnUriChanged(DependencyObject dependencyObject, 
    DependencyPropertyChangedEventArgs e)
{
    // Some custom logic that runs on effective property value change.
    Uri newValue = (Uri)dependencyObject.GetValue(AquariumGraphicProperty);
    Debug.WriteLine($"OnUriChanged: {newValue}");
}
' Register a dependency property with the specified property name,
' property type, owner type, and property metadata. Store the dependency
' property identifier as a public static readonly member of the class.
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty =
    DependencyProperty.Register(
        name:="AquariumGraphic",
        propertyType:=GetType(Uri),
        ownerType:=GetType(Aquarium),
        typeMetadata:=New FrameworkPropertyMetadata(
            defaultValue:=New Uri("http://www.contoso.com/aquarium-graphic.jpg"),
            flags:=FrameworkPropertyMetadataOptions.AffectsRender,
            propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnUriChanged)))

' Property wrapper with get & set accessors.
Public Property AquariumGraphic As Uri
    Get
        Return CType(GetValue(AquariumGraphicProperty), Uri)
    End Get
    Set
        SetValue(AquariumGraphicProperty, Value)
    End Set
End Property

' Property-changed callback.
Private Shared Sub OnUriChanged(dependencyObject As DependencyObject,
                                e As DependencyPropertyChangedEventArgs)
    ' Some custom logic that runs on effective property value change.
    Dim newValue As Uri = CType(dependencyObject.GetValue(AquariumGraphicProperty), Uri)
    Debug.WriteLine($"OnUriChanged: {newValue}")
End Sub

関連項目