次の方法で共有


プロパティ値の継承 (WPF .NET)

プロパティ値の継承は、Windows Presentation Foundation (WPF) プロパティ システムの機能であり、依存関係プロパティに適用されます。 プロパティ値の継承により、要素のツリー内の子要素は、最も近い親要素から特定のプロパティの値を取得できます。 親要素は、プロパティ値の継承によってプロパティ値を取得している可能性があるため、システムはページ ルートに再帰する可能性があります。

WPF プロパティ システムでは、既定ではプロパティ値の継承は有効になりません。また、依存関係プロパティ メタデータで特に有効になっていない限り、値の継承は非アクティブです。 プロパティ値の継承が有効になっている場合でも、子要素は、より高い 優先順位 値がない場合にのみプロパティ値を継承します。

前提 条件

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

要素ツリーを介した継承

プロパティ値の継承は、派生クラスが基底クラスのメンバーを継承するオブジェクト指向プログラミングのクラス継承と同じ概念ではありません。 この種の継承は WPF でもアクティブですが、XAML では、継承された基底クラスのプロパティは、派生クラスを表す XAML 要素の属性として公開されます。

プロパティ値の継承は、依存関係プロパティ値が、プロパティを含む要素のツリー内の親要素から子要素に伝達されるメカニズムです。 XAML マークアップでは、要素のツリーは入れ子になった要素として表示されます。

次の例は、XAML の入れ子になった要素を示しています。 WPF は、プロパティ値 継承 を有効にし、既定値を falseに設定するプロパティ メタデータ を使用して、UIElement クラスの AllowDrop 依存関係プロパティを登録します。 AllowDrop 依存関係プロパティは、UIElementから派生しているため、CanvasStackPanel、および Label 要素に存在します。 canvas1AllowDrop 依存関係プロパティは trueに設定されているため、子孫 stackPanel1 要素と label1 要素は AllowDrop 値として true を継承します。

<Canvas x:Name="canvas1" Grid.Column="0" Margin="20" Background="Orange" AllowDrop="True">
    <StackPanel Name="stackPanel1" Margin="20" Background="Green">
        <Label Name="label1" Margin="20" Height="40" Width="40" Background="Blue"/>
    </StackPanel>
</Canvas>

別の要素オブジェクトの子要素コレクションに要素オブジェクトを追加することで、プログラムによって要素のツリーを作成することもできます。 実行時に、プロパティ値の継承は結果のオブジェクト ツリーで動作します。 次の例では、stackPanel2canvas2子コレクション に追加されます。 同様に、label2stackPanel2の子コレクションに追加されます。 canvas2AllowDrop 依存関係プロパティは trueに設定されているため、子孫 stackPanel2 要素と label2 要素は AllowDrop 値として true を継承します。

Canvas canvas2 = new()
{
    AllowDrop = true
};
StackPanel stackPanel2 = new();
Label label2 = new();
canvas2.Children.Add(stackPanel2);
stackPanel2.Children.Add(label2);
Dim canvas2 As New Canvas With {
    .AllowDrop = True
}
Dim stackPanel2 As New StackPanel()
Dim label2 As New Label()
canvas2.Children.Add(stackPanel2)
stackPanel2.Children.Add(label2)

プロパティ値の継承の実用的な応用

特定の WPF 依存関係プロパティでは、AllowDropFlowDirectionなど、値の継承が既定で有効になっています。 通常、値の継承が既定で有効になっているプロパティは、基本 UI 要素クラスに実装されるため、派生クラスに存在します。 たとえば、AllowDropUIElement 基底クラスに実装されているため、その依存関係プロパティは、UIElementから派生したすべてのコントロールにも存在します。 WPF を使用すると、依存関係プロパティに対する値の継承が可能になります。これは、ユーザーが親要素に対してプロパティ値を 1 回設定し、そのプロパティ値を要素ツリーの子孫要素に伝達するのに便利です。

プロパティ値の継承モデルでは、依存関係プロパティ値の優先順位に従って、継承されたプロパティ値と継承されていないプロパティ値 割り当てられます。 したがって、子要素のプロパティが、ローカルに設定された値や、スタイル、テンプレート、またはデータ バインディングによって取得された値など、優先順位の高い値を持たない場合にのみ、親要素のプロパティ値が子要素に適用されます。

FlowDirection 依存関係プロパティは、親要素内のテキストおよび子 UI 要素のレイアウト方向を設定します。 通常、ページ内のテキスト要素と UI 要素のフロー方向は一貫している必要があります。 のメタデータ プロパティで値の継承が有効になっているため、値はページの要素ツリーの上部に 1 回だけ設定する必要があります。 フロー方向の組み合わせがページを対象とするまれなケースでは、ローカルに設定された値を割り当てることによって、ツリー内の要素に異なるフロー方向を設定できます。 その後、新しいフロー方向は、そのレベルより下の子孫要素に伝達されます。

カスタム プロパティを継承可能にする

