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

TextBox

(ㅇㅅㅎ) 2022. 6. 21. 11:19
728x90
반응형

 

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

 

 

 

TextBox

 서식 없는 텍스트를 표시하거나 편집하는 데 사용할 수 있는 Control을 나타냅니다. TextBox는 형식이 지정되지 않은 텍스트만을 지원합니다. 다양한 형식이 지정되는 텍스트의 경우 RischTextBox를 사용하여야 합니다. 예제의 XAML 코드를 TexBox에 적용하면 위와 같은 결과가 나옵니다. 이러한 결과에 도달하도록 코드 순서로 속성을 살펴보면 다음과 같습니다.

 

 

TextBox 속성

<Style TargetType="{x:Type TextBox}">
  <Setter Property="SnapsToDevicePixels" Value="True" />
  <Setter Property="OverridesDefaultStyle" Value="True" />
  <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
  <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  <Setter Property="MinWidth" Value="120" />
  <Setter Property="MinHeight" Value="20" />
  <Setter Property="AllowDrop" Value="true" />
  <Setter Property="Template">
    <Setter.Value>
      ...
    </Setter.Value>
  </Setter>
</Style>

TargetTye

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

 

 

SnapsToDevicePixels

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

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

더보기

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


 

 

OverridesDefaultStyle

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

 

 

KeyboardNavigation.TabNavigation

 자식 요소에 대한 논리적 탭 탐색 동작을 설정합니다. 값으로는 Contained, Continue, Cycle, Local, None과 Once가 있습니다.

👀 값에 대한 자세한 설명은 이 페이지를 참고하시면 됩니다.

 

 

FocusVisualStyle

 키보드 focus를 캡처할 때 TextBox에 적용되는 모양, 효과 또는 기타 스타일 특성을 사용자가 지정할 수 있는 속성을 설정합니다. 예제에서는 Null 값으로 설정했습니다.

 

 

MinWidth

 TextBox의 최소 너비를 설정합니다.

 

 

MinHeight

 TextBox의 최소 높이를 설정합니다.

 

 

AllowDrop

 TextBox를 끌어서 놓기 작업의 대상으로 사용할 수 있는지 여부를 설정합니다. 끌어서 놓기 작업의 대상으로 사용할 수 있으면 true이고 그렇지 않으면 false입니다.

 

 

Template

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type TextBoxBase}">
            <Border Name="Border" ... >
                ...
                <VisualStateManager.VisualStateGroups> ... </VisualStateManager.VisualStateGroups>
                <ScrollViewer x:Name="PART_ContentHost" />
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

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

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

 

 

TextBox Template 구성

 TextBox는 Border와 ScrollViewer로 구성되어있습니다.

Border

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

⭐ Border 속성

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

 

Name

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

 

CornerRadius

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

 

Padding

 윤곽선과 자식 요소 사이의 간격을 설정합니다.

 

BorderThickness

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

 

Background

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

 

BorderBrush

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


 

ScrollViewer

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

⭐ ScrollViewer 속성

더보기
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />

 

Margin

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

 

x:Name

 ScrollViewer에 이름을 설정합니다. 이름을 설정하는 것과 동시에 다른 곳에서 사용할 수 있도록 만들어줍니다. 예제에서는 TextBox Control의 명명된 부분인 PART_ContentHost로 설정했습니다.

🌟 PART_ContentHost : FrameworkElement를 포함할 수 있는 시각적 개체 요소입니다. 이 요소에 TextBox의 텍스트가 표시됩니다.


 

 

TextBox 이벤트

 예제에서는 이벤트로 Disabled와 ReadOnly변화를 VisualStateManager로 표현하였습니다.

 

VisualStateManager

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="CommonStates">
        ...
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

 VisualState는 Control의 시각적 상태를 나타냅니다. 예제의 이벤트에서 시각적 변화를 주기 위해서 VisualStateGroup의 x:Name을 CommonStates로 설정했습니다.

CommonStates

더보기
<VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Normal" />
    <VisualState x:Name="Disabled">
        <Storyboard>
            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                <EasingColorKeyFrame KeyTime="0" Value="{StaticResource DisabledControlLightColor}" />
            </ColorAnimationUsingKeyFrames>
        </Storyboard>
    </VisualState>
    <VisualState x:Name="ReadOnly">
        <Storyboard>
            <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                <EasingColorKeyFrame KeyTime="0" Value="{StaticResource DisabledControlDarkColor}" />
            </ColorAnimationUsingKeyFrames>
        </Storyboard>
    </VisualState>
    <VisualState x:Name="MouseOver" />
</VisualStateGroup>

 

Disabled & ReadOnly

 Disabled와 ReadOnly의 Storyboard 내용을 풀어보면 ["Border"의 Background 값을 변경하는 것]입니다.

 

ColorAnimationUsingKeyFrames

 KeyFrames 집합을 따라 Color 속성 값에 EasingColorKeyFrame의 애니메이션 효과를 줍니다.


 

 

 


 

 

 

전체 코드

더보기
<Style TargetType="{x:Type TextBox}">
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="OverridesDefaultStyle"
          Value="True" />
  <Setter Property="KeyboardNavigation.TabNavigation"
          Value="None" />
  <Setter Property="FocusVisualStyle"
          Value="{x:Null}" />
  <Setter Property="MinWidth"
          Value="120" />
  <Setter Property="MinHeight"
          Value="20" />
  <Setter Property="AllowDrop"
          Value="true" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type TextBoxBase}">
        <Border Name="Border"
                CornerRadius="2"
                Padding="2"
                BorderThickness="1">
          <Border.Background>
            <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
          </Border.Background>
          <Border.BorderBrush>
            <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
          </Border.BorderBrush>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal" />
              <VisualState x:Name="Disabled">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource DisabledControlLightColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="ReadOnly">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                    (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource DisabledControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="MouseOver" />
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <ScrollViewer Margin="0"
                        x:Name="PART_ContentHost" />
        </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/textbox-styles-and-templates?view=netframeworkdesktop-4.8 

 

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

WPF(Windows Presentation Foundation) TextBox 컨트롤의 스타일 및 템플릿에 대해 알아봅니다. 컨트롤에 고유한 모양을 제공하도록 ControlTemplate을 수정합니다.

docs.microsoft.com

 

반응형

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

ToggleButton  (0) 2022.06.22
Thumb  (0) 2022.06.21
TabControl  (0) 2022.06.20
StatusBar  (0) 2022.06.19
Slider  (0) 2022.06.18