본문 바로가기

Coding Note

[WPF] Dependency Property


Dependency property
 : 앞선 글에서 잠깐 언급한 적이 있다. dependency property란 자체 값을 가지는것이 아니라 어떤 property가 의존하고있는 property의 모체 같은거라고 설명했었다. 그리고 WPF의 property들은 이 dependency property를 바탕으로 구성되어 있으며 property의 해석은 DependencyObject에서 등록된 DependencyProperty를 가지고 이루어 진다고 하였다. 
 이번 글에선 이녀석을 확실하게 파헤쳐보자.

 우선은 기존의 dependency property는 어떻게 만들어 졌을까 하는 질문이다. 정답은 WPF의 기존 class들이 dependency property를 어떻게 만들고 있는지 뜯어보면 된다. =ㅅ=..

Control의 부모인 FrameworkElement를 살펴보자.

public class FrameworkElement : UIElement,...
{
 ...
    [CommonDependencyProperty]
    public static readonly DependencyProperty HeightProperty;
 ...

우선 클래스의 멤버중 HeightProperty가 눈에띈다. 흔히보는 control의 높이를 정하는 Height의 property 일 것이라는 냄새가 난다. 그런데 익히알던 Height 가 아니라 HeightProperty라니 다른변수가 아닐까?  정답은 얘가 정의되는 부분에서 나타난다.

static FrameworkElement()
{
 ...
    HeightProperty = DependencyProperty.Register("Height", typeof(double), _typeofThis, new FrameworkPropertyMetadata((double) 1.0 / (double) 0.0, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(FrameworkElement.OnTransformDirty)), new ValidateValueCallback(FrameworkElement.IsWidthHeightValid));
 ...
}
HeightProperty는 readonly이므로 static construct에서 정의된다. 그런데,,  그냥 값을 주는게 아니라 DependencyProperty.Register(..)라는 짓을 하고, 굉장히 많이들어간다 ㅡㅡ..  다 떨어내고 중요한 부분은 파라미터 앞에것 세개만 보면 된다.
 우선 HeightProperty라는 DependencyProperty의 인스턴스를 DependencyProperty.Register라는 작업을 해준다.(이 Register는 static 메소드이다.) 이 때 넣어주는 파라미터가 "Height"라는 string과 두 개의 타입을 넣는다. 처음 "Height"가 익히 알고있는 Height 라는 이름일 것이다. 두번째부터 있는 타입은, 처음것은 Height의 진짜 타입이다. 그리고 두번째 타입은 이 HeightProperty라는 property를 갖는 owner의 타입이다.
 흠.. 종합해보면 WPF의 property들은 DependencyPropery의 인스턴스이며, DependencyPropery.Register라는 작업을 통해서 이름과 저장되는 타입, 그리고 소유주의 타입정보를 담아 어딘가에 등록을 하며 추가적으로 값이 변했을 때 호출되는 콜백함수 정보를 갖는 Metadata나 값이 참값인지 확인하는 콜백함수를 등록하기도 한다는 내용이다.
 게다가 각control의 property들이 static임에도 서로 다른 값을 가지는 걸 보면, 클래스 내의 DependencyProperty 인스턴스는 실제값을 저장하지 않는다는것과 DependencyProperty.Register의 과정을 통해 어딘가에 실제값을 등록한다는 것을 짐작할 수 있다.
 과연 어디에 저장되는 것일까? 조금 더 깊이 가보자. DependencyProperty.Register의 동작을 보면 그 속에선 DependencyProperty의 RegisterCommon을 호출한다. 그리고 그 속에서야 드디어 new DependencyProperty를 하게된다 ㅠㅠ
꽁꽁숨겨놨구나. 그런데 new라니? 아까는 DependencyProperty가 실제 값이 아니라며 공간을 만들어서 뭐에쓰려고? 더 들춰보자.
 들어가보면 private construct로 dependency property를 만들기 위한 멤버들을 초기화 하고 있고 가장 눈에띄는 행동으로  RegisteredPropertyList.Add(this)의 작업을 하고있다! 아하 생성되는 동시에 internel static의 리스트에 등록시키는구나
(illef씨는 Dictionary에 등록시킨다고 하셨는데 도저히 못찾겠다...ㅜ  일단 있다고 하셨으니 짐작하기엔 동일한 컨트롤에 대한 dependency property는 RegisterdPropertyList에 추가되고, DependencyObject에서는 값의 해석과 실제값의 저장을 위해  만들어둔 DependencyProperty를 Key값으로 Dictionary에 등록시키는 것 같다. 하지만 찾아보기엔 내공이 부족하다..)

 DependencyProperty가 어떤식으로 구성되는지 알 것같다(DependencyObject와의 관계는 아직도 잘 모르겠지만.. ㅠ) 그렇다면 어떻게 값을 바꾸거나 사용되는지도 보자. 우선 FrameworkElement를 보면 UIElement를 상속하며, 이 클래스를 따라 쭉 올라가보면 DependencyObject를 상속하고 있는게 보인다. 그리고 FrameworkElement의 member들을 살펴보면, property를 wrapping해서 관리하고 있다는 것을 볼 수 있다.

public double Height{
    get
    {
        return (double) base.GetValue(HeightProperty);
    }
    set
    {
        base.SetValue(HeightProperty, value);
    }
}
게다가 특이하게 GetValue와 SetValue라는 메소드를 통해서 get과 set이 이루어진다. 여기서 GetValue와 SetValue가 DependencyObject의 메소드이다. (GetValue나 SetValue의 속을 들여다보고...  그냥 간단하게 설명하고 말아야겠다. 라는 생각을 했다.) 분명 이 메소드를 통해서 아까 등록된 리스트로의 접근이 이루어 질 것이고(직접적이든 간접적이든 공간에 접근하긴 하겠지^^; 확인해보진 못하겠다.)  실제 값의 변경이나 참조를 가능하게 해줄 것이다. 또한 등록시 옵션으로 준 owner의 metadata를 통해서 attached property나 property의 상속이 가능한 것 같다.(짐작..)

 이로써 기존 control이 어떤게 DependencyObject를 생성하고, 등록되고, 어떻게 값을 바꾸고 변경하는지에 대해 간단하게나마 이해할 수 있게되었다.(물론 짐작 반 사실 반이라 믿을만 하진 못하다.. 그리고 DependencyMetadata에 대한 내용은 천천~히 알아보자..  는 말은 나도 잘 모른다는 뜻 ㅋ)
 사실 글 쓴 목적은 나만의 property를 만들어보는 것이었는데,, 산으로 가버렸지만 하하..  나만의 property는 다음 글에서 만들어보고, 이번글은 마쳐야 겠다.

'Coding Note' 카테고리의 다른 글

[CUDA] visual studio 2010 configuration at x64  (0) 2012.03.08
[WPF] User Dependency Property  (0) 2012.01.21
[WPF] Layout  (2) 2012.01.20
[WPF] Properties  (2) 2012.01.20
[WPF] about XAML  (0) 2012.01.19