스타일 지정 및 템플릿

업데이트: 2007년 11월

WPF(Windows Presentation Foundation) 스타일 및 템플릿은 응용 프로그램, 문서 또는 UI(사용자 인터페이스) 디자이너가 멋진 시각 효과를 만들고 제품의 모양을 표준화하는 데 사용할 수 있는 기능 집합(스타일, 템플릿, 트리거 및 스토리보드)을 가리킵니다. 제작자나 디자이너가 응용 프로그램별로 모양을 폭넓게 사용자 지정할 수 있지만 응용 프로그램 내에서나 응용 프로그램 간에 일관성 있는 모양을 유지 및 공유하려면 강력한 스타일 및 템플릿 모델이 필요합니다. WPF(Windows Presentation Foundation)는 이러한 모델을 제공합니다.

WPF 스타일 모델의 또 다른 특징은 프레젠테이션과 논리의 분리입니다. 즉, 디자이너가 XAML만 사용하여 응용 프로그램의 모양을 디자인하는 동안 개발자는 C# 또는 Visual Basic을 사용하여 프로그래밍 논리를 개발하는 작업을 수행할 수 있습니다.

이 개요에서는 두 개의 TextBlock 요소와 하나의 이미지 목록에 바인딩된 ListBox 컨트롤로 구성된 스타일 및 템플릿 소개 샘플 응용 프로그램에 대해 설명합니다.

스타일 지정된 ListView

이 개요에서는 응용 프로그램의 스타일 및 템플릿 부분을 중점적으로 설명하고 데이터 바인딩 개념에 대해서는 설명하지 않습니다. 데이터 바인딩에 대한 자세한 내용은 데이터 바인딩 개요를 참조하십시오.

또한 스타일 및 템플릿을 재사용할 수 있게 하는 리소스에 대해서도 이해해야 합니다. 리소스에 대한 자세한 내용은 리소스 개요를 참조하십시오.

이 항목에는 다음 단원이 포함되어 있습니다.

  • 스타일 기본 사항
  • 데이터 템플릿
  • 컨트롤 템플릿
  • 트리거
  • 공유 리소스 및 테마
  • 관련 항목

스타일 기본 사항

Style을 사용하면 둘 이상의 요소에 속성 값 집합을 간편하게 적용할 수 있습니다. 예를 들어 다음과 같은 TextBlock 요소와 그 기본 모양을 살펴보겠습니다.

<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>

스타일 샘플 스크린 샷

TextBlock 요소에서 직접 FontSizeFontFamily 같은 속성을 설정하여 기본 모양을 변경할 수 있습니다. 하지만 TextBlock 요소가 몇 가지 속성을 공유하도록 하려면 다음과 같이 XAML 파일의 Resources 섹션에서 Style을 만들 수 있습니다.

<Window.Resources>


...


<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
  <Setter Property="HorizontalAlignment" Value="Center" />
  <Setter Property="FontFamily" Value="Comic Sans MS"/>
  <Setter Property="FontSize" Value="14"/>
</Style>


...


</Window.Resources>

스타일의 TargetTypeTextBlock 형식으로 설정하면 창의 모든 TextBlock 요소에 스타일이 적용됩니다.

이제 TextBlock 요소가 다음과 같이 나타납니다.

스타일 샘플 스크린 샷

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 스타일 확장
  • TargetType 속성과 x:Key 특성의 관계
  • 스타일 및 리소스
  • 프로그래밍 방식으로 스타일 설정
  • 바인딩, 동적 리소스 및 이벤트 처리기

스타일 확장

TextBlock 요소는 FontFamily 및 가운데에 맞춰진 HorizontalAlignment 같은 몇 가지 속성 값을 공유하도록 하고 "My Pictures"라는 텍스트에는 몇 가지 추가 속성을 지정하려고 하는 경우를 생각해 볼 수 있습니다. 이 경우 여기에서 볼 수 있는 것처럼 첫 번째 스타일에 기반한 스타일을 새로 만들어 이러한 작업을 수행할 수 있습니다.

<Window.Resources>


...


<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
       TargetType="TextBlock"
       x:Key="TitleText">
  <Setter Property="FontSize" Value="26"/>
  <Setter Property="Foreground">
  <Setter.Value>
      <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
        <LinearGradientBrush.GradientStops>
          <GradientStop Offset="0.0" Color="#90DDDD" />
          <GradientStop Offset="1.0" Color="#5BFFFF" />
        </LinearGradientBrush.GradientStops>
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
</Style>


