티스토리 뷰
최근에 SDK 강좌를 위해 샘플을 만들다가 놀라운걸 발견했습니다.
개발자와 팀원들과 오랜 회의 끝에 겨우 개념을 잡았는데
이제 그걸 공개할테니 여러분들도 같은 문제로 고민하지 마시기 바랍니다.
여기 내가 찾아낸 문제 소스 입니다.
세개의 아이템으로 ListBoxItem 과 ListBox 를 만들어 XAML로 추출하는 과정입니다.
string 과 TextBlock이 포함된 ListBoxItem 그리고 TextBlock입니다.
<Window x:Class="Blog11_06.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Blog11_06"
>
<!--Create a Style for a ListBoxItem that sets
the Foreground to Green and HorizontalContentAlignment to Right.-->
<Window.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
</Window.Resources>
<WrapPanel>
<!--The ListBox has its Foreground set to Blue and the
HorizontalContentAlignment set to Center.-->
<ListBox Width="250"
Foreground="Blue"
HorizontalContentAlignment="Center">
String not in a TextBlock.
<ListBoxItem>
<TextBlock Name="textBlock1">TextBlock in a ListBoxItem.</TextBlock>
</ListBoxItem>
<TextBlock Name="textBlock2">TextBlock not in a ListBoxItem.</TextBlock>
</ListBox>
</WrapPanel>
</Window>
ListBoxItems들이 서로 섞여서 만들어지는걸 원하지는 않을 겁니다.
하지만 아래를 보세요.
샘플로 만든 ListBox 입니다.:
스타일에 지정한 색상대로 나오지 않는다는걸 볼 수가 있습니다.
이러한 원인은 트리구조에서 부모값을 그대로 상속받아서 생깁니다.
여기 예제에서 textBlock1의 속성을 바꾸기 위해 ListBoxItem이 속성값을 바꿉니다.
그럼 textBlock2 도 그 값을 가지게 됩니다.
결국 아래와 같은 말이 되는 겁니다.
ListBoxItem은 새로 생기건 말건 원래 있던 ListBoxItem의 속성을 따르게 됩니다.
다만, 트리구조가 다른곳에 있다면 새로운 스타일을 적용할 순 있지요
아래 코드를 한번 봅시다.
<!--ContentControl with its Content property set
to a TextBlock.-->
<ContentControl Name="cc1" Margin="20" Foreground="Blue">
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border TextBlock.Foreground="Red" >
<StackPanel >
<TextBlock Text="In template" />
<ContentPresenter />
</StackPanel>
</Border>
</ControlTemplate>
</ContentControl.Template>
<ContentControl.Content>
<TextBlock Text="Logical content is a TextBlock" />
</ContentControl.Content>
</ContentControl>
<!--ContentControl with its Content property set
to a string.-->
<ContentControl Name="cc2" Margin="20" Foreground="Blue">
<ContentControl.Template>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border TextBlock.Foreground="Red" >
<StackPanel >
<TextBlock Text="In template" />
<ContentPresenter />
</StackPanel>
</Border>
</ControlTemplate>
</ContentControl.Template>
<ContentControl.Content>
Logical content is a string
</ContentControl.Content>
</ContentControl>
두가 샘플에서 아래와 같은 결과를 보입니다.
둘다 ContentControls안에 있습니다.
근데 속성은 다르죠
두번째 경우는 . ContentControl의 자식으로 속성을 이어 받아서 부모의 파란색으로 설정한 속성을 이어 받지 않았습니다.
자 또다른 경우의 트리를 봅시다.
WPF에서 Border는 부모가 될수가 없습니다.
아래의 형태를 갖춘 트리가 있다면
Border의 Textblock 속성 red을 따르지 않고, ContentControl의 속성 Blue를 따르게 됩니다.
결론적으로,
부모가 누구냐에 따라서 속성값이 달라집니다.
아래의 4가지 사항만 명심하시면 상속에 대한 개념에 대해서 헷갈리지 않을 겁니다.
- 속성값은 그 요소가 속해있는 부모값을 따른다.
- string은 부모가 없으며, 상속받지 않는 객체다.
- 객체가 부모가 없다면 WPF가 속성값을 만든다.
- 명시적으로 만든 아이템들도 (ListBoxItem, TreeViewItem, TabItem, 등등.) 논리적 트리를 포함하지만 암묵적으로 만든 아이템은 비쥬얼 트리안에 포함된다.
암묵적이든, 명시적이든 스타일은 가지고 있지만 자식 트리는 명시적인 속성값을 따른다. - 컨트롤 템플릿은 컨트롤의 비쥬얼 트리를 정의한다.
이 컨트롤은 컨트롤 객체 모델에 의존하는 논리적 트리이다.
(흠...번역하면서 대충 이해하긴 했지만, 그냥 읽는 사람은 더 헷갈릴지도 -0-)