프로그램 개발/WPF: Style&Template

ListBox

(ㅇㅅㅎ) 2022. 5. 30. 14:51
728x90
반응형

 

 안녕하세요, 이번 글에서는 Microsoft에서 제공하는 WPF [ListBox의 스타일 및 템플릿] 예제를 톺아보겠습니다.

ListBox Style의 경우 ListBoxListBoxItem으로 나눠져 있습니다. 이번 글에서는 ListBox에 대해서 보도록 하겠습니다.

 

 

 

ListBox 

 선택 가능한 항목 목록이 포함됩니다.

 

 

 

[ ListBox 속성 ]

SelectionMode

 ListBox에 대한 선택 동작을 설정합니다. 기본값은 Single이며 다른 값으로 Extended와 Multiple이 있습니다.

⭐ SelectionMode 값

  • Extended : 사용자가 Shift 키를 누른 상태로 연속적으로 항목을 선택할 수 있다.
  • Multiple : 사용자가 한정자 키를 누르지 않고도 여러 항목을 선택할 수 있다.
  • Single : 사용자가 항목을 한 번에 하나만 선택할 수 있다.
<ListBox SelectionMode="Multiple" ... />

SelectionMode

 

 


 

 

 

[ ListBox Style ]

 예제의 XAML 코드를 ListBox에 적용하면 위와 같은 결과가 나옵니다. 이러한 결과에 도달하도록 코드 순서로 속성을 살펴보면 다음과 같습니다.

⭐ 기본 ListBox와 비슷해 보이지만 자세히 보면 모서리 부분과 이벤트 부분 등이 다릅니다.

 

 

 

ListBox 속성

<Style x:Key="{x:Type ListBox}" TargetType="ListBox">
  <Setter Property="SnapsToDevicePixels" Value="true" />
  <Setter Property="OverridesDefaultStyle" Value="true" />
  <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
  <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
  <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
  <Setter Property="MinWidth" Value="120" />
  <Setter Property="MinHeight" Value="95" />
  <Setter Property="Template">
    <Setter.Value>
      ...
    </Setter.Value>
  </Setter>
</Style>

x:Key

 XAML 정의 사전에서 만들고 참고하는 요소를 고유하게 식별합니다.

 

 

TargetType

 이 Style을 적용할 형식을 설정합니다.

 

 

SnapsToDevicePixels

 렌더링 하는 동안 ContentPresenter의 렌더링에 디바이스 관련 픽셀 스냅(Pixel Snap)을 사용할지 여부를 설정합니다. 픽셀 스냅을 사용하면 값을 true로 설정하고, 그렇지 않으면 false(기본값)로 설정합니다.

⭐ 픽셀 스냅(Pixel Snap)을 사용하는 이유

더보기

 WPF는 시스템 DPI 설정에 맞게 자동으로 크기를 조정하게 됩니다. 조정할 때 가장자리가 흐려지거나 반투명하게 표시되는 문제가 발생합니다. 이 문제를 해결하기 위해서 픽셀 스냅 기능을 사용하여 객체의 가장자리를 픽셀에 맞추어 고정시키는 기능을 제공합니다. 픽셀 스냅을 사용하면 객체에 작은 단위의 offset을 적용하여 객체의 크기를 장치 픽셀에 맞추거나 일부분을 렌더링 시점에서 제거하여 해결하는 방법입니다.


 

 

OverridesDefaultStyle

 테마 스타일의 스타일 속성을 포함할지 여부를 설정합니다. 테마 스타일 속성을 사용하지 않으면 true이고, 사용하면 false(기본값)입니다.

 

 

ScrollViewer.HorizontalScrollBarVisibility

 가로 ScrollBar를 표시해야 하는지 여부를 설정합니다. 기본값은 Hidden이고 다른 값으로는 Auto, Disabled, Visibile이 있습니다.

 

 

ScrollViewer.VerticalScrollBarVisibility

 세로 ScrollBar를 표시해야 하는지 여부를 설정합니다. 기본값은 Visible이고 다른 값으로는 Auto, Disabled, Hidden이 있습니다.

 

 

ScrollViewer.CanContentScroll

 IScrollInfo 인터페이스를 지원하는 요소를 스크롤할 수 있는지 여부를 설정합니다. ScrollViewer가 논리 단위의 측면에서 스크롤되는 경우 true이고 물리적 단위 측면에서 스크롤되는 경우 false입니다.

 

 

MinWidth

 최소 너비를 설정합니다.

 

 

MinHeight

 최소 높이를 설정합니다.

 

 

Template

<Setter Property="Template">
  <Setter.Value>
    <ControlTemplate TargetType="ListBox">
      <Border Name="Border" ... >
        ...
        <ScrollViewer ... >
          <StackPanel ... />
        </ScrollViewer>
      </Border>
      <ControlTemplate.Triggers>
        ...
      </ControlTemplate.Triggers>
    </ControlTemplate>
  </Setter.Value>
</Setter>

 Control의 템플릿을 설정합니다. 예제에서 사용되는 Template는 Control의 외형을 지정해줄 수 있는 ControlTemplate입니다.

👀 Template에 대해서 좀 더 아시고 싶으신 분은 이 페이지를 참고하시길 바랍니다.

 

 

 

ListBox Style 구성

 ListBox Style은 ScrollViewer를 사용하여 StackPanel를 감싼 형태로 구성되어있습니다. ListBoxItem은 StackPanel에서 구성됩니다.

 

Border(Border)

 다른 요소의 주위에 윤곽선, 배경 또는 둘 다를 그립니다.

Border 속성

더보기
<Border Name="Border" BorderThickness="1" CornerRadius="2">
  <Border.Background>
    <SolidColorBrush Color="{StaticResource ControlLightColor}" />
  </Border.Background>
  <Border.BorderBrush>
    <SolidColorBrush Color="{StaticResource BorderMediumColor}" />
  </Border.BorderBrush>
  ...
</Border>

 

Name

 Border에 이름을 설정합니다. 이름을 붙이는 것과 동시에 다른 곳에서 사용할 수 있도록 만들어줍니다.

 

BorderThickness

 Border의 윤곽선 두께를 설정합니다.

 

CornerRadius

 Border의 모서리의 둥근 정도를 설정합니다.

 

Background

 Border의 배경색을 설정합니다. 예제에서는 SolidColorBrush를 사용하여 미리 정의한 ControlLightColor로 설정했습니다.

 

BorderBrush

 Border의 윤곽선 색을 설정합니다. 예제에서는 SolidColorBrush를 사용하여 미리 정의한 BorderMediumColor로 설정했습니다.


 

ScrollViewer

 표시 가능한 다른 요소를 포함할 수 있는 Scroll 가능한 영역을 나타냅니다.

ScrollViewer 속성

더보기
<ScrollViewer Margin="0" Focusable="false">
  ...
</ScrollViewer>

 

Margin

 ScrollViewer의 외부 여백을 설정합니다.

 

Focusable

 ScrollViwer가 focus를 받을 수 있는지 여부를 설정합니다. focus를 받을 수 있으면 true이고, 그렇지 않으면 false입니다.


 

StackPanel

 가로 또는 세로 방향으로 한 줄로 자식 요소를 정렬합니다.

StackPanel 속성

더보기
<StackPanel Margin="2" IsItemsHost="True" />

 

Margin

 StackPanel의 외부 여백을 설정합니다.

 

IsItemsHost

 ItemsControl에 의해 생성된 UI(사용자 인터페이스) 항목에 대한 컨테이너임을 나타내는 Panel 값을 설정합니다.

항목 호스트이면 true이고, 그렇지 않으면 false(기본값)입니다. 예제의 경우 ListBoxItem이 항목 호스트이므로 true로 설정했습니다.


 

 

ListBox 이벤트

 예제에서는 IsEnabled와 IsGrouping의 상태 변화를 Trigger로 표현했습니다.

 

Triggers

<ControlTemplate.Triggers>
  <Trigger Property="IsEnabled" Value="false">
    <Setter TargetName="Border" Property="Background">
      <Setter.Value>
        <SolidColorBrush Color="{StaticResource DisabledControlLightColor}" />
      </Setter.Value>
    </Setter>
    <Setter TargetName="Border" Property="BorderBrush">
      <Setter.Value>
        <SolidColorBrush Color="{DynamicResource DisabledBorderLightColor}" />
      </Setter.Value>
    </Setter>
  </Trigger>
  <Trigger Property="IsGrouping" Value="true">
    <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
  </Trigger>
</ControlTemplate.Triggers>

 Trigger는 어떤 조건이나 이벤트 등이 주어졌을 때 Control의 상태 또는 이벤트 핸들러 등을 호출하는 기능을 의미합니다. 예제에서는 다음과 같이 사용됩니다.

  • IsEnabled의 값이 false일 때 "Border"의 Background 값을 DisabledControlLightColor로 변경하고 BorderBrush 값을 DisabledBorderLightColor로 변경합니다.
  • IsGrouping의 값이 true일 때 ScrollViewer.CanContentScroll 값을 false로 변경합니다.

 

 


 

 

전체 코드

더보기
<Style x:Key="{x:Type ListBox}"
       TargetType="ListBox">
  <Setter Property="SnapsToDevicePixels"
          Value="true" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
          Value="Auto" />
  <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
          Value="Auto" />
  <Setter Property="ScrollViewer.CanContentScroll"
          Value="true" />
  <Setter Property="MinWidth"
          Value="120" />
  <Setter Property="MinHeight"
          Value="95" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ListBox">
        <Border Name="Border"
                BorderThickness="1"
                CornerRadius="2">
          <Border.Background>
            <SolidColorBrush Color="{StaticResource ControlLightColor}" />
          </Border.Background>
          <Border.BorderBrush>
            <SolidColorBrush Color="{StaticResource BorderMediumColor}" />
          </Border.BorderBrush>
          <ScrollViewer Margin="0"
                        Focusable="false">
            <StackPanel Margin="2"
                        IsItemsHost="True" />
          </ScrollViewer>
        </Border>
        <ControlTemplate.Triggers>
          <Trigger Property="IsEnabled"
                   Value="false">
            <Setter TargetName="Border"
                    Property="Background">
              <Setter.Value>
                <SolidColorBrush Color="{StaticResource DisabledControlLightColor}" />
              </Setter.Value>
            </Setter>
            <Setter TargetName="Border"
                    Property="BorderBrush">
              <Setter.Value>
                <SolidColorBrush Color="{DynamicResource DisabledBorderLightColor}" />
              </Setter.Value>

            </Setter>
          </Trigger>
          <Trigger Property="IsGrouping"
                   Value="true">
            <Setter Property="ScrollViewer.CanContentScroll"
                    Value="false" />
          </Trigger>
        </ControlTemplate.Triggers>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<Style x:Key="{x:Type ListBoxItem}"
       TargetType="ListBoxItem">
  <Setter Property="SnapsToDevicePixels"
          Value="true" />
  <Setter Property="OverridesDefaultStyle"
          Value="true" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ListBoxItem">
        <Border x:Name="Border"
                Padding="2"
                SnapsToDevicePixels="true">
          <Border.Background>
            <SolidColorBrush Color="Transparent" />
          </Border.Background>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="SelectionStates">
              <VisualState x:Name="Unselected" />
              <VisualState x:Name="Selected">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedBackgroundColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="SelectedUnfocused">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource SelectedUnfocusedColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <ContentPresenter />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<!--Control colors.-->
<Color x:Key="WindowColor">#FFE8EDF9</Color>
<Color x:Key="ContentAreaColorLight">#FFC5CBF9</Color>
<Color x:Key="ContentAreaColorDark">#FF7381F9</Color>