...


</Window.Resources>

위 스타일은 x:Key로 지정됩니다. 이 스타일을 적용하려면 여기에서처럼 TextBlockStyle 속성을 x:Key 값으로 설정합니다.

<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>

이제 이 TextBlock 스타일은 예제와 같이 HorizontalAlignment 값이 Center로, FontFamily 값이 Comic Sans MS로, FontSize 값이 26으로, Foreground 값이 LinearGradientBrush로 설정됩니다. 기본 스타일의 FontSize 값을 재정의했다는 점에 유의하십시오. Style에 동일한 속성을 설정하는 둘 이상의 Setter가 있다면 마지막으로 선언된 Setter가 우선적으로 적용됩니다.

아래에서 TextBlock 요소의 모양을 볼 수 있습니다.

스타일 적용된 TextBlocks

이 TitleText 스타일은 TextBlock 형식을 위해 만들어진 스타일을 확장합니다. 또한 x:Key 값을 사용하여 x:Key가 있는 스타일을 확장할 수도 있습니다. 예제를 보려면 BasedOn 속성용으로 제공된 예제를 참조하십시오.

TargetType 속성과 x:Key 특성의 관계

첫 번째 예제와 같이 스타일에 x:Key를 할당하지 않은 상태로 TargetType 속성을 TextBlock으로 설정하면 모든 TextBlock 요소에 해당 스타일이 적용됩니다. 이 경우 x:Key는 암시적으로 {x:Type TextBlock}으로 설정됩니다. 즉, x:Key 값을 명시적으로 {x:Type TextBlock} 이외의 값으로 설정하면 Style이 모든 TextBlock 요소에 자동으로 적용되지 않습니다. 이러한 경우 x:Key 값을 사용하여 스타일을 TextBlock 요소에 명시적으로 적용해야 합니다. 스타일이 Resources 섹션에 있고 스타일에 TargetType 속성을 설정하지 않은 경우 x:Key를 제공해야 합니다.

TargetType 속성은 x:Key에 대한 기본값을 제공하는 동시에 setter 속성이 적용되는 형식을 지정합니다. TargetType을 지정하지 않는 경우 Property="ClassName.Property" 구문을 사용하여 클래스 이름으로 Setter 개체의 속성을 정규화해야 합니다. 예를 들어 Property="FontSize"를 설정하는 대신 Property를 "TextBlock.FontSize" 또는 "Control.FontSize"로 설정해야 합니다.

또한 많은 WPF 컨트롤은 다른 WPF 컨트롤의 조합으로 구성되어 있습니다. 특정 형식의 모든 컨트롤에 적용되는 스타일을 만드는 경우 예기치 않은 결과를 가져올 수 있습니다. 예를 들어 Window에서 TextBlock 형식을 대상으로 하는 스타일을 만드는 경우 해당 스타일이 창의 모든 TextBlock 컨트롤에 적용됩니다. 이것은 TextBlockListBox와 같은 다른 컨트롤의 일부인 경우에도 마찬가지입니다.

스타일 및 리소스

FrameworkElement 또는 FrameworkContentElement에서 파생된 모든 요소에 스타일을 사용할 수 있습니다. 스타일을 선언하는 가장 일반적인 방식은 앞의 예제와 같이 XAML 파일의 Resources 섹션에서 리소스로 선언하는 것입니다. 스타일은 리소스이므로 모든 리소스에 적용되는 범위 지정 규칙을 따릅니다. 즉, 스타일을 선언하는 위치가 스타일을 적용할 수 있는 위치에 영향을 미칩니다. 예를 들어 응용 프로그램 정의 XAML 파일의 루트 요소에 선언된 스타일은 응용 프로그램의 모든 위치에서 사용할 수 있습니다. 탐색 응용 프로그램을 만드는 경우 응용 프로그램의 XAML 파일 중 하나에 선언된 스타일은 해당 XAML 파일에서만 사용할 수 있습니다. 리소스의 범위 지정 규칙에 대한 자세한 내용은 리소스 개요를 참조하십시오.

또한 이 개요 뒷부분에 있는 공유 리소스 및 테마에서 스타일 및 리소스에 대한 자세한 정보를 참조하십시오.

프로그래밍 방식으로 스타일 설정

