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

DataGrid①

(ㅇㅅㅎ) 2022. 5. 13. 10:57
728x90
반응형

 

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

⭐ [Microsoft Control Style & Template 톺아보기 - DataGrid] 편은 총 4편(DataGrid, Button/DataGridColumnHeadersPresenterDataGridColumnHeader/DataGridRowHeaderDataGridRow/DataGridCell)으로 구성되어있습니다.

 

 

DataGrid

 사용자 지정 가능한 표의 데이터를 표시하는 Control을 나타냅니다. DataGrid는 행과 열에 Data Collection을 표시하는 Control입니다.

 

 

 

[ DataGrid 속성 ]

AlternatingRowBackground

 교대로 반복되는 행에 사용할 배경 브러시를 설정합니다.

<DataGrid AlternatingRowBackground="LavenderBlush" />

AlternatingRowBackground

 

 

CanUserAddRows

 사용자가 DataGrid에 새 행을 추가할 수 있는지 여부를 설정합니다. 사용자가 새 행을 추가할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다.

<DataGrid CanUserAddRows="False" />

CanUserAddRows

 

 

CanUserDeleteRows

 사용자가 DataGrid에서 행을 삭제할 수 있는지 여부를 설정합니다. 사용자가 행을 삭제할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다. 키보드의 Delete 키로 삭제 가능합니다.

 

 

CanUserReorderColumns

 사용자가 마우스로 열 헤더를 끌어 열 표시 순서를 변경할 수 있는지 여부를 설정합니다. 사용자가 열을 다시 정렬할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다.

CanUserReorderColumns

 

 

CanUserResizeColumns

 사용자가 마우스를 사용하여 열 너비를 조정할 수 있는지 여부를 설정합니다. 사용자가 열 너비를 조정할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다.

CanUserResizeColumns

 

 

CanUserResizeRows

 사용자가 마우스를 사용하여 행 높이를 조정할 수 있는지 여부를 설정합니다. 사용자가 행 높이를 조정할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다.

CanUserResizeRows

 

 

CanUserSortColumns

 사용자가 열 헤더를 클릭하여 열을 정렬할 수 있는지 여부를 설정합니다. 사용자가 열을 정렬할 수 있으면 true(기본값)이고, 그렇지 않으면 false입니다.

CanUserSortColumns

 

 

CellStyle

 DataGrid에 있는 모든 셀에 적용된 스타일을 설정합니다.

👀 예제에서 사용된 CellStyle은  편에서 다룹니다.

 

 

ColumnHeaderHeight

 열 머리글 행의 높이를 설정합니다. 열 머리글의 크기가 콘텐츠에 맞게 자동으로 조정되도록 하려면 NaN(기본값)으로 설정합니다.

<DataGrid ColumnHeaderHeight="50" />

ColumnHeaderHeight

 

 

ColumnHeaderStyle

 DataGrid에 있는 모든 열 머리글에 적용할 스타일을 설정합니다.

👀 예제에서 사용된 ColumnHeaderStyle은 편에서 다룹니다.

 

 

ColumnWidth

 DataGrid에 있는 열 및 머리글의 표준 너비 또는 크기 조정 모드를 설정합니다. 

<DataGrid ColumnWidth="100" />

ColumnWidth

 

 

FrozenColumnCount

 스크롤되지 않는 열의 수를 설정합니다.

<DataGrid FrozenColumnCount="1" />

FrozenColumnCount

 

 

GridLinesVisibility

 모눈선 중 표시되는 모눈선을 나타내는 값을 설정합니다. 기본값은 All이며, 다른 값으로 Horizontal, None, Vertical이 있습니다.

<DataGrid GridLinesVisibility="Horizontal" />

GridLinesVisibility

 

 

HeadersVisibility

 행 머리글과 열 머리글의 표시 여부를 설정합니다. 기본값은 All이며, 다른 값으로 Column, None, Row가 있습니다.

<DataGrid HeadersVisibility="None" />

 

 

HorizontalGridLinesBrush

 가로 모눈선을 그리는 데 사용되는 브러시를 설정합니다.

<DataGrid HorizontalGridLinesBrush="Red" />

HorizontalGridLInesBrush

 

 

HorizontalScrollBarVisibility

 DataGrid에서 가로 스크롤 막대가 표시되는 방법을 설정합니다. 기본값은 Auto이며,  다른 값으로 Disabled, Hidden, Visible이 있습니다.

<DataGrid HorizontalScrollBarVisibility="Visible" />

HorizontalScrollBarVisibility

 

 

IsReadOnly

DataGrid에서 사용자가 값을 편집할 수 있는지 여부를 설정합니다. 행과 셀이 읽기 전용인 경우 true이고, 그렇지 않으면 false(기본값)입니다.

<DataGrid IsReadOnly="True" />

IsReadOnly

 

 

RowHeaderStyle

 모든 행 머리글에 적용되는 스타일을 설정합니다.

👀 예제에서 사용된 RowHeaderStyle은 편에서 다룹니다.

 

 

RowHeaderWidth

 행 헤더 열의 너비를 설정합니다.

<DataGrid RowHeaderWidth="30" />

RowHeaderWidth

 

 

RowHeight

 모든 행의 높이를 설정합니다.