<Color x:Key="DisabledControlLightColor">#FFE8EDF9</Color>
<Color x:Key="DisabledControlDarkColor">#FFC5CBF9</Color>
<Color x:Key="DisabledForegroundColor">#FF888888</Color>

<Color x:Key="SelectedBackgroundColor">#FFC5CBF9</Color>
<Color x:Key="SelectedUnfocusedColor">#FFDDDDDD</Color>

<Color x:Key="ControlLightColor">White</Color>
<Color x:Key="ControlMediumColor">#FF7381F9</Color>
<Color x:Key="ControlDarkColor">#FF211AA9</Color>

<Color x:Key="ControlMouseOverColor">#FF3843C4</Color>
<Color x:Key="ControlPressedColor">#FF211AA9</Color>


<Color x:Key="GlyphColor">#FF444444</Color>
<Color x:Key="GlyphMouseOver">sc#1, 0.004391443, 0.002428215, 0.242281124</Color>

<!--Border colors-->
<Color x:Key="BorderLightColor">#FFCCCCCC</Color>
<Color x:Key="BorderMediumColor">#FF888888</Color>
<Color x:Key="BorderDarkColor">#FF444444</Color>

<Color x:Key="PressedBorderLightColor">#FF888888</Color>
<Color x:Key="PressedBorderDarkColor">#FF444444</Color>

<Color x:Key="DisabledBorderLightColor">#FFAAAAAA</Color>
<Color x:Key="DisabledBorderDarkColor">#FF888888</Color>

<Color x:Key="DefaultBorderBrushDarkColor">Black</Color>

<!--Control-specific resources.-->
<Color x:Key="HeaderTopColor">#FFC5CBF9</Color>
<Color x:Key="DatagridCurrentCellBorderColor">Black</Color>
<Color x:Key="SliderTrackDarkColor">#FFC5CBF9</Color>

<Color x:Key="NavButtonFrameColor">#FF3843C4</Color>

<LinearGradientBrush x:Key="MenuPopupBrush"
                     EndPoint="0.5,1"
                     StartPoint="0.5,0">
  <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="0" />
  <GradientStop Color="{DynamicResource ControlMediumColor}"
                Offset="0.5" />
  <GradientStop Color="{DynamicResource ControlLightColor}"
                Offset="1" />
</LinearGradientBrush>

<LinearGradientBrush x:Key="ProgressBarIndicatorAnimatedFill"
                     StartPoint="0,0"
                     EndPoint="1,0">
  <LinearGradientBrush.GradientStops>
    <GradientStopCollection>
      <GradientStop Color="#000000FF"
                    Offset="0" />
      <GradientStop Color="#600000FF"
                    Offset="0.4" />
      <GradientStop Color="#600000FF"
                    Offset="0.6" />
      <GradientStop Color="#000000FF"
                    Offset="1" />
    </GradientStopCollection>
  </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

 

 


 

 

이 글의 내용은 아래의 사이트에서 기초합니다.

https://docs.microsoft.com/ko-kr/dotnet/desktop/wpf/controls/listbox-styles-and-templates?view=netframeworkdesktop-4.8 

 

ListBox 스타일 및 템플릿 - WPF .NET Framework

ListBox 스타일 및 템플릿 아티클 05/08/2022 읽는 데 4분 걸림 기여자 1명 이 문서의 내용 --> 이 항목에서는 ListBox 컨트롤에 대한 스타일 및 템플릿을 설명합니다. 기본값을 수정할 수 있습니다 ControlT

docs.microsoft.com

 

반응형

'프로그램 개발 > WPF: Style&Template' 카테고리의 다른 글

ListView①  (0) 2022.05.31
ListBoxItem  (0) 2022.05.30
Label  (0) 2022.05.28
GroupBox  (0) 2022.05.28
Frame④  (0) 2022.05.27