명명된 스타일을 프로그래밍 방식으로 요소에 할당하려면 리소스 컬렉션에서 스타일을 가져와 요소의 Style 속성에 할당합니다. 리소스 컬렉션의 항목은 Object 형식이므로 검색한 스타일을 Style 속성에 할당하기 전에 Style로 캐스팅해야 합니다. 예를 들어 textblock1이라는 TextBlock에 정의된 TitleText 스타일을 설정하려면 다음과 같이 합니다.

textblock1.Style = (Style)(this.Resources["TitleText"]);

스타일을 적용하면 봉인된 상태가 되어 변경할 수 없게 됩니다. 이미 적용된 스타일을 동적으로 변경하려면 기존 스타일을 대체하는 새 스타일을 만들어야 합니다. 자세한 내용은 IsSealed 속성을 참조하십시오.

사용자 지정 논리에 따라 적용할 스타일을 선택하는 개체를 만들 수 있습니다. 예제를 보려면 StyleSelector 클래스용으로 제공된 예제를 참조하십시오.

바인딩, 동적 리소스 및 이벤트 처리기

Setter.Value 속성을 사용하여 Binding 태그 확장 또는 DynamicResource 태그 확장을 지정할 수 있습니다. 자세한 내용은 Setter.Value 속성용으로 제공된 예제를 참조하십시오.

지금까지는 setter를 사용하여 속성 값을 설정하는 방법만 설명했지만 스타일에 이벤트 처리기를 지정할 수도 있습니다. 자세한 내용은 EventSetter를 참조하십시오.

데이터 템플릿

이 샘플 응용 프로그램에서는 사진 목록에 바인딩된 ListBox 컨트롤을 사용합니다.

<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
         Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>

ListBox는 현재 다음과 같이 보입니다.

템플릿 적용 전의 ListBox

대부분의 컨트롤은 특정 콘텐츠 형식을 가지며 해당 콘텐츠를 바인딩된 데이터에서 가져오는 경우가 많습니다. 이 샘플에서 데이터는 사진 목록입니다. WPF에서 DataTemplate을 사용하여 데이터의 시각적 표현을 정의합니다. 기본적으로 DataTemplate에 설정하는 내용에 따라 렌더링된 응용 프로그램에 데이터가 표시되는 모양이 결정됩니다.

이 샘플 응용 프로그램에서는 각 사용자 지정 Photo 개체에 이미지 파일 경로를 지정하는 문자열 형식의 Source 속성이 있습니다. 현재는 사진 개체가 파일 경로로 나타납니다.

사진을 이미지로 표시하기 위해 DataTemplate을 리소스로 만듭니다.

<Window.Resources>


...


<!--DataTemplate to display Photos as images
    instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
  <Border Margin="3">
    <Image Source="{Binding Source}"/>
  </Border>
</DataTemplate>


...


</Window.Resources>

DataType 속성은 StyleTargetType 속성과 매우 유사합니다. DataTemplate이 Resources 섹션에 있으면 DataType 속성을 특정 형식으로 지정하고 x:Key에 할당하지 않는 경우 해당 형식이 나타날 때마다 DataTemplate이 적용됩니다. x:Key를 사용하여 DataTemplate을 할당한 다음 ItemTemplate 속성 또는 ContentTemplate 속성 같은 DataTemplate 형식을 가져오는 속성의 StaticResource로 설정하는 옵션을 항상 사용할 수 있습니다.

기본적으로 위 예제의 DataTemplate에서는 Photo 개체가 있을 경우에는 항상 Border 내에서 Image로 나타나도록 정의합니다. 이 DataTemplate을 사용하는 응용 프로그램은 다음과 같습니다.

사진 이미지

데이터 템플릿 모델에는 다른 기능도 있습니다. 예를 들어 MenuTreeView 같은 HeaderedItemsControl 형식을 사용하여 다른 컬렉션을 포함하는 컬렉션 데이터를 표시하는 경우 HierarchicalDataTemplate을 사용할 수 있습니다. 또 다른 데이터 템플릿 기능은 DataTemplateSelector입니다. 이 기능을 사용하면 사용자 지정 논리를 기반으로 사용할 DataTemplate을 선택할 수 있습니다. 자세한 내용은 다양한 데이터 템플릿 기능에 대해 설명하는 데이터 템플릿 개요를 참조하십시오.

컨트롤 템플릿

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • ControlTemplate을 사용하지 않는 경우
  • ControlTemplate의 정의
  • ControlTemplate 만들기
  • IsItemsHost 속성
  • ItemsPresenter 및 ContentPresenter
  • TemplateBinding

이제 사진이 이미지로 나타납니다. 계속해서 사진을 세로가 아니라 가로로 표시해 보겠습니다. ListBox를 가로로 만들어야 합니다.

ControlTemplate을 사용하지 않는 경우

먼저 ListBox를 가로로 만들기 위해 ControlTemplate을 사용할 필요가 없다는 점을 기억하십시오. ListBox에는 ListBox 항목의 레이아웃을 제어하는 템플릿인 ItemsPanelTemplate을 설정할 수 있는 ItemsPanel 속성이 있습니다. 한 가지 방법은 다음 예제와 같이 간단하게 ListBox 스타일을 만들고 ItemsPanel 속성을 설정하는 것입니다.

<Style TargetType="ListBox">
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center"/>
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>
</Style>

이 방식은 문제 없이 작동하고 ListBox를 가로로 배열할 수 있습니다. 이 예제에서는 시나리오에 따라서는 ControlTemplate을 대체하는 것 외의 다른 방법을 사용할 수도 있다는 것을 보여 줍니다. 이 예제의 경우 둥근 모서리와 같은 추가 속성이 있는 가로로 된 ListBox가 필요하다면 ListBoxControlTemplate을 사용해야 합니다.

이 작업을 수행하는 방법을 보여 주는 예제를 제시하기 전에 먼저 ControlTemplate의 개념에 대해 설명하겠습니다.

ControlTemplate의 정의

대부분의 컨트롤에는 모양과 동작이 있습니다. 단추를 생각해 보십시오. 모양은 사용자가 클릭할 수 있는 돌출된 영역이고 동작은 클릭에 대한 응답으로 발생하는 Click 이벤트입니다.

경우에 따라 필요한 동작을 제공하지만 필요한 모양을 제공하지 않는 컨트롤이 있을 수 있습니다. 지금까지는 스타일 setter를 사용하여 컨트롤 모양에 영향을 미치는 속성 값을 설정하는 방법을 소개했지만, 컨트롤의 구조를 변경하거나 컨트롤을 구성하는 구성 요소의 속성 값을 설정하려면 ControlTemplate을 사용해야 합니다.

WPF에서 컨트롤의 ControlTemplate은 컨트롤의 모양을 정의합니다. 컨트롤에 대한 새 ControlTemplate을 정의하여 컨트롤의 구조와 모양을 변경할 수 있습니다. 대부분의 경우 이 방법을 사용하는 것으로 충분하므로 고유한 사용자 지정 컨트롤을 작성할 필요가 없습니다. 컨트롤에 대해 고유한 ControlTemplate을 정의하지 않는 경우에는 시스템 테마와 일치하는 기본 템플릿을 가져옵니다. 이 템플릿이 Button 컨트롤에 기본 모양을 제공합니다.

한 가지 명심해야 할 것은 컨트롤에 대한 ControlTemplate을 만드는 것은 전체 ControlTemplate을 대체하는 작업이라는 것입니다. 예를 들어 다음과 같은 방식으로 ButtonControlTemplate을 정의할 수 있습니다.

ContentPresenter 요소는 단순히 ButtonContent가 표시될 위치를 표시합니다. 다른 부분에 대해서는 이후의 단원에서 설명할 것입니다.

<Style TargetType="Button">
  <!--Set to true to not get any properties from the themes.-->
  <Setter Property="OverridesDefaultStyle" Value="True"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="Button">
        <Grid>
          <Ellipse Fill="{TemplateBinding Background}"/>
          <ContentPresenter HorizontalAlignment="Center"
                            VerticalAlignment="Center"/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

이 스타일을 적용하면 ButtonEllipse로 표시됩니다.

단추 ControlTemplate 샘플

포커스가 있거나 눌렀을 때 Button이 표시되는 모양은 모두 대체하는 기본 단추 모양의 일부입니다. 따라서 필요에 따라 단추를 눌렀을 때의 모양을 정의에 추가할 수 있습니다. 전체 예제는 Button ControlTemplate 예제를 참조하십시오.

ControlTemplate을 만드는 경우 ControlTemplate 예제를 사용하는 것부터 시작하는 것이 좋습니다. 컨트롤을 구성하는 부분을 실제로 살펴보고 싶다면 테마에 있는 테마 파일을 살펴보거나 Windows SDK(소프트웨어 개발 키트)와 함께 설치되는 응용 프로그램인 XAMLPad의 Show Visual Tree 기능을 사용해 볼 수 있습니다.

ControlTemplate 만들기

계속해서 예제에서 가로로 배열된 둥근 모서리가 있는 ListBox를 정의하는 ControlTemplate을 만들어 보겠습니다. 컨트롤의 ControlTemplate을 대체하기 위해 Template 속성을 새 ControlTemplate으로 설정합니다.

<Style TargetType="ListBox">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ListBox">
        <Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
          <ScrollViewer HorizontalScrollBarVisibility="Auto">
            <StackPanel Orientation="Horizontal"
                       VerticalAlignment="Center"
                       HorizontalAlignment="Center"
                       IsItemsHost="True"/>
          </ScrollViewer>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

이 방식으로 Template 속성을 설정하는 것은 Style을 사용하여 다른 컨트롤 속성을 설정하는 것과 차이가 없습니다. 따라서 StyleTemplate 속성을 설정하는 도구로 사용할 수 있습니다. 즉, ControlTemplate을 설정하는 다른 방법은 컨트롤에서 직접 Template 속성을 설정하는 것입니다. 이 방식을 사용할 경우에는 Resources 섹션에서 ControlTemplate을 만들고 x:Key를 사용하여 지정한 다음 정적 리소스로 사용합니다. 예제를 보려면 Template 속성을 참조하십시오.

위 예제에서 볼 수 있는 것처럼 ControlTemplate 클래스에는 Style 클래스의 TargetType 속성과 유사한 TargetType 속성이 있습니다. 하지만 StyleDataTemplate과 달리 ControlTemplate 개체에는 암시적 키 개념이 없습니다. 즉, TargetType 속성이 특정 형식으로 설정된 독립 실행형 ControlTemplate이 있는 경우 ControlTemplate이 자동으로 해당 형식에 적용되지 않습니다. 또한 템플릿 정의에 ContentPresenter가 들어 있는 경우에는 ControlTemplateTargetType 속성이 필요합니다.

ControlTemplate으로 시험해 보십시오. 예를 들어 StackPanelWrapPanel로 대체하고, ScrollViewerHorizontalScrollBarVisibility 속성을 Disabled로 설정한 다음 ListBox의 Width를 300으로 설정합니다. WrapPanel은 첫 번째 행의 공간이 부족하면 항목을 다음 행에 배치합니다. ScrollViewerHorizontalScrollBarVisibility 속성을 Disabled로 설정하지 않으면 첫 번째 행을 끝까지 스크롤할 수 있으므로 공간이 부족해지지 않습니다. 결과적으로 WrapPanel은 항목을 래핑하지 않습니다.

IsItemsHost 속성

이 예제에서 반드시 필요한 중요한 속성은 IsItemsHost 속성입니다. IsItemsHost 속성은 ItemsControl(항목 목록에서 동작하는 ListBox 같은 컨트롤)의 템플릿에서 생성된 요소가 배치되어야 할 위치를 나타내는 데 사용됩니다. StackPanel에 대한 속성을 true로 설정하는 것은 ListBox에 추가된 항목이 StackPanel로 이동한다는 의미입니다. 이 속성은 Panel 형식에만 사용할 수 있습니다.

ItemsPresenter 및 ContentPresenter

하지만 ControlTemplate에서 패널을 지정하고 해당 패널을 이 방식으로 IsItemsHost로 표시할 경우 ItemsPanelControlTemplate을 사용하지 않는 컨트롤의 사용자에 의해 대체될 수 없습니다. 따라서 템플릿을 사용하지 않고 패널을 바꿀 필요가 없는 경우에만 이 방법을 사용해야 합니다. 또는 ItemsPresenter 요소를 사용하여 항목이 배치되어야 하는 위치를 표시하고 ItemsPanel 속성을 설정하여 ItemsPanelTemplate을 지정해야 합니다. ItemsPanelTemplate 페이지에는 이 작업을 수행하는 방법을 보여 주는 예제가 있습니다. ItemsPresenter를 사용하는 다른 예제를 보려면 TreeView ControlTemplate 예제를 참조하십시오.