<DataGrid RowHeight="30" />

RowHeight

 

 

RowStyle

 모든 행에 적용되는 스타일을 설정합니다.

👀 예제에서 사용된 RowStyle은 편에서 다룹니다.

 

 

SelectionMode

 DataGrid에서 열과 셀을 선택하는 방법을 설정합니다. 기본값은 Extended이며, 다른 값으로 Single이 있습니다. Extended 모드에서 셀을 선택한 뒤 Control이나 Shift를 사용하여 다중 선택 가능합니다.

SelectionMode

 

 

SelectionUnit

 DataGrid에서 행, 셀 또는 둘 다를 선택할 수 있는지 여부를 설정합니다. 기본값은 FullRow이며, 다른 값으로 Cell, CellOrRowHeader가 있습니다.

<DataGrid SelectionUnit="Cell" />

SelectionUnit

 

 

VerticalGridLinesBrush

 세로 모눈선을 그리는 데 사용되는 브러시를 설정합니다.

<DataGrid VerticalGridLinesBrush="Red" />

VerticalGridLinesBrush

 

 

VerticalScrollBarVisibility

 DataGrid에서 세로 스크롤 막대가 표시되는 방법을 설정합니다. 기본값은 Auto이며, 다른 값으로 Disabled, Hidden, Visible이 있습니다.

<DataGrid VerticalScrollBarVisibility="Visible" />

VerticalScrollBarVisibility

 

 


 

 

[ DataGrid Style ]

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

 

 

DataGrid 속성

<Style TargetType="{x:Type DataGrid}">
  <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
  <Setter Property="BorderBrush">
    <Setter.Value>
      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
        <GradientStop Color="{DynamicResource BorderLightColor}" Offset="0" />
        <GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1" />
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
  <Setter Property="BorderThickness" Value="1" />
  <Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
  <Setter Property="ScrollViewer.CanContentScroll" Value="true" />
  <Setter Property="ScrollViewer.PanningMode" Value="Both" />
  <Setter Property="Stylus.IsFlicksEnabled" Value="False" />
  <Setter Property="Template">
    <Setter.Value>
      ...
    </Setter.Value>
  </Setter>
  
  <Style.Triggers>
    ...
  </Style.Triggers>
</Style>

Foreground

 DataGrid 내부의 글자 색을 설정합니다. 예제에서는 SystemColors에 미리 정의되어 있는 ControlTextBrushKey 색을 설정하였습니다.

 

 

BorderBrush

 DataGrid의 윤곽선 색을 설정합니다. 예제에서는 LinearGradientBrush를 사용하여 그라데이션 색을 설정하였습니다.

⭐ 그라데이션 색에 관해서 궁금하신 분은 이 페이지를 참고하시기 바랍니다.

 

 

BorderThickness

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

 

 

RowDetailsVisibilityMode

 행의 세부 정보 섹션이 표시될 때를 나타내는 값을 가져오거나 설정합니다. 값으로는 Collapsed, Visible, VisibleWhenSelected가 있습니다.

 

 

ScrollViewer.CanContentScroll

 IScrollInfo(스크롤이 가능한 ScrollViewer Control 내의 주 영역) 인터페이스를 지원하는 요소를 스크롤할 수 있는지 여부를 설정합니다. ScrollViewer가 논리 단위의 측면에서 스크롤되는 경우 true이고 ScrollViewer이 물리적 단위 측면에서 스크롤되는 경우 false(기본값)입니다.

⭐ ScrollViewer의 기본 동작은 물리적 단위를 사용하여 콘텐츠를 스크롤하는 것입니다. 예를 들어 ItemsControl이 상속되는 ListBox나 ListView 같은 Control이 있습니다. 이 경우 실제 단위가 아닌 항목의 수를 사용해야 하므로 CanContentScroll을 true로 설정해야 합니다.

 

 

ScrollViewer.PanningMode

 ScrollViewer가 터치식 조작에 반응하는 방식을 설정합니다. 기본값은 None이며, 다른 값으로는 Both(가로/세로 스크롤), HorizontalFirst(가로 먼저 스크롤), HorizontalOnly(가로 스크롤), VerticalFirst(세로 먼저 스크롤)와 VerticalOnly(세로 스크롤)가 있습니다. 이 값에 대한 자세한 설명은 이 페이지를 참조하시길 바랍니다.

 

 

Stylus.IsFlicksEnabled

 flick(긋기)이 사용되는지 여부를 설정합니다. 사용할 경우 true이고 그렇지 사용하지 않을 경우 false입니다.

⭐ Flick(긋기)란?

더보기

 Windows Vista에서 가능한 시스템 제스처 중 하나인 flick(긋기)은 탐색 또는 바로가기 명령에 매핑할 수 있는 짧고 빠른 직선 스트로크입니다. 기본적으로 ScrollBar 및 InkCanvasInkPresenter에서 사용하지 않도록 설정됩니다. 그리고 다른 모든 Control에서 flick을 사용할 수 있습니다.


 

 


 

 

[ DataGrid Style : Template ]

