2019년 4월 10일 수요일

WPF의 Dependency Property와 Attached Property.

Dependency Properties와 Attatched Properties는 WPF가 제공하는 UI 시스템이 효율적으로 운영되게 하는 장치라 봐야겠다.


Dependency Properties


DP는 일반적인 프로퍼티와 다르게 인스턴스의 값이 인스턴스에 저장되는 것이 아니고, DependencyObject에 사전(dictionary) 형태로 기록된다. 값을 읽을 때에도 DependencyObject의 GetValue() 메서드를 통한다.

DependencyObject는 특정 UI Control에 대한 기본 속성 값을 가지고 있는다. DependencyObject는 어떤 사용자가 Button을 100개 선언한다고 하여도 Button 100개에 대한 속성 각각을 따로 따로 메모리에 기록하지 않고, 기본 속성 값에서 변경되는 값만 따로 기록하는 방식을 채택해 메모리 낭비를 줄인다. 또한 Value inheritance를 지원해 선언되지 않은 속성 값은 Visual Tree 상 부모의 값을 따르게 하며 PropertyMetadata를 통해 값의 변경, 밸리데이션에 대한 통지를 해준다.

등록하는 DP 이름의 끝에 Property가 붙는 것은 관례다.


// Dependency Property
public static readonly DependencyProperty CurrentTimeProperty = 
     DependencyProperty.Register( "CurrentTime", typeof(DateTime),
     typeof(MyClockControl), new FrameworkPropertyMetadata(DateTime.Now));
 
// .NET Property wrapper
public DateTime CurrentTime
{
    get { return (DateTime)GetValue(CurrentTimeProperty); }
    set { SetValue(CurrentTimeProperty, value); }
}

new FrameworkPropertyMetadata( DateTime.Now, 
                       OnCurrentTimePropertyChanged,  // Value Changed Callback
                       OnCoerceCurrentTimeProperty ), // Coerce Value Callback (Range Check,...)
                       OnValidateCurrentTimeProperty ); // Validation Callback (Type Checking,...)



Attached Properties


Attached Properties는 DP의 특수한 형태로 프로퍼티가 선언된 곳과 다른 곳에서 쓰일 수 있도록 하는 장치다. DP 사례의 Register() 대신에 RegisterAttatched()에 의해 등록된다.

Attached Properties의 경우 예를 떠올리면 이해가 편하다.
Panel.ZIndex 또는 Grid.Row와 같은 것. 이런 프로퍼티는 Button이나 TextBox 같은 컨트롤에서 쓰일 수 있지만 실제 프로퍼티의 정의는 Panel이나 Grid에 되어 있다. 다른 인스턴스에 'attached'되는 것이다.

DP와 다르게 static 메서드 형태로 Set / Get을 정의한다. 당연한게 선언된 곳과 다른 인스턴스에서 호출되어야 하기 때문이다.


<Canvas>
    <Button Canvas.Top="20" Canvas.Left="20" Content="Click me!"/>
</Canvas>

public static readonly DependencyProperty TopProperty =
    DependencyProperty.RegisterAttached("Top", 
    typeof(double), typeof(Canvas),
    new FrameworkPropertyMetadata(0d,
        FrameworkPropertyMetadataOptions.Inherits));
 
public static void SetTop(UIElement element, double value)
{
    element.SetValue(TopProperty, value);
}
 
public static double GetTop(UIElement element)
{
    return (double)element.GetValue(TopProperty);
}


댓글 1개: