XAML or HTML

'template'에 해당되는 글 2건

  1. 018. 컨트롤템플릿(ControlTemplate) #1
  2. 019. 컨트롤템플릿(ControlTemplate) #2

018. 컨트롤템플릿(ControlTemplate) #1

XAML 뽀개기

ControlTemplate 한마디로 정의하자면 외형바꾸기입니다. 모든 컨트롤은 ControlTemplate 가질 있습니다. 다시 말하자면 System.Windows.Controls.Control을 상속 받은 컨트롤은 템플릿을 가질 수 있습니다.

 

물론 아주 간단한 외형 변경은 Style 이용해 바꿀 수도 있습니다. 하지만 다른 요소들을 추가하는  복잡하고 섬세한 수준의 외형 변경은 한계가 있습니다. 다시 말해 버튼의 외형에 간단한 도형이라도 추가하려면 스타일을 이용해서는 불가능에 가깝습니다.

 

Button 외형바꾸기는 지겨우니깐 단계 복잡한 컨트롤을 예를 들어 살펴봅시다.

 

 

Header Content 그룹으로 묶여있는 구조입니다. 위와 같이 표현하는 방법에는 어떤 것들이 있을까요?

 

1
2
3
4
5
<StackPanel Margin="15,10">                
    <TextBlock Text="재생" FontWeight="Bold" Margin="5"/>                
    <Button Content="시작"/>                
    <Button Content="정지"/>            
</StackPanel>
cs

 

아무래도 위와 같은 XAML 코드가 가장 빠르고 적당할 같습니다.

 

 

만약 위와 같은 형식이 몇 번이고 반복된다면 어떨까요?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<StackPanel>
    <StackPanel Margin="15,10">
        <TextBlock Text="재생" FontWeight="Bold" Margin="5"/>
        <Button Content="시작"/>
        <Button Content="정지"/>
    </StackPanel>
    <StackPanel Margin="15,10">
        <TextBlock Text="트랙" FontWeight="Bold" Margin="5"/>
        <Button Content="이전"/>
        <Button Content="다음"/>
    </StackPanel>
    <StackPanel Margin="15,10">
        <TextBlock Text="소리" FontWeight="Bold" Margin="5"/>
        <Button Content="작게"/>
        <Button Content="크게"/>
    </StackPanel>
</StackPanel>
cs


StackPanel 각 그룹 요소를 감싼 후 반복해서 코드를 작성하면 되겠습니다. 하지만 여기에 디자인을 변경하기 위한 스타일링 작업이 추가된다면 어떨까요?

 

 

Border 요소를 추가하고 Background, BorderBrush, BorderThickness, Margin 속성 등을 이용해 아주 살짝 스타일을 다듬어주었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<StackPanel>
    <Border Background="WhiteSmoke" BorderBrush="DarkGray" BorderThickness="1" Margin="5">
        <StackPanel Margin="5" Background="WhiteSmoke">
            <TextBlock Text="재생" FontWeight="Bold" Margin="0,0,0,5"/>
            <Button Content="시작"/>
            <Button Content="정지"/>
        </StackPanel>
    </Border>
    <Border Background="WhiteSmoke" BorderBrush="DarkGray" BorderThickness="1" Margin="5">
        <StackPanel Margin="5">
            <TextBlock Text="트랙" FontWeight="Bold" Margin="0,0,0,5"/>
            <Button Content="이전"/>
            <Button Content="다음"/>
        </StackPanel>
    </Border>
    <Border Background="WhiteSmoke" BorderBrush="DarkGray" BorderThickness="1" Margin="5">
        <StackPanel Margin="5">
            <TextBlock Text="소리" FontWeight="Bold" Margin="0,0,0,5"/>
            <Button Content="작게"/>
            <Button Content="크게"/>
        </StackPanel>
    </Border>
</StackPanel>
cs

 

아주 간단한 스타일 변경이지만 그룹 및 그룹 내 요소의 갯수만큼 반복해서 XAML 코드가 늘어납니다. 말인 즉슨 디자인이 변경될 경우 그룹 및 그룹 내 요소의 갯수만큼 코드를 변경해야 한다는 말과 같습니다. 자 그러면 그런 비효율적인 일 최소화할 있을까요? 하나하나씩 고쳐보겠습니다.



1
2
3
4
5
6
<HeaderedContentControl Header="재생" Grid.Column="1">
    <StackPanel>
        <Button Content="시작"/>
        <Button Content="정지"/>
    </StackPanel>