<Setter Property="Template">
  <Setter.Value>
    <ControlTemplate TargetType="{x:Type DataGrid}">
      <Border x:Name="border" SnapsToDevicePixels="True" BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
        <Border.Background>
          <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
        </Border.Background>
        
        <VisualStateManager.VisualStateGroups>
          ...
        </VisualStateManager.VisualStateGroups>
        
        <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false" Background="Black">
          ... 
          <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
        </ScrollViewer>
      </Border>
    </ControlTemplate>
  </Setter.Value>
</Setter>

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

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

 

 

DataGrid 구성

 예제의 Template에서 구성한 DataGrid는 위의 이미지와 같이 Border가 StackPanel을 감싸는 형태로 구성되어있습니다.

 

Border(Border)

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

Border 속성

더보기

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

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

BorderBrush
 Border의 윤곽선 색을 설정합니다. 예제에서는 TemplateBinding을 사용하여 DataGrid의 BorderBrush 색으로 설정했습니다.

BorderThickness
 Border의 윤곽선 두께를 설정합니다. 예제에서는 TemplateBinding을 사용하여 DataGrid의 BorderThickness 값으로 설정했습니다.

Padding
 Border의 윤곽선 두께와 자식 요소 사이의 간격을 설정합니다.

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


 

ScrollViewer(DG_ScrollViewer)

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

ScrollViewer 속성

더보기

x:Name
 ScrollViewer에 이름을 붙입니다. 이름을 붙이는 것과 동시에 다른 곳에서 사용할 수 있도록 만들어줍니다.

Focusable
 ScrollViewer가 포커스를 받을 수 있는지 여부를 설정합니다. 포커스를 받을 수 있으면 true이고, 포커스를 받을 수 없으면 false(기본값)입니다.

Background
 ScrollViewer에 배경색을 설정합니다.


 

ScrollViewer Template

<ScrollViewer.Template>
  <ControlTemplate TargetType="{x:Type ScrollViewer}">
    <Grid>
      ...
      <Button ... />
      <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter" ... />
      <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" ... />
      <ScrollBar x:Name="PART_VerticalScrollBar" ... />
      <Grid Grid.Column="1" Grid.Row="2">
        ...
        <ScrollBar x:Name="PART_HorizontalScrollBar" ... />
      </Grid>
    </Grid>
  </ControlTemplate>
</ScrollViewer.Template>

Grid

 열 및 행으로 구성되는 유연한 모눈 영역을 정의합니다.

👀 Grid 속성

더보기
<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  ...
</Grid>

ColumnDefinitions
 Grid에 ColumnDefinition을 사용하여 ColumnDefinitionCollection(ColumnDefinition 개체의 순서가 지정된 컬렉션)을 설정합니다.

ColumnDefinition
 Grid 요소에 적용되는 열 별 속성을 정의합니다. Width로 너비를 숫자 값, Auto 또는 '*'(기본값)로 설정할 수 있습니다. 숫자 값은 그 숫자의 픽셀 값이 고정되고 Auto는 Content 개체의 크기 속성에 따라 값을 결정합니다. 그리고 '*'은 가중치에 따른 여유 공간을 비율에 따라서 값을 결정합니다.

RowDefinitions
 Grid에 RowDefinition을 사용하여 RowDefinitionCollection(RowDefinition 개체의 순서가 지정된 컬렉션)을 설정합니다.

RowDefinition
 Grid 요소에 적용되는 행별 속성을 정의합니다. Height로 높이를 숫자 값, Auto 또는 '*'(기본값)로 설정할 수 있습니다. 숫자 값은 그 숫자의 픽셀 값이 고정되고 Auto는 Content 개체의 크기 속성에 따라 값을 결정합니다. 그리고 '*'은 가중치에 따른 여유 공간을 비율에 따라서 값을 결정합니다.


 

Button

 Click 이벤트에 반응하는 Windows 단추 Control입니다. 예제에서는 모든 셀을 선택하는 기능을 합니다.

👀 Button 속성

더보기
<Button Focusable="false"
      Command="{x:Static DataGrid.SelectAllCommand}"
      Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}}"
      Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
      Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />

Focusable

 Button이 포커스를 받을 수 있는지 여부를 설정합니다. 포커스를 받을 수 있으면 true이고, 포커스를 받을 수 없으면 false(기본값)입니다.

 

Command

 Button을 누를 때 호출할 명령을 설정합니다. 예제에서는 DataGrid.SelectAllCommand는 DataGrid의 모든 셀을 선택하려고 함을 나타내는 명령을 나타냅니다.

 

Style

 렌더링 될 때 이 요소에서 사용할 스타일을 설정합니다. 예제에서는 ComponentResourceKey을 사용하여 DataGrid의 DataGridSelectAllButtonStyle을 설정하였습니다.

* ComponentResourceKey.ResourceId : 이 형식과 연관된 다른 키와 이 키를 구분하기 위한 고유 식별자를 설정합니다.

* ComponentResourceKey.TypeInTargetAssembly : 리소스 키를 정의하는 Type을 설정합니다.

 

Visibility

 Button의 표시 유형을 설정합니다. 기본 값은 Visible이며, 다른 값으로는 Collapsed와 Hidden이 있습니다. 예제에서는 RelativeSource를 사용하여 부모인 DataGrid에서 HeadersVisibility 값(정확히는 DataGridHeadersVisibility.All 값)을 Binding 설정했습니다. 하지만 HeadersVisibility 값을 Visibility 값으로 사용하기 위해서는 DataGrid.HeadersVisibilityConverter를 사용하여 Visibility 값으로 변화해주어야 합니다.

* RelativeSource : 바인딩 대상의 위치를 기준으로 하여 바인딩 소스 위치를 설명하는 태그 확장을 구현합니다.

* DataGrid.HeadersVisibility : 행 머리글과 열 머리글의 표시 여부를 설정합니다.

* DataGrid.HeadersVisibilityConverter : DataGridHeadersVisibility를 Visibility로 변환하는 변환기입니다.

 

Width

 Button의 너비를 설정합니다. 예제에서는 RelativeSource를 사용하여 부모인 DataGrid에서 CellsPanelHorizontalOffset 값을 Binding 설정했습니다.

* RelativeSource : 바인딩 대상의 위치를 기준으로 하여 바인딩 소스 위치를 설명하는 태그 확장을 구현합니다.


 

DataGridColumnHeadersPresenter(PART_ColumnHeadersPresenter)

 DataGrid의 템플릿 내에서 열 머리글을 추가할 Control의 시각적 트리 내 위치를 지정하는 데 사용됩니다. 

👀 DataGridColumnHeadersPresenter 속성

더보기
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
                              Grid.Column="1"
                              Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />

x:Name

 DataGridColumnHeadersPresenter에 이름을 붙입니다. 이름을 붙이는 것과 동시에 다른 곳에서 사용할 수 있도록 만들어줍니다. 예제에서 "PART_ColumnHeadersPresenter" 값으로 사용하여 열 머리글이 포함된 행을 나타냅니다.

 

Grid.Column

 표시할 Grid(Parent)의 열을 설정합니다.

 

Visibility

 DataGridColumnHeadersPresenter의 표시 유형을 설정합니다. 기본 값은 Visible이며, 다른 값으로는 Collapsed와 Hidden이 있습니다. 예제에서는 RelativeSource를 사용하여 부모인 DataGrid에서 HeadersVisibility 값(정확히는 DataGridHeadersVisibility.Column 값)을 Binding 설정했습니다. 하지만 HeadersVisibility 값을 Visibility 값으로 사용하기 위해서는 DataGrid.HeadersVisibilityConverter를 사용하여 Visibility 값으로 변화해주어야 합니다.

* RelativeSource : 바인딩 대상의 위치를 기준으로 하여 바인딩 소스 위치를 설명하는 태그 확장을 구현합니다.

* DataGrid.HeadersVisibility : 행 머리글과 열 머리글의 표시 여부를 설정합니다.

* DataGrid.HeadersVisibilityConverter : DataGridHeadersVisibility를 Visibility로 변환하는 변환기입니다.


 

ScrollContentPresenter(PART_ScrollContentPresenter)

 ScrollViewer Control의 내용을 표시합니다.

👀 ScrollContentPresenter 속성

더보기
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
                      Grid.ColumnSpan="2"
                      Grid.Row="1"
                      CanContentScroll="{TemplateBinding CanContentScroll}" />

x:Name

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

 

Grid.ColumnSpan

 Grid에서 자식 Content를 채울 전체 열 수를 나타내는 값을 설정합니다.

 

Grid.Row

 표시할 Grid(Parent)의 행을 설정합니다.

 

CanContentScroll

 IScrollInfo(스크롤이 가능한 ScrollViewer Control 내의 주 영역)가 지원되는 경우 콘텐츠가 스크롤을 제어할 수 있는지 여부를 설정합니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 CanContentScroll 값으로 설정했습니다.


 

ScrollBar(PART_VerticalScrollBar)

 값에 따라 위치가 지정되는 이동식 Thumb(사용자가 끌어올 수 있는 Control)이 있는 스크롤 막대를 제공하는 Control입니다.

👀 ScrollBar 속성

더보기
<ScrollBar x:Name="PART_VerticalScrollBar"
         Grid.Column="2"
         Grid.Row="1"
         Orientation="Vertical"
         ViewportSize="{TemplateBinding ViewportHeight}"
         Maximum="{TemplateBinding ScrollableHeight}"
         Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
         Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>

x:Name

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

 

Grid.Column

 표시할 Grid(Parent)의 열을 설정합니다.

 

Grid.Row

 표시할 Grid(Parent)의 행을 설정합니다.

 

Orientation

 ScrollBar가 세로 방향으로 표시될지 가로 방향으로 표시될지를 설정합니다. 기본값은 Vertical(세로 방향)이며, 다른 값으로 Horizontal(가로방향)이 있습니다.

 

ViewportSize

 현재 볼 수 있는 스크롤 가능한 Content의 양을 설정합니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 ScrollableHeight 값으로 설정했습니다.

 

Maximum

 ScrollBar에서 사용 가능한 가장 높은 Value 값을 설정합니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 ComputedVerticalScrollBarVisibility 값으로 설정했습니다.

 

Visibility

 ScrollBar의 표시 유형을 설정합니다. 기본 값은 Visible이며, 다른 값으로는 Collapsed와 Hidden이 있습니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 ComputedVerticalScrollBarVisibility 값으로 설정했습니다.

 

Value

 ScrollBar의 현재 크기를 설정합니다. 예제에서는 RelativeSource를 사용하여 ScrollViewer에서 VerticalOffset 값을 Binding 설정했습니다. 

* RelativeSource : 바인딩 대상의 위치를 기준으로 하여 바인딩 소스 위치를 설명하는 태그 확장을 구현합니다.

* BindingMode : 바인딩의 데이터 흐름 방향입니다. 예제의 OneWay는 원본에서 받아오는 것만을 의미합니다.


 

Grid

 열 및 행으로 구성되는 유연한 모눈 영역을 정의합니다.

👀 Grid 속성

더보기
<Grid Grid.Column="1" Grid.Row="2">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
    <ColumnDefinition Width="*" />
  </Grid.ColumnDefinitions>

  <ScrollBar x:Name="PART_HorizontalScrollBar" ... />
</Grid>

Grid.Column

 표시할 Grid(Parent)의 열을 설정합니다.

 

Grid.Row

 표시할 Grid(Parent)의 행을 설정합니다.

 

ColumnDefinitions

 Grid에 ColumnDefinition을 사용하여 ColumnDefinitionCollection(ColumnDefinition 개체의 순서가 지정된 컬렉션)을 설정합니다.

 

ColumnDefinition
 Grid 요소에 적용되는 열 별 속성을 정의합니다. Width로 너비를 숫자 값, Auto 또는 '*'(기본값)로 설정할 수 있습니다. 숫자 값은 그 숫자의 픽셀 값이 고정되고 Auto는 Content 개체의 크기 속성에 따라 값을 결정합니다. 그리고 '*'은 가중치에 따른 여유 공간을 비율에 따라서 값을 결정합니다.


 

ScrollBar(PART_HorizontalScrollBar)

 값에 따라 위치가 지정되는 이동식 Thumb(사용자가 끌어올 수 있는 Control)이 있는 스크롤 막대를 제공하는 Control입니다.

👀 ScrollBar 속성

더보기
<ScrollBar x:Name="PART_HorizontalScrollBar"
           Grid.Column="1"
           Orientation="Horizontal"
           ViewportSize="{TemplateBinding ViewportWidth}"
           Maximum="{TemplateBinding ScrollableWidth}"
           Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
           Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>

x:Name

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

 

Grid.Column

 표시할 Grid(Parent)의 열을 설정합니다.

 

Orientation

 ScrollBar가 세로 방향으로 표시될지 가로 방향으로 표시될지를 설정합니다. 기본값은 Vertical(세로 방향)이며, 다른 값으로 Horizontal(가로방향)이 있습니다.

 

ViewportSize

 현재 볼 수 있는 스크롤 가능한 Content의 양을 설정합니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 ScrollableWidth값으로 설정했습니다.

 

Maximum

 ScrollBar에서 사용 가능한 가장 높은 Value 값을 설정합니다. 예제에서는 TemplateBinding을 사용하여 ScrollViewer의 ComputedHorizontalScrollBarVisibility 값으로 설정했습니다.

 

Visibility

 ScrollBar의 표시 유형을 설정합니다. 기본 값은 Visible이며, 다른 값으로는 Collapsed와 Hidden이 있습니다.

 

Value

 ScrollBar의 현재 크기를 설정합니다. 예제에서는 RelativeSource를 사용하여 ScrollViewer에서 HorizontalOffset 값을 Binding 설정했습니다. 

* RelativeSource : 바인딩 대상의 위치를 기준으로 하여 바인딩 소스 위치를 설명하는 태그 확장을 구현합니다.

* BindingMode : 바인딩의 데이터 흐름 방향입니다. 예제의 OneWay는 원본에서 받아오는 것만을 의미합니다.


 

ItemsPresenter

 항목 Control의 템플릿 내에서 ItemsPanel이 정의하는 ItemsControl을 추가할 Control의 시각적 트리 내 위치를 지정하는 데 사용됩니다. 예제에서는 DataGrid에 각 항목을 표시합니다. 

⭐ ItemsPresenter 속성

더보기

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

 

 

DataGrid 이벤트

 예제에서는 DataGrid의 이벤트로 Disabled 변화를 VisualStateManger 그리고 IsGrouping의 변화를 Triggers로 표현하였습니다.

 

VisualStateManager

<VisualStateManager.VisualStateGroups>
  <VisualStateGroup x:Name="CommonStates">
    <VisualState x:Name="Disabled">
      <Storyboard>
        <ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
                                      Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
          <EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ControlLightColor}" />
        </ColorAnimationUsingKeyFrames>
      </Storyboard>
    </VisualState>
    <VisualState x:Name="Normal" />
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

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

⭐ DataGrid은 2개(CommonStates, ValidationStates)의 VisualStateGroup을 가지고 있습니다.

Disabled
 Storyboard의 내용을 풀어보면 ["border"라는 이름을 가진 Control의 Background를 ControlLightColor로 바꾸는 것]입니다.
⭐ Normal의 경우 Storyboard가 존재하지 않지만 명시해주지 않으면 상태가 Disabled에서 Normal로 변할 때 외형이 바뀌지 않습니다.

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

 

 

Triggers

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

 Trigger는 어떤 조건이나 이벤트 등이 주어졌을 때 Control의 상태 또는 이벤트 핸들러 등을 호출하는 기능을 의미합니다. 예제의 코드는 IsGrouping의 값이 true일 경우 ScrollViewer.CanContentScroll의 값이 "false"로 설정합니다.

