WPF 스터디 시즌 3 문서입니다!
Thanks go to these wonderful people (List made with contrib.rocks):
참고 내용
-
GitHub Profile
-
GitHub Wiki
- 1. Button
- 2. ControlTemplate
- 3. DataTemplate
- 4. Trigger
- 5. ContentControl
- 6. ListBox
- 7. ListBoxItem
- 8. ItemsControl
- 9. CustomControl
- 10. GetContainerItemForOverride
- 11. AutoGrid.Core
- 12. CommunityToolkit
- 13. NugetPackage
- 14. Bubbling / Tunneling
- 15. Languages
- 16. Themes
- 17. TreeView / TreeViewItem
- ContentControl을 상속한다.
- 즉,
Content
프로퍼티를 갖고 있으며 이는 곧 Button의 내용이다.
<Button Content="버튼"/>
Control
클래스가 갖고 있는Template
프로퍼티의 타입이다.Control
의Template
을 정의(set value)한다는 것은, 해당Control
의 기존 xaml 구성을 모두 지우고 다시 그리겠다는 의미다.
<Button>
<Button.Template>
<!-- ControlTemplate 을 정의하는 순간 본래 Button의 모습을 잃어버린다. -->
<ControlTemplate>
<!-- StackPanel, CheckBox, TextBlock 으로 새로운 Button을 그린다. -->
<StackPanel Orientation="Horizontal">
<CheckBox/>
<TextBlock Text="Button"/>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
ControlTemplate
은TargetType
프로퍼티를 갖고 있다.TargetType
으로 새로 그리는Control
의 타입을 알려줘야 해당Control
의 고유 프로퍼티를 호출/연결할 수 있다.ControlTemplate
은Triggers
프로퍼티를 갖고 있다.Triggers
의 타입은TriggerCollection
으로,TriggerBase
를 아이템으로 가진다. (4. Trigger 참조)Trigger
를 등록하여 대상Control
의 상태를 감시하고 변경 할 수 있다. (4. Trigger 참조)
<!-- TargetType 으로 Button 지정 -->
<ControlTemplate TargetType="{x:Type Button}">
...
<ControlTemplate.Triggers>
<!-- Button(ButtonBase)의 고유 프로퍼티인 IsPressed 와 연결 가능 -->
<!-- IsPressed True 로 변경 시 Background 값 #777777 으로 변경 -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#777777"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
- 대상
Control
의 프로퍼티와 연결하기 위해TemplateBinding
을 사용한다.
<ControlTemplate TargetType="{x:Type Button}">
<!-- Button의 BorderBrush, Background 프로퍼티를 연결 -->
<Border BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="1"
Padding="16 6">
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#777777"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
- 내부 Control에
Name
을 부여하여 내부에서 직접 접근하는 방법도 있다.
<ControlTemplate TargetType="{x:Type Button}">
<!-- 내부 Control에 border Name 부여 -->
<!-- Background 연결 해제 -->
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
Background="#eeeeee"
BorderThickness="1"
Padding="16 6">
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<!-- TargetName 으로 border를 지정하여 Border Background에 직접 접근 -->
<Setter TargetName="border" Property="Background" Value="#777777"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
- 대상
Control
이ContentControl
을 상속하고 있다면,ContentPresenter
를 통해ContentTemplate
을 바인딩 할 수 있다.
<ControlTemplate TargetType="{x:Type Button}">
<!-- 내부 Control에 border Name 부여 -->
<!-- Background 연결 해제 -->
<Border x:Name="border"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="1"
Padding="16 6">
<!-- ContentPresenter 로 Content 바인딩 -->
<ContentPresenter/>
<!-- 아래 코드와 같은 의미
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"/>
-->
</Border>
</ControlTemplate>
-
ContentControl을 상속 받는 클래스의 ContentTemplate을 재정의 해줌
Content
를 재정의하고 있으며,ContentControl
을 상속 받는Window
나Button
이나 모두 같은 원리로 동작한다.(ContentControl을 상속 받는 모든 개체)Button
,ToggleButton
,CheckBox
,RadioButton
등에 모두 같은DataTemplate
이 적용된 것을 볼 수 있다.
-
실행 화면 (좌측부터
Button
,ToggleButton
,CheckBox
,RadioButton
- 같은DataTemplate
을 사용하고 있다.)
<!-- 위 화면의 xaml 코드 -->
<Window.Resources>
<DataTemplate x:Key="ButtonContentTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Text1"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="Text2"/>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<Button Margin="5"
ContentTemplate="{StaticResource ButtonContentTemplate}"/>
<ToggleButton Margin="5"
ContentTemplate="{StaticResource ButtonContentTemplate}"/>
<CheckBox Margin="5"
ContentTemplate="{StaticResource ButtonContentTemplate}"/>
<RadioButton Margin="5"
ContentTemplate="{StaticResource ButtonContentTemplate}"/>
</StackPanel>
TriggerBase
를 상속한다.- 조건을 설정하고, 조건 만족시 변경할 상태(or Action)를 정의.
- 조건 불만족 시 이전 상태로 복귀.
- 주요 프로퍼티.
Name | Type | Note |
---|---|---|
Property |
DependencyProperty |
감시 대상(Control)의 Property(DependencyProperty) |
Value |
object |
설정한 Property 와 비교할 값 |
Setters |
SetterBaseCollection |
Trigger 조건 만족 시 적용할 Setter 목록 (복수 Setter 설정 가능) |
<Button Content="버튼">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<!-- Trigger 1. 감시 대상 Button의 IsMouseOver 값이 True 일 때 -->
<!-- Foreground = Red, Cursor = Hand 로 변경 -->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
<!-- Trigger 2. 감시 대상 Button의 IsPressed 값이 True 일 때 -->
<!-- Foreground = White 로 변경 -->
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="White"/>
<!-- Setters 태그 생략 가능
<Trigger.Setters>
<Setter Property="Foreground" Value="White"/>
</Trigger.Setters>
-->
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Content
프로퍼티를 갖고 있다.Content
타입은object
로 다른 Control 을 넣을 수 있다.
<!-- case 1. text content-->
<Button Content="버튼"/>
<!-- case 2. control content -->
<Button>
<Button.Content>
<StackPanel Orientation="Horizontal">
<CheckBox/>
<TextBlock Text="버튼"/>
</StackPanel>
</Button.Content>
</Button>
Content
로 문자열만 입력된 경우는 내부적으로TextBlock
이 추가됐다고 볼 수 있다.
<!-- case 1 -->
<Button Content="버튼"/>
<!-- case 2 -->
<Button>
<Button.Content>
버튼
</Button.Content>
</Button>
<!-- case 3 -->
<Button>
<Button.Content>
<TextBlock Text="버튼"/>
</Button.Content>
</Button>
ContentTemplate
프로퍼티를 갖고 있다.ContentTemplate
타입은DateTemplate
으로 Resource에 정의한 DataTemplate을 넣을 수 있다.
<Window.Resources>
<!-- DataTemplate example -->
<DataTemplate x:Key="buttonContentTemplate">
<TextBlock Text="버튼"/>
</DataTemplate>
</Window.Resources>
<Grid>
<!-- Use ContentTemplate -->
<Button ContentTemplate="{StaticResource buttonContentTemplate}"/>
</Grid>
- Xaml 에서
Content
태그는 생략 가능하다.
<Button>
<Button.Content>
버튼
</Button.Content>
</Button>
<!-- Content Tag 생략 -->
<Button>
버튼
</Button>
ContentControl
클래스를 상속받는 Control 목록 (작성 중...)
클래스 | 부모 클래스 |
---|---|
Button | ButtonBase |
CheckBox | ContentControl |
RadioButton | ContentControl |
ToggleButton | ContentControl |
ListBoxItem | ContentControl |
Label | ContentControl |
ComboBoxItem | ContentControl |
ListViewItem | ContentControl |
TreeViewItem | ContentControl |
GroupBox | ContentControl |
Window | ContentControl |
UserControl | ContentControl |
ScrollViewer | ContentControl |
- 다음과 같은 상속 관계를 가진다
ItemsControl
->Selector
->ListBox
- 주요 프로퍼티
Name | Type | Content | Note |
---|---|---|---|
ItemsSource |
IEnumerable |
ListBoxItem 을 생성하기 위한 컬렉션 |
ItemsControl 에서 상속됨 |
ItemTemplate |
DataTemplate |
ListBoxItem 의 ContentTemplate을 재정의하기 위한 DataTemplate |
ItemsControl 에서 상속됨 (3. DataTemplate 참조) |
ItemContainerStyle |
Style |
ListBoxItem 의 Style |
ItemsControl 에서 상속됨 |
DisplayMemberPath |
string |
ListBoxItem 의 Content로 표시할 Path 이름. 바인딩 된 아이템 Source 객체의 프로퍼티 중 Content로 표시할 프로퍼티 이름으로 설정한다. |
ItemsControl 에서 상속됨 |
SelectedItem |
object |
|
Selector 에서 상속됨 |
SelectionMode |
SelectionMode (Enum) |
ListBox 의 선택 동작 정의 |
|
- 다음과 같은 상속 관계를 가진다
- ContentControl ->
ListBoxItem
- ContentControl ->
- ListBox 의
ItemTemplate
을 설정하여 Content를 재정의할 수 있다. - ListBox 의
ItemContainerStyle
설정하여 Style을 적용할 수 있다.
- 이벤트의 순서는
Tunneling
->Bubbling
순서로 발생한다.
Tunneling
이벤트는UIElement
의Preview
접두사가 붙은 이벤트이다.Tunneling
이벤트는Tunneling
이벤트를 처리하는Handler
가 없으면Bubbling
이벤트를 처리하는Handler
를 찾는다.
Bubbling
이벤트는Tunneling
이벤트와 반대로UIElement
의Preview
접두사가 붙지 않은 이벤트이다.
- Arong Note. : 일상 생활 내용 및 IT 프로그램 기술 관련 정보 정리하는 공간
- jamesnet214. : WPF 개발 내용 및 인생 팁
- kjun. : C# 개발 내용 정리
- Kratos. : C# 관련