Button 같은 ContentControl에 대한 템플릿을 생성하려는 경우 대응되는 요소는 ContentPresenter입니다. 마찬가지로 ControlTemplate의 정의 단원의 예제에서 설명하는 것처럼 ContentControl 형식의 ControlTemplate에 이 요소를 배치하여 콘텐츠 표시 위치를 지정합니다. 다른 예제를 보려면 Label ControlTemplate 예제ListBoxItem ControlTemplate 예제를 참조하십시오.

TemplateBinding

이전 예제에서 주목해야 할 또 하나는 {TemplateBinding ListBox.Background}로 설정된 Background 값입니다. 이것은 단순히 BorderBackgroundListBox에 설정되어 있는 Background 값과 동기화해야 한다는 것을 나타냅니다. TemplateBinding은 Binding과 유사합니다. 실제로 TemplateBinding이 보다 효율적이지만 Binding보다 기능적이지 못합니다. TemplateBinding을 사용하는 것은 Source 속성을 RelativeSource.TemplatedParent로 설정한 Binding을 사용하는 것과 동일합니다.

컨트롤 사용자가 특정 속성 값을 제어할 수 있게 만들려면 ControlTemplate에서 TemplateBinding을 사용합니다. TemplateBinding은 TemplateBindingExtension 클래스로 표현되는 태그 확장입니다.

DataTemplateControlTemplate은 콘텐츠가 개체의 시각화가 된다는 점에서 유사합니다. ListBox ControlTemplate 정의를 사용하면 응용 프로그램이 다음과 같은 모양이 됩니다.

스타일 샘플 스크린 샷

트리거

Style, ControlTemplateDataTemplate 모두 트리거 집합을 포함할 수 있는 Triggers 속성이 있습니다. 트리거는 속성 값이 변경되거나 이벤트가 발생할 때 속성을 설정하거나 애니메이션 같은 동작을 시작합니다.

이 단원에는 다음 하위 단원이 포함되어 있습니다.

  • 속성 트리거
  • EventTrigger 및 Storyboard
  • MultiTriggers, DataTriggers 및 MultiDataTriggers

속성 트리거

트리거를 사용하여 속성을 설정하는 방법을 보여 주기 위해서 ListBoxItem이 선택되지 않은 경우 부분적으로 투명하게 만들어 보겠습니다.

다음 스타일은 ListBoxItemOpacity 값을 0.5로 설정합니다. 하지만 IsSelected 속성이 true가 되면 Opacity가 1.0으로 설정됩니다.

<Style TargetType="ListBoxItem">
  <Setter Property="Opacity" Value="0.5" />
  <Setter Property="MaxHeight" Value="75" />
  <Style.Triggers>
    <Trigger Property="IsSelected" Value="True">
        <Setter Property="Opacity" Value="1.0" />
    </Trigger>


...


  </Style.Triggers>
</Style>

이 예제에서는 Trigger를 사용하여 속성 값을 설정하지만 Trigger 클래스에는 트리거가 작업을 수행할 수 있게 만드는 EnterActionsExitActions 속성도 있습니다.

또한 ListBoxItemMaxHeight 속성을 75로 설정했습니다. 다음 스크린 샷에서는 세 번째 항목이 선택된 항목입니다.

스타일 지정된 ListView

EventTrigger 및 Storyboard

앞에서는 속성 값에 따라 Trigger가 속성 값을 설정하거나 작업을 시작하는 것을 보여 주었습니다. 다른 형식의 트리거는 이벤트 발생을 기반으로 일련의 작업을 시작하는 EventTrigger입니다. 예를 들어 다음 EventTrigger 개체는 마우스 포인터가 ListBoxItem으로 들어가는 시점을 지정하고 MaxHeight 속성은 0.2초 동안 90의 값으로 애니메이션 효과를 적용합니다. 마우스가 항목에서 나가면 속성이 1초 동안 원래 값을 반환합니다. MouseLeave 애니메이션의 To 값을 지정할 필요가 없다는 것에 주의하십시오. 이것은 애니메이션이 원래 값을 추적할 수 있기 때문입니다.

<EventTrigger RoutedEvent="Mouse.MouseEnter">
  <EventTrigger.Actions>
    <BeginStoryboard>
      <Storyboard>
        <DoubleAnimation
          Duration="0:0:0.2"
          Storyboard.TargetProperty="MaxHeight"
          To="90"  />
      </Storyboard>
    </BeginStoryboard>
  </EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
  <EventTrigger.Actions>
    <BeginStoryboard>
      <Storyboard>
        <DoubleAnimation
          Duration="0:0:1"
          Storyboard.TargetProperty="MaxHeight"  />
      </Storyboard>
    </BeginStoryboard>
  </EventTrigger.Actions>