カスタム依存関係プロパティを継承可能にするには、FrameworkPropertyMetadataのインスタンスで Inherits プロパティを有効にしてから、そのメタデータ インスタンスにカスタム依存関係プロパティを登録します。 既定では、InheritsFrameworkPropertyMetadatafalse に設定されます。 プロパティ値を継承可能にすることはパフォーマンスに影響するため、その機能が必要な場合にのみ Inheritstrue に設定します。

メタデータで が有効になっている依存関係プロパティを登録する場合は、「添付プロパティの登録 」の説明に従って、 メソッドを使用します。 また、継承可能な値が存在するように、プロパティに既定値を割り当てます。 また、接続されていない依存関係プロパティの場合と同様に、所有者型に対して get アクセサーと set アクセサーを使用してプロパティ ラッパーを作成することもできます。 その方法で、所有者や派生型でプロパティラッパーを使用してプロパティの値を設定できます。 次の例では、IsTransparentという名前の依存関係プロパティを作成し、Inherits を有効にし、既定値を falseします。 この例には、getset アクセサーが付いたプロパティラッパーもあります。

public class Canvas_IsTransparentInheritEnabled : Canvas
{
    // Register an attached dependency property with the specified
    // property name, property type, owner type, and property metadata
    // (default value is 'false' and property value inheritance is enabled).
    public static readonly DependencyProperty IsTransparentProperty =
        DependencyProperty.RegisterAttached(
            name: "IsTransparent",
            propertyType: typeof(bool),
            ownerType: typeof(Canvas_IsTransparentInheritEnabled),
            defaultMetadata: new FrameworkPropertyMetadata(
                defaultValue: false,
                flags: FrameworkPropertyMetadataOptions.Inherits));

    // Declare a get accessor method.
    public static bool GetIsTransparent(Canvas element)
    {
        return (bool)element.GetValue(IsTransparentProperty);
    }

    // Declare a set accessor method.
    public static void SetIsTransparent(Canvas element, bool value)
    {
        element.SetValue(IsTransparentProperty, value);
    }

    // For convenience, declare a property wrapper with get/set accessors.
    public bool IsTransparent
    {
        get => (bool)GetValue(IsTransparentProperty);
        set => SetValue(IsTransparentProperty, value);
    }
}
Public Class Canvas_IsTransparentInheritEnabled
    Inherits Canvas

    ' Register an attached dependency property with the specified
    ' property name, property type, owner type, and property metadata
    ' (default value is 'false' and property value inheritance is enabled).
    Public Shared ReadOnly IsTransparentProperty As DependencyProperty =
        DependencyProperty.RegisterAttached(
            name:="IsTransparent",
            propertyType:=GetType(Boolean),
            ownerType:=GetType(Canvas_IsTransparentInheritEnabled),
            defaultMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=False,
                flags:=FrameworkPropertyMetadataOptions.[Inherits]))

    ' Declare a get accessor method.
    Public Shared Function GetIsTransparent(element As Canvas) As Boolean
        Return element.GetValue(IsTransparentProperty)
    End Function

    ' Declare a set accessor method.
    Public Shared Sub SetIsTransparent(element As Canvas, value As Boolean)
        element.SetValue(IsTransparentProperty, value)
    End Sub

    ' For convenience, declare a property wrapper with get/set accessors.
    Public Property IsTransparent As Boolean
        Get
            Return GetValue(IsTransparentProperty)
        End Get
        Set(value As Boolean)
            SetValue(IsTransparentProperty, value)
        End Set
    End Property
End Class

添付プロパティは概念的にはグローバル プロパティに似ています。 任意の DependencyObject で値を確認し、有効な結果を取得できます。 添付プロパティの一般的なシナリオは、子要素にプロパティ値を設定することです。そのシナリオは、該当するプロパティがツリー内の各 DependencyObject 要素に添付プロパティとして暗黙的に存在する場合に効果的です。

ツリー境界を越えてプロパティ値を継承する

プロパティの継承は、要素のツリーを走査することによって機能します。 多くの場合、このツリーは論理ツリーと並列です。 ただし、要素ツリーを定義するマークアップに、Brushなどの WPF コア レベルのオブジェクトを含めると、不連続の論理ツリーが作成されます。 論理ツリーは WPF フレームワーク レベルの概念であるため、実際の論理ツリーは概念的には Brushを通じて拡張されません。 LogicalTreeHelper のヘルパー メソッドを使用して、論理ツリーの範囲を分析および表示できます。 プロパティ値の継承は、不連続の論理ツリーを介して継承された値を渡すことができますが、継承可能なプロパティが添付プロパティとして登録されていて、Frameなどの意図的な継承ブロック境界がない場合に限ります。

手記

プロパティ値の継承は、アタッチされていない依存関係プロパティでは機能するように見えるかもしれませんが、ランタイム ツリー内の一部の要素境界を介した非アタッチプロパティの継承動作は未定義です。 プロパティ メタデータで Inherits を指定するときは常に、RegisterAttachedを使用してプロパティを登録します。

参照