⭐ CanContentScroll : IScrollInfo(스크롤이 가능한 ScrollViewer Control 내의 주 영역)가 지원되는 경우 콘텐츠가 스크롤을 제어할 수 있는지 여부를 설정합니다.

 

 


 

 

전체 코드

더보기
<BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" />

<!--Style and template for the button in the upper left corner of the DataGrid.-->
<Style TargetType="{x:Type Button}"
       x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, 
  TypeInTargetAssembly={x:Type DataGrid}}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal" />
              <VisualState x:Name="MouseOver">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Shape.Fill).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="Pressed">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                Storyboard.TargetProperty="(Shape.Fill).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlPressedColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="Disabled">
                <Storyboard>
                  <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)"
                                                 Storyboard.TargetName="Arrow">
                    <DiscreteObjectKeyFrame KeyTime="0"
                                            Value="{x:Static Visibility.Collapsed}" />
                  </ObjectAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <Rectangle x:Name="Border"
                     SnapsToDevicePixels="True">
            <Rectangle.Stroke>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource BorderLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource BorderMediumColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Rectangle.Stroke>
            <Rectangle.Fill>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource ControlLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource ControlMediumColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Rectangle.Fill>
          </Rectangle>
          <Polygon x:Name="Arrow"
                   HorizontalAlignment="Right"
                   Margin="8,8,3,3"
                   Opacity="0.15"
                   Points="0,10 10,10 10,0"
                   Stretch="Uniform"
                   VerticalAlignment="Bottom">
            <Polygon.Fill>
              <SolidColorBrush Color="{DynamicResource GlyphColor}" />
            </Polygon.Fill>
          </Polygon>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the DataGrid.-->
<Style TargetType="{x:Type DataGrid}">
  <Setter Property="Foreground"
          Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
  <Setter Property="BorderBrush">
    <Setter.Value>
      <LinearGradientBrush EndPoint="0.5,1"
                           StartPoint="0.5,0">
        <GradientStop Color="{DynamicResource BorderLightColor}"
                      Offset="0" />
        <GradientStop Color="{DynamicResource BorderDarkColor}"
                      Offset="1" />
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
  <Setter Property="BorderThickness"
          Value="1" />
  <Setter Property="RowDetailsVisibilityMode"
          Value="VisibleWhenSelected" />
  <Setter Property="ScrollViewer.CanContentScroll"
          Value="true" />
  <Setter Property="ScrollViewer.PanningMode"
          Value="Both" />
  <Setter Property="Stylus.IsFlicksEnabled"
          Value="False" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGrid}">
        <Border x:Name="border"
                SnapsToDevicePixels="True"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                Padding="{TemplateBinding Padding}">
          <Border.Background>
            <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
          </Border.Background>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Disabled">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{DynamicResource ControlLightColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="Normal" />
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <ScrollViewer x:Name="DG_ScrollViewer"
                        Focusable="false"
                        Background="Black">
            <ScrollViewer.Template>
              <ControlTemplate TargetType="{x:Type ScrollViewer}">
                <Grid>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                  </Grid.ColumnDefinitions>
                  <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                  </Grid.RowDefinitions>

                  <Button Focusable="false"
                          Command="{x:Static DataGrid.SelectAllCommand}"
                          Style="{DynamicResource {ComponentResourceKey 
                      ResourceId=DataGridSelectAllButtonStyle, 
                      TypeInTargetAssembly={x:Type DataGrid}}}"
                          Visibility="{Binding HeadersVisibility, 
                      ConverterParameter={x:Static DataGridHeadersVisibility.All}, 
                      Converter={x:Static DataGrid.HeadersVisibilityConverter}, 
                      RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                          Width="{Binding CellsPanelHorizontalOffset, 
                      RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />

                  <DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
                                                  Grid.Column="1"
                                                  Visibility="{Binding HeadersVisibility, 
                      ConverterParameter={x:Static DataGridHeadersVisibility.Column}, 
                      Converter={x:Static DataGrid.HeadersVisibilityConverter}, 
                      RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />

                  <ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
                                          Grid.ColumnSpan="2"
                                          Grid.Row="1"
                                          CanContentScroll="{TemplateBinding CanContentScroll}" />

                  <ScrollBar x:Name="PART_VerticalScrollBar"
                             Grid.Column="2"
                             Grid.Row="1"
                             Orientation="Vertical"
                             ViewportSize="{TemplateBinding ViewportHeight}"
                             Maximum="{TemplateBinding ScrollableHeight}"
                             Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                             Value="{Binding VerticalOffset, Mode=OneWay, 
                      RelativeSource={RelativeSource TemplatedParent}}"/>

                  <Grid Grid.Column="1"
                        Grid.Row="2">
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, 
                          RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                      <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>

                    <ScrollBar x:Name="PART_HorizontalScrollBar"
                               Grid.Column="1"
                               Orientation="Horizontal"
                               ViewportSize="{TemplateBinding ViewportWidth}"
                               Maximum="{TemplateBinding ScrollableWidth}"
                               Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                               Value="{Binding HorizontalOffset, Mode=OneWay, 
                        RelativeSource={RelativeSource TemplatedParent}}"/>
                  </Grid>
                </Grid>
              </ControlTemplate>
            </ScrollViewer.Template>
            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
          </ScrollViewer>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Style.Triggers>
    <Trigger Property="IsGrouping"
             Value="true">
      <Setter Property="ScrollViewer.CanContentScroll"
              Value="false" />
    </Trigger>
  </Style.Triggers>
