속성 값 상속(WPF .NET)

속성 값 상속은 WPF(Windows Presentation Foundation) 속성 시스템의 기능이며 종속성 속성에 적용됩니다. 속성 값 상속을 사용하면 요소 트리의 자식 요소가 가장 가까운 부모 요소에서 특정 속성의 값을 가져올 수 있습니다. 부모 요소도 속성 값 상속을 통해 속성 값을 얻었을 수 있으므로 시스템이 잠재적으로 페이지 루트로 되돌아갈 수 있습니다.

WPF 속성 시스템은 기본적으로 속성 값 상속을 사용하도록 설정하지 않으며, 종속성 속성 메타데이터에서 특별히 사용하도록 설정하지 않는 한 값 상속은 비활성화됩니다. 속성 값 상속을 사용하도록 설정하더라도 자식 요소는 더 높은 우선 순위 값이 없는 경우에만 속성 값을 상속합니다.

중요

.NET 7 및 .NET 6에 관한 데스크톱 가이드 설명서는 제작 중입니다.

필수 구성 요소

이 문서에서는 독자들이 종속성 속성에 대한 기본 지식을 갖고 있으며 종속성 속성 개요를 읽었다고 가정합니다. XAML(Extensible Application Markup Language)에 익숙하고 WPF 애플리케이션을 작성하는 방법을 알고 있으면 이 문서의 예제를 따라 하는 데 도움이 됩니다.

요소 트리를 통한 상속

속성 값 상속은 파생 클래스가 기본 클래스 멤버를 상속하는 개체 지향 프로그래밍의 클래스 상속과 동일한 개념이 아닙니다. 이러한 종류의 상속은 WPF에서도 활성화되지만 XAML에서는 상속된 기본 클래스 속성이 파생 클래스를 나타내는 XAML 요소의 특성으로 노출됩니다.

속성 값 상속은 종속성 속성 값이 속성을 포함하는 요소 트리 내의 부모 요소에서 자식 요소로 전파되는 메커니즘입니다. XAML 태그에서 요소 트리는 중첩된 요소로 표시됩니다.

다음 예제에서는 XAML의 중첩된 요소를 보여줍니다. WPF는 속성 값 상속을 사용하도록 설정하고 기본값을 false로 설정하는 속성 메타데이터를 사용하여 UIElement 클래스에 AllowDrop 종속성 속성을 등록합니다. AllowDrop 종속성 속성은 모두 UIElement에서 파생되므로 Canvas, StackPanelLabel 요소에 있습니다. canvas1에 대한 AllowDrop 종속성 속성이 true로 설정되어 있으므로 하위 stackPanel1label1 요소는 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>

다른 요소 개체의 자식 요소 컬렉션에 요소 개체를 추가하여 프로그래밍 방식으로 요소 트리를 만들 수도 있습니다. 런타임에 속성 값 상속은 결과 개체 트리에서 작동합니다. 다음 예제에서 stackPanel2canvas2자식 컬렉션에 추가됩니다. 마찬가지로, label2stackPanel2의 자식 컬렉션에 추가됩니다. canvas2에 대한 AllowDrop 종속성 속성이 true로 설정되어 있으므로 하위 stackPanel2label2 요소는 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 종속성 속성에는 기본적으로 값 상속(예: AllowDropFlowDirection)이 사용하도록 설정되어 있습니다. 일반적으로 값 상속이 기본적으로 활성화된 속성은 기본 UI 요소 클래스에서 구현되므로 파생 클래스에 존재합니다. 예를 들어 AllowDropUIElement 기본 클래스에서 구현되므로 해당 종속성 속성은 UIElement에서 파생된 모든 컨트롤에도 존재합니다. WPF를 사용하면 사용자가 부모 요소에서 속성 값을 한 번 설정하고 해당 속성 값이 요소 트리의 하위 요소로 전파되도록 하여 편리한 종속성 속성에 대한 값 상속을 사용할 수 있습니다.

속성 값 상속 모델은 종속성 속성 값 우선 순위에 따라 상속된 값과 상속되지 않은 속성 값을 할당합니다. 따라서 부모 요소 속성 값은 자식 요소 속성에 로컬로 설정된 값 또는 스타일, 템플릿 또는 데이터 바인딩을 통해 얻은 값과 같은 더 높은 우선 순위 값이 없는 경우에만 자식 요소에 적용됩니다.

FlowDirection 종속성 속성은 부모 요소 내에서 텍스트 및 자식 UI 요소의 레이아웃 방향을 설정합니다. 일반적으로 페이지 내의 텍스트 및 UI 요소의 흐름 방향이 일관될 것으로 예상합니다. FlowDirection의 값 속성 메타데이터에서 값 속성이 사용하도록 설정되어 있으므로 페이지의 요소 트리 맨 위에서 한 번만 값을 설정하면 됩니다. 드문 경우이지만 흐름 방향의 혼합이 페이지를 대상으로 하는 경우 로컬로 설정된 값을 할당하여 트리의 요소에 다른 흐름 방향을 설정할 수 있습니다. 그러면 새 흐름 방향이 해당 수준 아래의 하위 요소로 전파됩니다.

사용자 지정 속성을 상속 가능으로 설정

FrameworkPropertyMetadata 인스턴스에서 Inherits 속성을 사용하도록 설정한 다음, 해당 메타데이터 인스턴스에 사용자 지정 종속성 속성을 등록하여 사용자 지정 종속성 속성을 상속 가능하게 만들 수 있습니다. 기본적으로 InheritsFrameworkPropertyMetadata에서 false로 설정됩니다. 속성 값을 상속 가능하도록 설정하면 성능에 영향을 주므로 해당 기능이 필요한 경우에만 Inheritstrue로 설정합니다.

메타데이터에서 사용하도록 설정된 Inherits로 종속성 속성을 등록하는 경우 연결된 속성 등록에 설명된 대로 RegisterAttached 메서드를 사용합니다. 또한 상속 가능한 값이 존재하도록 속성에 기본값을 할당합니다. 연결되지 않은 종속성 속성과 마찬가지로 소유자 유형에 getset 접근자가 있는 속성 래퍼를 만들 수도 있습니다. 이렇게 하면 소유자 또는 파생 형식의 속성 래퍼를 사용하여 속성 값을 설정할 수 있습니다. 다음 예제에서는 Inherits가 활성화되고 기본값이 falseIsTransparent라는 종속성 속성을 만듭니다. 이 예제에는 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 핵심 수준 개체를 포함할 때마다 불연속적인 논리 트리를 만들었습니다. 실제 논리적 트리는 개념적으로 Brush를 통해 확장됩니다. 논리 트리는 WPF 프레임워크 수준 개념이기 때문입니다. LogicalTreeHelper의 도우미 메서드를 사용하여 논리 트리의 범위를 분석하고 볼 수 있습니다. 속성 값 상속은 상속된 값을 불연속적인 논리 트리를 통해 전달할 수 있지만 상속 가능한 속성이 연결된 속성으로 등록되고 Frame과 같은 의도적인 상속 차단 경계가 없는 경우에만 가능합니다.

참고

속성 값 상속이 연결되지 않은 종속성 속성에 대해 작동하는 것처럼 보일 수 있지만 런타임 트리의 일부 요소 경계를 통해 연결되지 않은 속성에 대한 상속 동작은 정의되지 않습니다. 속성 메타데이터에서 Inherits를 지정할 때마다 RegisterAttached를 사용하여 속성을 등록합니다.

참고 항목