</HeaderedContentControl>
cs

 

먼저 HeaderedContentControl을 사용하면 Header Content가 짝으로 이루어진 그룹을 표현할 있습니다. 컨트롤 이름에서 어느 정도 짐작이 됩니다. 그런데 어떻게 이런 기본 구조가 표현되는지 궁금할겁니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<Style x:Key="Style_HeaderedContentControl" TargetType="{x:Type HeaderedContentControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type HeaderedContentControl}">
                <StackPanel>
                    <ContentPresenter ContentSource="Header"/>
                    <ContentPresenter />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
 
cs

 

Blend for VS [템플릿 편집 > 복사본 편집] 기능을 이용하면 아주 간단히 HeaderedContentControl의 기본 ControlTemplate 얻을 있습니다. 자동으로 생성된 코드를 살펴보면 템플릿은 스타일에 속한다고 볼  있습니다. 단독으로 사용될 수도 있습니다만 다음 기회에 살펴봅시다.

 

2개의 ContentPresenter Header Content 역할을 하는 것을 알  있습니다. 단순히 StackPanel 이용해 헤더와 컨텐츠를 세로로 정렬하고 있는 구조입니다. 이전 포스트에서 ContentPresenter 암시적으로 바인딩된다고 이야기했습니다. 그리고 Header 분리하기 위해 ContentSource 속성을 이용해 명시적으로 정의하고 있습니다. Content 속성에 TemplateBinding 문법을 이용해 명시적으로 정의할 수도 있습니다.

 

이렇게 ControlTemplate 컨트롤의 기본 구조 정의와 함께 외형을 정의하는 역할을 합니다. 다른 요소들을 추가하거나 다양한 속성들을 정의해  복잡하고 새로운 외형을 스타일링  있습니다. 다음 포스트에 이어 템플릿을 수정해 보도록 하겠습니다.


관련 목차


018. 컨트롤템플릿(ControlTemplate) #1

019. 컨트롤템플릿(ControlTemplate) #2

019. 컨트롤템플릿(ControlTemplate) #2

XAML 뽀개기

이번 포스트에서는 템플릿 수정과 다양한 템플릿의 효율적인 사용방법에 대해 알아봅니다.

 

1
2
3
4
5
6
7
<HeaderedContentControl Header="재생" Grid.Column="1"
                        Style="{DynamicResource Style_HeaderedContentControl}">
    <StackPanel>
        <Button Content="시작"/>
        <Button Content="정지"/>
    </StackPanel>
</HeaderedContentControl>
cs