</Style>

<!--Style and template for the DataGridCell.-->
<Style TargetType="{x:Type DataGridCell}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridCell}">
        <Border x:Name="border"
                BorderBrush="Transparent"
                BorderThickness="1"
                Background="Transparent"
                SnapsToDevicePixels="True">
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="FocusStates">
              <VisualState x:Name="Unfocused" />
              <VisualState x:Name="Focused" />
            </VisualStateGroup>
            <VisualStateGroup x:Name="CurrentStates">
              <VisualState x:Name="Regular" />
              <VisualState x:Name="Current">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
                                                Storyboard.TargetProperty="(Border.BorderBrush).
                      (SolidColorBrush.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource DatagridCurrentCellBorderColor}" />
                  </ColorAnimationUsingKeyFrames
                                                >
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the DataGridRow.-->
<Style TargetType="{x:Type DataGridRow}">
  <Setter Property="Background">
    <Setter.Value>
      <SolidColorBrush Color="{DynamicResource ControlLightColor}" />
    </Setter.Value>
  </Setter>
  <Setter Property="SnapsToDevicePixels"
          Value="true" />
  <Setter Property="Validation.ErrorTemplate"
          Value="{x:Null}" />
  <Setter Property="ValidationErrorTemplate">
    <Setter.Value>
      <ControlTemplate>
        <TextBlock Foreground="Red"
                   Margin="2,0,0,0"
                   Text="!"
                   VerticalAlignment="Center" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridRow}">
        <Border x:Name="DGR_Border"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}"
                SnapsToDevicePixels="True">
          <Border.Background>
            <LinearGradientBrush EndPoint="0.5,1"
                                 StartPoint="0.5,0">
              <GradientStop Color="Transparent"
                            Offset="0" />
              <GradientStop Color="{DynamicResource ControlLightColor}"
                            Offset="1" />
            </LinearGradientBrush>
          </Border.Background>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal" />

              <!--Provide a different appearance for every other row.-->
              <VisualState x:Name="Normal_AlternatingRow">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ContentAreaColorLight}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">

                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ContentAreaColorDark}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <!--In this example, a row in Editing or selected mode has an
              identical appearances. In other words, the states 
              Normal_Selected, Unfocused_Selected, Normal_Editing, 
              MouseOver_Editing, MouseOver_Unfocused_Editing,
              and Unfocused_Editing are identical.-->
              <VisualState x:Name="Normal_Selected">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="Unfocused_Selected">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="Normal_Editing">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="MouseOver_Editing">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="MouseOver_Unfocused_Editing">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="Unfocused_Editing">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlDarkColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="MouseOver">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMediumColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <!--In this example, the appearance of a selected row 
              that has the mouse over it is the same regardless of
              whether the row is selected.  In other words, the states 
              MouseOver_Editing and MouseOver_Unfocused_Editing are identical.-->
              <VisualState x:Name="MouseOver_Selected">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>

              <VisualState x:Name="MouseOver_Unfocused_Selected">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[0].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="DGR_Border"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>

          <SelectiveScrollingGrid>
            <SelectiveScrollingGrid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="*" />
            </SelectiveScrollingGrid.ColumnDefinitions>
            <SelectiveScrollingGrid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="Auto" />
            </SelectiveScrollingGrid.RowDefinitions>
            <DataGridCellsPresenter Grid.Column="1"
                                    ItemsPanel="{TemplateBinding ItemsPanel}"
                                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
            <DataGridDetailsPresenter Grid.Column="1"
                                      Grid.Row="1"
                                      Visibility="{TemplateBinding DetailsVisibility}"
                                      SelectiveScrollingGrid.SelectiveScrollingOrientation=
                "{Binding AreRowDetailsFrozen, 
                ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical},
                Converter={x:Static DataGrid.RowDetailsScrollingConverter}, 
                RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
            <DataGridRowHeader Grid.RowSpan="2"
                               SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
                               Visibility="{Binding HeadersVisibility, 
                ConverterParameter={x:Static DataGridHeadersVisibility.Row}, 
                Converter={x:Static DataGrid.HeadersVisibilityConverter}, 
                RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
          </SelectiveScrollingGrid>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the resize control on the DataGridRowHeader.-->
<Style x:Key="RowHeaderGripperStyle"
       TargetType="{x:Type Thumb}">
  <Setter Property="Height"
          Value="8" />
  <Setter Property="Background"
          Value="Transparent" />
  <Setter Property="Cursor"
          Value="SizeNS" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Thumb}">
        <Border Background="{TemplateBinding Background}"
                Padding="{TemplateBinding Padding}" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the DataGridRowHeader.-->
