プロパティ値の継承は、Windows Presentation Foundation (WPF) プロパティ システムの機能であり、依存関係プロパティに適用されます。 プロパティ値の継承により、要素のツリー内の子要素は、最も近い親要素から特定のプロパティの値を取得できます。 親要素は、プロパティ値の継承によってプロパティ値を取得している可能性があるため、システムはページ ルートに再帰する可能性があります。
WPF プロパティ システムでは、既定ではプロパティ値の継承は有効になりません。また、依存関係プロパティ メタデータで特に有効になっていない限り、値の継承は非アクティブです。 プロパティ値の継承が有効になっている場合でも、子要素は 優先順位 の高い値がない場合にのみプロパティ値を継承します。
[前提条件]
この記事では、依存関係プロパティの基本的な知識と、依存関係プロパティの概要
要素ツリーを介した継承
プロパティ値の継承は、派生クラスが基底クラスのメンバーを継承するオブジェクト指向プログラミングのクラス継承と同じ概念ではありません。 この種の継承は WPF でもアクティブですが、XAML では、継承された基底クラスのプロパティは、派生クラスを表す XAML 要素の属性として公開されます。
プロパティ値の継承は、依存関係プロパティ値が、プロパティを含む要素のツリー内の親要素から子要素に伝達されるメカニズムです。 XAML マークアップでは、要素のツリーは入れ子になった要素として表示されます。
次の例は、XAML の入れ子になった要素を示しています。 WPF は、プロパティ値のAllowDropを有効にし、既定値を UIElement に設定するプロパティ メタデータを使用して、 クラスのfalse
依存関係プロパティを登録します。
AllowDrop
依存関係プロパティは、すべてCanvasから派生するため、StackPanel、Label、およびUIElement
要素に存在します。
AllowDrop
のcanvas1
依存関係プロパティはtrue
に設定されているため、子孫stackPanel1
要素とlabel1
要素はtrue
値としてAllowDrop
を継承します。
<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>
別の要素オブジェクトの子要素コレクションに要素オブジェクトを追加することで、プログラムによって要素のツリーを作成することもできます。 実行時に、プロパティ値の継承は結果のオブジェクト ツリーで動作します。 次の例では、stackPanel2
の子コレクションにcanvas2
が追加されています。 同様に、 label2
は stackPanel2
の子コレクションに追加されます。
AllowDropのcanvas2
依存関係プロパティはtrue
に設定されているため、子孫stackPanel2
要素とlabel2
要素はtrue
値としてAllowDrop
を継承します。
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 依存関係プロパティでは、 AllowDrop や FlowDirectionなど、既定で値の継承が有効になっています。 通常、値の継承が既定で有効になっているプロパティは、基本 UI 要素クラスに実装されるため、派生クラスに存在します。 たとえば、 AllowDrop
は UIElement 基底クラスに実装されているため、その依存関係プロパティは、 UIElement
から派生したすべてのコントロールにも存在します。 WPF を使用すると、依存関係プロパティに対する値の継承が可能になります。これは、ユーザーが親要素に対してプロパティ値を 1 回設定し、そのプロパティ値を要素ツリーの子孫要素に伝達するのに便利です。
プロパティ値継承モデルでは、依存関係プロパティ値の優先順位に従って、継承されたプロパティ値と非継承 プロパティ値の両方が割り当てられます。 したがって、子要素のプロパティが、ローカルに設定された値や、スタイル、テンプレート、またはデータ バインディングによって取得された値など、優先順位の高い値を持たない場合にのみ、親要素のプロパティ値が子要素に適用されます。
FlowDirection依存関係プロパティは、親要素内のテキストと子 UI 要素のレイアウト方向を設定します。 通常、ページ内のテキスト要素と UI 要素のフロー方向は一貫している必要があります。
のプロパティ FlowDirection
で値の継承が有効になっているため、値はページの要素ツリーの上部に 1 回だけ設定する必要があります。 フロー方向の組み合わせがページを対象とするまれなケースでは、ローカルに設定された値を割り当てることによって、ツリー内の要素に異なるフロー方向を設定できます。 その後、新しいフロー方向は、そのレベルより下の子孫要素に伝達されます。
カスタム プロパティを継承可能にする
カスタム依存関係プロパティを継承可能にするには、InheritsのインスタンスでFrameworkPropertyMetadata プロパティを有効にしてから、そのメタデータ インスタンスにカスタム依存関係プロパティを登録します。 既定では、Inherits
は false
でFrameworkPropertyMetadata
に設定されます。 プロパティ値を継承可能にすることはパフォーマンスに影響するため、その機能が必要な場合にのみ Inherits
を true
に設定します。
メタデータでInherits
が有効になっている依存関係プロパティを登録する場合は、「RegisterAttached」の説明に従ってメソッドを使用します。 また、継承可能な値が存在するように、プロパティに既定値を割り当てます。 また、接続されていない依存関係プロパティの場合と同様に、所有者型に対して get
アクセサーと set
アクセサーを使用してプロパティ ラッパーを作成することもできます。 そうすることで、所有者または派生型のプロパティ ラッパーを使用してプロパティ値を設定できます。 次の例では、 IsTransparent
という名前の依存関係プロパティを作成し、 Inherits
を有効にし、既定値を false
します。 この例には、 get
アクセサーと set
アクセサーを含むプロパティ ラッパーも含まれています。
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を使用してプロパティを登録します。
こちらも参照ください
.NET Desktop feedback