이전 포스트에서 Blend for VS [템플릿 편집 > 복사본 편집기능을 이용해 HeaderedContentControl의 기본 템플릿을 구했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Style x:Key="Style_HeaderedContentControl" TargetType="{x:Type HeaderedContentControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type HeaderedContentControl}">
                <Border Background="WhiteSmoke" 
                        BorderBrush="DarkGray" 
                        BorderThickness="1" 
                        Margin="5">
                    <StackPanel Background="WhiteSmoke" 
                                Margin="5">
                        <ContentPresenter ContentSource="Header" 
                                          TextBlock.FontWeight="Bold" 
                                          Margin="0,0,0,5"/>
                        <ContentPresenter />
                    </StackPanel>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
cs

 

이전 포스트에서 작성했던 스타일링 작업의 XAML 코드를 참고해 템플릿을 수정했습니다. HeaderedContentControl의 구조와 외형을 변경하는 작업입니다.

 

1
2
3
4
5
6
7
<HeaderedContentControl Header="재생"
                        Style="{DynamicResource Style_HeaderedContentControl}">
    <StackPanel>
        <Button Content="시작"/>
        <Button Content="정지"/>
    </StackPanel>
</HeaderedContentControl>
cs

           

HeaderedContentControl에 스타일을 각각 선언 수도 있지만 StackPanel 아래에 리소스로 스타일을 정의하면서 Key 이름을 생략하고 BasedOn 속성을 이용해 일괄적으로 하위 컨트롤에 영향을 미칠  있습니다

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<StackPanel Grid.Column="1">
    <StackPanel.Resources>
        <Style TargetType="HeaderedContentControl"
               BasedOn="{StaticResource Style_HeaderedContentControl}"/>
    </StackPanel.Resources>
            
    <HeaderedContentControl Header="재생">
        <StackPanel>
            <Button Content="시작"/>
            <Button Content="정지"/>
        </StackPanel>
    </HeaderedContentControl>
    <HeaderedContentControl Header="트랙">
        <StackPanel>
            <Button Content="이전"/>
            <Button Content="다음"/>
        </StackPanel>
    </HeaderedContentControl>
    <HeaderedContentControl Header="소리">
        <StackPanel>
            <Button Content="작게"/>
            <Button Content="크게"/>
        </StackPanel>
    </HeaderedContentControl>
</StackPanel>
cs



  절약하고 깔끔한 코드를 얻게 되었습니다. 이전 포스트에서도 다룬 적이 있으니 참고하세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<StackPanel.Resources>
    <ControlTemplate x:Key="Template_HeaderedContentControl" 
                     TargetType="{x:Type HeaderedContentControl}">
        <Border Background="WhiteSmoke" 
                BorderBrush="DarkGray" 
                BorderThickness="1" 
                Margin="5">
            <StackPanel Background="WhiteSmoke" 
                        Margin="5">
                <ContentPresenter ContentSource="Header" 
                                  TextBlock.FontWeight="Bold" 
                                  Margin="0,0,0,5"/>
                <ContentPresenter />
            </StackPanel>
        </Border>
    </ControlTemplate>
</StackPanel.Resources>
cs


1
2
3
4
5
6
7
<HeaderedContentControl Header="재생"
                        Template="{DynamicResource Template_HeaderedContentControl}">
    <StackPanel>
        <Button Content="시작"/>
        <Button Content="정지"/>
    </StackPanel>
</HeaderedContentControl>
cs


 

스타일이 아니더라도 템플릿을 변경할 있습니다. 말인 즉슨 스타일의 ControlTemplate을 단독으로도 사용할 있다는 것입니다. 리소스로 정의해 사용하는 방법 동일하기 때문에 Key 이름 선언이 필수입니다.

 

1
2
3
4
5
6
7
<!--HeaderedContentControl의 Content 템플릿-->
<DataTemplate x:Key="DataTemplate_Content">
    <StackPanel Orientation="Horizontal">
        <Button Content="이전" Width="50" Margin="0,0,5,0"/>
        <Button Content="다음" Width="50"/>
    </StackPanel>
</DataTemplate>
cs

 

1
2
3
4
5
6
7
8
<HeaderedContentControl Header="트랙"
                        Template="{DynamicResource Template_HeaderedContentControl}"
                        ContentTemplate="{DynamicResource DataTemplate_Content}">
    <!--<StackPanel>
        <Button Content="이전"/>    
        <Button Content="다음"/>        
    </StackPanel>-->
</HeaderedContentControl>
cs

 

 

Content만의 템플릿을 새로이 정의할 수도 있습니다. 이 템플릿은 DataTemplate이라고 합니다. DataTemplate은 이전 ControlTemplate의 하위 템플릿이라고 할  있습니다. DataTemplate 다른 포스트에서 다시 살펴보겠습니다.

 

1
2
3
4
5
6
7
<!--HeaderedContentControl의 Header 템플릿-->
<DataTemplate x:Key="DataTemplate_Header">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="※" Margin="0,0,5,0" Foreground="Red"/>
        <TextBlock Text="{Binding }" Foreground="Red"/>
    </StackPanel>
</DataTemplate>
cs

 

1
2
3
4
5
6
7
8
<HeaderedContentControl Header="소리" 
                        Template="{DynamicResource Template_HeaderedContentControl}"
                        HeaderTemplate="{DynamicResource DataTemplate_Header}">
    <StackPanel>
        <Button Content="작게"/>
        <Button Content="크게"/>
    </StackPanel>
</HeaderedContentControl>
cs

 

 

앞서 본 Content의 템플릿과 동일한 방법으로 Header만의 템플릿을 새로이 정의할 수도 있습니다.

 

Template, ContentTemplate, HeaderTemplate 모두 템플릿이라 있습니다. Template 기본 골격(외형)이라면 ContentTemplate, HeaderTemplate 아래 골격(외형)이라 있겠습니다. ContentPresenter의 Content 속성이 암시적 바인딩이 작용한 것과 같이 템플릿 속성도 암시적으로 바인딩됩니다.

 

지금까지 예로  템플릿 사용 방법들은 기본 골격은 같은데 특정 일부만 변경을 필요로 할  하위 템플릿을 새로이 정의해서 리소스(템플릿) 효율적으로 사용 가능케 합니다.


관련 목차


018. 컨트롤템플릿(ControlTemplate) #1

019. 컨트롤템플릿(ControlTemplate) #2