<Style TargetType="{x:Type DataGridRowHeader}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridRowHeader}">
        <Grid>
          <VisualStateManager.VisualStateGroups>
            <!--This example does not specify an appearance for every
                state.  You can add storyboard to the states that are listed
                to change the appearance of the DataGridRowHeader when it is
                in a specific state.-->
            <VisualStateGroup x:Name="CommonStates">
              <VisualState x:Name="Normal" />
              <VisualState x:Name="Normal_CurrentRow" />
              <VisualState x:Name="Unfocused_EditingRow" />
              <VisualState x:Name="Normal_EditingRow" />
              <VisualState x:Name="MouseOver">
                <Storyboard>
                  <ColorAnimationUsingKeyFrames Storyboard.TargetName="rowHeaderBorder"
                                                Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
                    <EasingColorKeyFrame KeyTime="0"
                                         Value="{StaticResource ControlMouseOverColor}" />
                  </ColorAnimationUsingKeyFrames>
                </Storyboard>
              </VisualState>
              <VisualState x:Name="MouseOver_CurrentRow" />
              <VisualState x:Name="MouseOver_Unfocused_EditingRow" />
              <VisualState x:Name="MouseOver_EditingRow" />
              <VisualState x:Name="MouseOver_Unfocused_Selected" />
              <VisualState x:Name="MouseOver_Selected" />
              <VisualState x:Name="MouseOver_Unfocused_CurrentRow_Selected" />
              <VisualState x:Name="MouseOver_CurrentRow_Selected" />
              <VisualState x:Name="Unfocused_Selected" />
              <VisualState x:Name="Unfocused_CurrentRow_Selected" />
              <VisualState x:Name="Normal_CurrentRow_Selected" />
              <VisualState x:Name="Normal_Selected" />
            </VisualStateGroup>
          </VisualStateManager.VisualStateGroups>
          <Border x:Name="rowHeaderBorder"
                  Width="10"
                  BorderThickness="1">
            <Border.BorderBrush>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource BorderLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource BorderDarkColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Border.BorderBrush>
            <Border.Background>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource ControlLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource ControlMediumColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Border.Background>
            <StackPanel Orientation="Horizontal">
              <ContentPresenter VerticalAlignment="Center"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
              <Control SnapsToDevicePixels="false"
                       Template="{Binding ValidationErrorTemplate, 
                  RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}"
                       Visibility="{Binding (Validation.HasError), 
                  Converter={StaticResource bool2VisibilityConverter}, 
                  RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
            </StackPanel>
          </Border>

          <Thumb x:Name="PART_TopHeaderGripper"
                 Style="{StaticResource RowHeaderGripperStyle}"
                 VerticalAlignment="Top" />
          <Thumb x:Name="PART_BottomHeaderGripper"
                 Style="{StaticResource RowHeaderGripperStyle}"
                 VerticalAlignment="Bottom" />
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the resize control on the DataGridColumnHeader.-->
<Style x:Key="ColumnHeaderGripperStyle"
       TargetType="{x:Type Thumb}">
  <Setter Property="Width"
          Value="8" />
  <Setter Property="Background"
          Value="Transparent" />
  <Setter Property="Cursor"
          Value="SizeWE" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Thumb}">
        <Border Background="{TemplateBinding Background}"
                Padding="{TemplateBinding Padding}" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the DataGridColumnHeader.-->
<Style TargetType="{x:Type DataGridColumnHeader}">
  <Setter Property="VerticalContentAlignment"
          Value="Center" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
        <Grid>
          <Border x:Name="columnHeaderBorder"
                  BorderThickness="1"
                  Padding="3,0,3,0">
            <Border.BorderBrush>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource BorderLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource BorderDarkColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Border.BorderBrush>
            <Border.Background>
              <LinearGradientBrush EndPoint="0.5,1"
                                   StartPoint="0.5,0">
                <GradientStop Color="{DynamicResource ControlLightColor}"
                              Offset="0" />
                <GradientStop Color="{DynamicResource ControlMediumColor}"
                              Offset="1" />
              </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
          </Border>

          <Thumb x:Name="PART_LeftHeaderGripper"
                 HorizontalAlignment="Left"
                 Style="{StaticResource ColumnHeaderGripperStyle}" />
          <Thumb x:Name="PART_RightHeaderGripper"
                 HorizontalAlignment="Right"
                 Style="{StaticResource ColumnHeaderGripperStyle}" />
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="Background">
    <Setter.Value>
      <LinearGradientBrush EndPoint="0.5,1"
                           StartPoint="0.5,0">
        <GradientStop Color="{DynamicResource ControlLightColor}"
                      Offset="0" />
        <GradientStop Color="{DynamicResource ControlMediumColor}"
                      Offset="1" />
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
</Style>

<!--Style and template for the DataGridColumnHeadersPresenter.-->
<Style TargetType="{x:Type DataGridColumnHeadersPresenter}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
        <Grid>
          <DataGridColumnHeader x:Name="PART_FillerColumnHeader"
                                IsHitTestVisible="False" />
          <ItemsPresenter />
        </Grid>
      </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/datagrid-styles-and-templates?view=netframeworkdesktop-4.8 

 

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

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

docs.microsoft.com

 

반응형

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

DataGrid③  (0) 2022.05.16
DataGrid②  (0) 2022.05.13
ContextMenu  (0) 2022.05.11
ComboBox②  (0) 2022.05.10
ComboBox①  (0) 2022.05.09