</EventTrigger>

자세한 내용은 Storyboard 개요를 참조하십시오.

다음 스크린 샷에서는 마우스가 세 번째 항목을 가리키고 있습니다.

스타일 샘플 스크린 샷

MultiTriggers, DataTriggers 및 MultiDataTriggers

TriggerEventTrigger뿐만 아니라 다른 종류의 트리거도 있습니다. MultiTrigger를 사용하면 여러 조건을 기준으로 속성 값을 설정할 수 있습니다. 조건 속성이 데이터 바인딩된 경우에는 DataTriggerMultiDataTrigger를 사용합니다.

이 개요에서 설명하는 전체 샘플을 보려면 스타일 및 템플릿 소개 샘플을 참조하십시오.

공유 리소스 및 테마

일반적인 WPF(Windows Presentation Foundation) 응용 프로그램에는 응용 프로그램 전체에 적용되는 여러 개의 UI(사용자 인터페이스)가 있습니다. 이러한 리소스 집합을 응용 프로그램의 테마로 간주할 수 있습니다. WPF(Windows Presentation Foundation)에서는 ResourceDictionary 클래스로 캡슐화된 리소스 사전을 사용하여 UI(사용자 인터페이스) 리소스를 테마로 패키징할 수 있도록 지원합니다.

WPF(Windows Presentation Foundation) 테마는 WPF(Windows Presentation Foundation)가 요소의 시각화를 사용자 지정하기 위해 노출하는 스타일 및 템플릿 메커니즘을 사용하여 정의됩니다.

WPF(Windows Presentation Foundation) 테마 리소스는 포함된 리소스 사전에 저장됩니다. 이러한 리소스 사전은 서명된 어셈블리 내에 포함되어야 하며 동일한 어셈블리에 코드로 포함되거나 side-by-side 어셈블리에 포함될 수 있습니다. WPF(Windows Presentation Foundation) 컨트롤을 포함하는 어셈블리인 PresentationFramework.dll의 경우에는 테마 리소스가 일련의 side-by-side 어셈블리에 있습니다.

테마는 요소의 스타일을 검색할 때 마지막으로 찾는 위치입니다. 일반적으로 이러한 검색은 요소 트리에서 적절한 리소스를 찾는 것에서 시작해 응용 프로그램 리소스 컬렉션을 찾은 다음 마지막으로 시스템을 쿼리합니다. 따라서 검색이 테마에 도달하기 전에 응용 프로그램 작성자가 트리나 응용 프로그램 수준에서 개체의 스타일을 다시 정의할 수 있습니다.

리소스 사전을 별도의 파일로 정의하여 여러 응용 프로그램에서 테마를 재사용할 수 있습니다. 또한 동일한 형식의 리소스를 제공하지만 값이 다른 여러 개의 리소스 사전을 정의하여 스왑 가능한 테마를 만들 수도 있습니다. 응용 프로그램 수준에서 이러한 스타일이나 기타 리소스를 다시 정의하는 것이 응용 프로그램에 스킨을 제공하는 방식으로 권장됩니다.

응용 프로그램 간에 스타일과 템플릿을 비롯한 리소스 집합을 공유하려면 XAML 파일을 만들고 ResourceDictionary를 정의할 수 있습니다. 예를 들어 ControlTemplates를 사용한 스타일 지정 샘플의 일부분을 보여 주는 다음 스크린 샷을 살펴보십시오.

Control Template 예제

샘플의 XAML 파일을 보면 모든 파일에 다음 항목이 있다는 것을 알 수 있습니다.

<ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>

이것은 샘플의 컨트롤이 일관성 있는 모양을 가지도록 스타일 및 브러시 리소스 집합을 포함하는 ResourceDictionary를 정의하는 shared.xaml을 공유하는 것입니다.

자세한 내용은 병합된 리소스 사전을 참조하십시오.

사용자 지정 컨트롤에 대한 테마를 만드는 경우에는 컨트롤 제작 개요에서 외부 컨트롤 라이브러리 단원을 참조하십시오.

참고 항목

작업

방법: ControlTemplate에서 생성된 요소 찾기

방법: DataTemplate에서 생성된 요소 찾기

사진 저장소 데모

개념

Windows Presentation Foundation의 Pack URI

기타 리소스

테마