WPF에서 DataTemplate 리소스의 암시적 Key 지정

안녕하세요?

저는 WPF가 처음 나왔을 때부터 사용했는데요, 부끄럽지만 오늘에야 알게 된 내용이 있어 한 번 적어볼까 합니다ㅎ

WPF에서 암시적 키를 가지는 리소스를 정의할 때 StyleDataTemplatex:Key가 어떻게 다르게 적용되는지에 대한 이야기입니다.

Style 리소스의 암시적 키 지정

일반적으로, 컨트롤에 대한 Style 리소스를 정의할 때 x:Key를 명시적으로 설정하지 않으면 자동으로 TargetType 속성으로 지정된 Type 인스턴스가 키로 설정됩니다.

예를 들어, 버튼에 대한 스타일을 정의할 경우, 다음과 같이 x:Key를 생략해도 암시적으로 아래와 같은 구문이 추가됩니다.

<Style TargetType="{x:Type Button}">
    <!-- ... -->
</Style>

<!-- 컴파일 된 리소스 -->
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
    <!-- ... -->
</Style>

그리고 해당 스타일을 참조할 때는 다음과 같이 사용할 수 있습니다.

<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}" 
       BasedOn="{StaticResource {x:Type Button}}" />

여기까지는 대부분 알고 계신 내용입니다.

DataTemplate 리소스의 암시적 키 지정

그렇다면 DataTemplate에서는 암시적 키가 어떻게 작동할까요?

저를 포함한 많은 분들이 Style과 마찬가지로 DataTemplate도 자동으로 DataType속성으로 지정된 형식의 인스턴스가 자동으로 x:Key="{x:Type local:MyType}" 형태로 설정되지 않은까?라고 생각하고 계실 것 같습니다.

공식문서를 살펴봐도 자동으로 지정된다고만 나와 있을 뿐 구체적은 내용은 없습니다.

DataTemplate 클래스에는 Style 클래스의 TargetType 속성과 매우 유사한 DataType 속성이 있습니다. 따라서 위 예제에서 DataTemplate에 대한 x:Key를 지정하는 대신 다음을 수행할 수 있습니다.

DataTemplate은 모든 Task 개체에 자동으로 적용됩니다. 이 경우 x:Key는 암시적으로 설정됩니다. 따라서 이 DataTemplatex:Key 값을 할당하면 암시적 x:Key가 재정의되고 DataTemplate이 자동으로 적용되지 않습니다.

심지어 StackOverflow에서도 위 내용처럼 x:Key="{x:Type 형식이름}"으로 설정된다고 답변하고 있습니다.

하지만 이 답변을 잘못된 답변으로, 실제로는 그렇게 동작하지 않습니다.

예를 들어, MyType이라는 타입에 대한 DataTemplate을 다음과 같이 작성했을 때,

<DataTemplate DataType="{x:Type local:MyType}">
    <!-- 템플릿 내용 -->
</DataTemplate>

이렇게 정의된 리소스를 참조하기 위해 다음과 같은 코드를 작성하면 오류가 발생합니다.

<ContentControl Content="{Binding MyObject}" 
                ContentTemplate="{StaticResource {x:Type local:MyType}}"/>

DataTemplateKey

컴파일된 XAML 파일을 리플렉터 툴로 디컴파일 해보면 WPF는 아래와 같은 코드를 생성하는 것을 확인할 수 있습니다.

<DataTemplate x:Key="{DataTemplateKey {x:Type local:MyType}}" 
              DataType="{x:Type local:MyType}" >
    <!-- 템플릿 내용 -->
</DataTemplate>

WPF에서는 DataTemplatex:Key를 명시적으로 지정하지 않으면, 컴파일러는 위와 같이 자동으로 x:Key="{DataTemplateKey {x:Type local:MyType}}" 구문을
추가해서 DataTemplateKey형식의 래퍼 객체 인스턴스를 키로 지정합니다.

이제 암시적 키로 정의된 DataTemplate을 명시적으로 참조하려면 아래와 같이 사용할 수 있습니다.

<ContentControl Content="{Binding MyObject}" 
                ContentTemplate="{StaticResource {DataTemplateKey {x:Type local:MyType}}}"/>

이상으로 StyleDataTemplate은 리소스의 암시적 키가 어떻게 다르게 설정되는지 알아봤습니다.
혹시나 아직 모르셨던 분들이 계시다면 도움이 됐으면 합니다.

감사합니다ㅎ

13개의 좋아요

저도 오늘에야 처음 알았네요.
감사합니다!!

WPF가 XAML에서 암시적으로 동작하는 부분이 많아서 이 부분은 확실한 짬의 영역인거 같습니다…아티클도 많은 편이 아니라서 이런 글이 도움이 많이 되는 것 같습니다.

3개의 좋아요