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

Menu③

(ㅇㅅㅎ) 2022. 6. 8. 15:15
728x90
반응형

 

 안녕하세요, 이번 글에서는 지난 글에 이어서 Microsoft에서 제공하는 WPF [Menu의 스타일 및 템플릿] 예제를 톺아보겠습니다. Menu Style의 경우 Menu, Separator, MenuItemRole ControlTemplate(TopLevelHeader, TopLevelItem, SubmenuItem, SubmenuHeader), MenuItem, MenuScrollViewer 순서로 나눠져 있습니다. 이번 글에서는 MenuItemRole ControlTemplateSubmenuHeaderSubmeneItem에 대해서 보도록 하겠습니다.

 

 

 

MenuItemRole

모두 MenuItem이나 Role이 다르다

 MenuItem에 포함될 수 있는 서로 다른 역할을 정의합니다. 값으로는 TopLevelHeader, TopLevelItem, SubmenuHeaderSubmenuItem이 있습니다. 예제에서는 각 Role을 ControlTemplate로 따로 정의한 뒤 사용했습니다.

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

 

 

 

SubmenuHeader 구성

 SubmenuHeader는 하위 메뉴의 헤더입니다. 예제에서는 Grid 내부에 SubmenuHeader를 나타내는 ContentPresenterTextBlockSubmenItem을 위한 Popup이 구성되어 있습니다.

 

Border(Border, Check)

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

Border 속성

더보기
<Border x:Name="Border" BorderThickness="1">
  ...
      <Border x:Name="SubmenuBorder" SnapsToDevicePixels="True" Background="{DynamicResource MenuPopupBrush}" BorderThickness="1">
        <Border.BorderBrush>
          <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
        </Border.BorderBrush>
          ...
      </Border>
  ...
</Border>

 

x:Name

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

 

BorderThickness

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

 

SnapsToDevicePixels

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

 

Background

 Border의 배경색을 설정합니다. 예제에서는 미리 정의한 MenuPopupBrush로 설정했습니다.

 

BorderBrush

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


 

Grid

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

⭐ Grid 속성

더보기
<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" SharedSizeGroup="Icon" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut" />
    <ColumnDefinition Width="13" />
  </Grid.ColumnDefinitions>
  ...
</Grid>

 

ColumnDefinitions

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

 

ColumnDefinition

 Grid 요소에 적용되는 열 별 속성을 정의합니다. Width로 너비를 숫자 값, 'Auto' 또는 '*'로 설정할 수 있습니다.


 

ContentPresenter(Icon, HeaderHost)

 ContentControl의 내용을 표시합니다.

ContentPresenter 속성

더보기
<ContentPresenter x:Name="Icon" Margin="6,0,6,0" VerticalAlignment="Center" ContentSource="Icon" />
<ContentPresenter x:Name="HeaderHost" Grid.Column="1" ContentSource="Header" RecognizesAccessKey="True" />

 

x:Name

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

 

Margin

 ContentPresenter의 외부 여백을 설정합니다. 예제에서는 4개(좌, 상, 우, 하)로 나누어서 설정했습니다.

 

VerticalAlignment

 ContentPresenter의 세로 정렬 위치를 설정합니다. 기본값은 Stretch이며, 다른 값으로는 Top, Center, Bottom이 있습니다.

 

ContentSource

 별칭을 자동으로 지정할 때 사용할 기본 이름을 설정합니다.

 

Grid.Column

 표시할 Grid의 열 자식 Content를 나타내는 값을 설정합니다.

 

RecognizesAccessKey

 ContentPresenter의 스타일에 AccessText가 사용되는지 여부를 설정합니다. AccessText가 사용되면 true이고, 그렇지 않으면 false입니다.


 

TextBlock(InputGestureText)

 작은 양의 유동 Content를 표시하는 간단한 Control을 제공합니다.

TextBlock 속성

더보기
<TextBlock x:Name="InputGestureText" Grid.Column="2" Text="{TemplateBinding InputGestureText}" Margin="5,2,2,2" DockPanel.Dock="Right" />

 

x:Name

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

 

Grid.Column

 표시할 Grid의 열 자식 Content를 나타내는 값을 설정합니다.

 

Text

 TextBlock의 텍스트 Content를 설정합니다. 예제에서는 TemplateBinding을 사용하여 부모의 InputGestureText로 설정했습니다.

 

Margin

 TextBlock의 외부 여백을 설정합니다. 예제에서는 4개(좌, 상, 우, 하)로 나누어서 설정했습니다.

 

DockPanel.Dock

 Doc 내에 있는 자식 요소의 DockPanel 위치를 지정합니다.


 

Path

 일련의 연결된 선 및 곡선을 그립니다.

⭐ Path 속성

더보기
<Path Grid.Column="3" HorizontalAlignment="Center" VerticalAlignment="Center" Data="M 0 0 L 0 7 L 4 3.5 Z">
  <Path.Fill>
    <SolidColorBrush Color="{DynamicResource GlyphColor}" />
  </Path.Fill>
</Path>

 

Grid.Column

 표시할 Grid의 열 자식 Content를 나타내는 값을 설정합니다.

 

HorizontalAlignment

 Path의 가로 정렬 위치를 설정합니다. 기본값은 Stretch이며, 다른 값으로는 Left, Center, Right가 있습니다.

 

VerticalAlignment

 Path의 세로 정렬 위치를 설정합니다. 기본값은 Stretch이며, 다른 값으로는 Top, Center, Bottom이 있습니다.

 

Data

 그릴 모양을 지정하는 Geometry를 설정합니다.

👀 Data 값에 대한 자세한 설명은 이 페이지를 참고하시길 바랍니다.

 

Fill

 도형 내부의 색을 설정합니다. 예제에서는 SolidColorBrush를 사용하여 미리 정의한 색인 GlyphColor로 설정했습니다.


 

Popup(Popup)

 Content가 포함된 Popup 창을 나타냅니다.

⭐ Popup 속성

더보기
<Popup x:Name="Popup" Placement="Right" HorizontalOffset="-4" IsOpen="{TemplateBinding IsSubmenuOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Fade">
  ...
</Popup>

 

x:Name

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

 

Placement

 Popup이 열리는 방향을 설정합니다. 값으로는 Absolute, AbsolutePoint, Bottom, Center, Custom, Left 등이 있습니다.

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

 

HorizontalOffset

 대산 원점과 팝업 맞춤 지점 간의 가로 거리를 설정합니다.

 

IsOpen

 Popup의 표시 여부를 설정합니다. 예제에서는 TemplateBinding을 사용하여 부모의 IsSubmenuOpen 값으로 설정했습니다.

 

AllowsTransparency

 Popup이 투명 Content를 포함할 수 있는지 여부를 설정합니다. 투명 Content를 포함할 수 있으면 true이고, 포함할 수 없으면 false입니다.

 

Focusable

 Popup이 focus를 받을 수 있는지 여부를 설정합니다. focus를 받을 수 있으면 true이고, 받을 수 없으면 false입니다.

 

PopupAnimation

 Popup 열기 및 닫기 애니메이션을 설정합니다. 기본값은 None이며 다른 값으로는 Fade, Scroll, Slide가 있습니다.

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


 

ScrollViewer

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

ScrollViewer 속성

더보기
<ScrollViewer CanContentScroll="True" Style="{StaticResource MenuScrollViewer}">
  ...
</ScrollViewer>

 

CanContentScroll

 IScrollInfo가 지원되는 경우 Content가 Scroll을 제어할 수 있는지 여부를 설정합니다. Content를 Scroll 할 수 있으면 true이고, 그렇지 않으면 false입니다.

 

Style

 Style은 ScrollViewer에 속성, 리소스 및 이벤트 처리기를 공유할 수 있게합니다. 예제에서는 미리 정의한 MenuScrollViewer로 설정했습니다.


 

StackPanel

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

StackPanel 속성

더보기
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle" />

 

IsItemsHost

 ItemsControl에 의해 생성된 UI(사용자 인터페이스) 항목에 대한 컨테이너임을 나타내는 Panel 값을 설정합니다. 항목 호스트이면 true이고, 그렇지 않으면 false입니다.

 

KeyboardNavigation.DirectionalNavigation

 이 속성이 설정된 요소의 자식에 대한 방향 탐색 동작을 설정합니다. 값으로는 Contained, Continue, Cycle, Local, None, Once가 있습니다.

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


 

 

 

SubmenuHeader 이벤트

 예제에서는 이벤트로 Icon, IsHighlighted, Popup 및 IsEnabled 변화를 Trigger로 표현하였습니다.

 

Triggers

<ControlTemplate.Triggers>
  <Trigger Property="Icon" Value="{x:Null}">
    <Setter TargetName="Icon" Property="Visibility" Value="Collapsed" />
  </Trigger>
  <Trigger Property="IsHighlighted" Value="true">
    <Setter Property="Background" TargetName="Border">
      <Setter.Value>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="Transparent" Offset="0" />
          <GradientStop Color="{DynamicResource ControlMouseOverColor}" Offset="1" />
        </LinearGradientBrush>
      </Setter.Value>
    </Setter>
    <Setter Property="BorderBrush" TargetName="Border">
      <Setter.Value>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="{DynamicResource BorderMediumColor}" Offset="0" />
          <GradientStop Color="Transparent" Offset="1" />
        </LinearGradientBrush>
      </Setter.Value>
    </Setter>
  </Trigger>
  <Trigger SourceName="Popup" Property="AllowsTransparency" Value="True">
    <Setter TargetName="SubmenuBorder" Property="CornerRadius" Value="4" />
    <Setter TargetName="SubmenuBorder" Property="Padding" Value="0,3,0,3" />
  </Trigger>
  <Trigger Property="IsEnabled" Value="false">
    <Setter Property="Foreground">
      <Setter.Value>
        <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
      </Setter.Value>
    </Setter>
  </Trigger>
</ControlTemplate.Triggers>

 Trigger는 어떤 조건이나 이벤트 등이 주어졌을 때 Control의 상태 또는 이벤트 핸들러 등을 호출하는 기능을 의미합니다. 예제에서는 아래와 같이 설정되었습니다.

  • Icon 값이 null일 경우 Icon의 Visibility를 Collapsed로 변경합니다.
  • IsHighlighted 값이 true일 경우 Border의 Background와 BorderBrush를 그라데이션 색으로 변경합니다.
  • Popup의 AllowsTransparency 값이 true일 경우 SubmenuBorder의 CornerRadius를 4로 변경하고 Padding을 "0, 3, 0, 3"으로 변경합니다.
  • IsEnabled 값이 false일 경우 Foreground를 DisabledForegroundColor로 변경합니다.

👀 그라데이션 색에 대해서 알고 싶으신 분은 이 페이지를 참고하시길 바랍니다.

 

 

 


 

 

 

SubmenuItem 구성

 SubmenuItem은 명령을 호출할 수 있는 하위 메뉴의 메뉴 항목입니다. 예제에서는 Grid 내부에 SubmenuItem을 나타내는 ContentPresenterTextBlock을 나누어서 구성되어 있습니다.

 

Border(Border, Check)

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

⭐ Border 속성

더보기
<Border x:Name="Border" BorderThickness="1">
  ...
    <Border x:Name="Check" Width="13" Height="13" Visibility="Collapsed" Margin="6,0,6,0" BorderThickness="1">
      <Border.BorderBrush>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
          <LinearGradientBrush.GradientStops>
            <GradientStopCollection>
              <GradientStop Color="{DynamicResource BorderLightColor}" Offset="0.0" />
              <GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1.0" />
            </GradientStopCollection>
          </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
      </Border.BorderBrush> 
      <Border.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
          <LinearGradientBrush.GradientStops>
            <GradientStopCollection>
              <GradientStop Color="{DynamicResource ControlLightColor}" />
              <GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1.0" />
            </GradientStopCollection>
          </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
      </Border.Background>
      ...
    </Border>
    ...
</Border>

 

x:Name

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

 

BorderThickness

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

 

Width

 Border의 너비를 설정합니다.

 

Height

 Border의 높이를 설정합니다.

 

Visibility

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

 

Margin

 Border의 외부 여백을 설정합니다. 예제에서는 4개(좌, 상, 우, 하)로 나누어서 설정했습니다.

 

BorderBrush

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

 

Background

 Border의 배경색을 설정합니다. 예제에서는 LinearGradientBrush를 사용하여 그라데이션 색으로 설정했습니다. 

 

👀 그라데이션 색에 대해서 알고 싶으신 분은 이 페이지를 참고하시길 바랍니다.


 

Grid

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

⭐ Grid 속성

더보기
<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" SharedSizeGroup="Icon" />
    <ColumnDefinition Width="*" />
    <ColumnDefinition Width="Auto" SharedSizeGroup="Shortcut" />
    <ColumnDefinition Width="13" />
  </Grid.ColumnDefinitions>
  ...
</Grid>

 

ColumnDefinitions

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

 

ColumnDefinition

 Grid 요소에 적용되는 열 별 속성을 정의합니다. Width로 너비를 숫자 값, 'Auto' 또는 '*'로 설정할 수 있습니다.


 

ContentPresenter(Icon, HeaderHost)

 ContentControl의 내용을 표시합니다.

ContentPresenter 속성

더보기
<ContentPresenter x:Name="Icon" Margin="6,0,6,0" VerticalAlignment="Center" ContentSource="Icon" />
<ContentPresenter x:Name="HeaderHost" Grid.Column="1" ContentSource="Header" RecognizesAccessKey="True" />

 

x:Name

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

 

Margin

 ContentPresenter의 외부 여백을 설정합니다. 예제에서는 4개(좌, 상, 우, 하)로 나누어서 설정했습니다.

 

VerticalAlignment

 ContentPresenter의 세로 정렬 위치를 설정합니다. 기본값은 Stretch이며, 다른 값으로는 Top, Center, Bottom이 있습니다.

 

ContentSource

 별칭을 자동으로 지정할 때 사용할 기본 이름을 설정합니다.

 

Grid.Column

 표시할 Grid의 열 자식 Content를 나타내는 값을 설정합니다.

 

RecognizesAccessKey

 ContentPresenter의 스타일에 AccessText가 사용되는지 여부를 설정합니다. AccessText가 사용되면 true이고, 그렇지 않으면 false입니다.


 

TextBlock(InputGestureText)

 작응 양의 유동 Content를 표시하는 간단한 Control을 제공합니다.

TextBlock 속성

더보기
<TextBlock x:Name="InputGestureText" Grid.Column="2" Text="{TemplateBinding InputGestureText}" Margin="5,2,0,2" DockPanel.Dock="Right" />

 

x:Name

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

 

Grid.Column

 표시할 Grid의 열 자식 Content를 나타내는 값을 설정합니다.

 

Text

 TextBlock의 텍스트 Content를 설정합니다. 예제에서는 TemplateBinding을 사용하여 부모의 InputGestureText로 설정했습니다.

 

Margin

 TextBlock의 외부 여백을 설정합니다. 예제에서는 4개(좌, 상, 우, 하)로 나누어서 설정했습니다.

 

DockPanel.Dock

 Doc 내에 있는 자식 요소의 DockPanel 위치를 지정합니다.


 

Path(CheckMark)

 일련의 연결된 선 및 곡선을 그립니다.

⭐ Path 속성

더보기
<Path x:Name="CheckMark" Width="7" Height="7" Visibility="Hidden" SnapsToDevicePixels="False" StrokeThickness="2" Data="M 0 0 L 7 7 M 0 7 L 7 0">
  <Path.Stroke>
    <SolidColorBrush Color="{DynamicResource GlyphColor}" />
  </Path.Stroke>
</Path>

 

x:Name

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

 

Width

 Path의 너비를 설정합니다.

 

Height

 Path의 높이를 설정합니다.

 

Visibility

 Path의 표시 유형을 설정합니다. 기본값은 Visible이며 다른 값으로 Hidden과 Collapsed가 있습니다.

 

SnapsToDevicePixels

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

 

StrokeThickness

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

 

Data

 그릴 모양을 지정하는 Geometry를 설정합니다.

👀 Data 값에 대한 자세한 설명은 이 페이지를 참고하시길 바랍니다.

 

Stroke

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


 

 

 

SubmenuItem 이벤트

 예제에서는 이벤트로 Icon, IsChecked, IsCheckable, IsHighlighted 및 IsEnabled 변화를 Trigger로 표현하였습니다.

 

Triggers

<ControlTemplate.Triggers>
  <Trigger Property="ButtonBase.Command" Value="{x:Null}" />
  <Trigger Property="Icon" Value="{x:Null}">
    <Setter TargetName="Icon" Property="Visibility" Value="Hidden" />
  </Trigger>
  <Trigger Property="IsChecked" Value="true">
    <Setter TargetName="CheckMark" Property="Visibility" Value="Visible" />
  </Trigger>
  <Trigger Property="IsCheckable" Value="true">
    <Setter TargetName="Check" Property="Visibility" Value="Visible" />
    <Setter TargetName="Icon" Property="Visibility" Value="Hidden" />
  </Trigger>
  <Trigger Property="IsHighlighted" Value="true">
    <Setter Property="Background" TargetName="Border">
      <Setter.Value>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="Transparent" Offset="0" />
          <GradientStop Color="{DynamicResource ControlMouseOverColor}" Offset="1" />
        </LinearGradientBrush>
      </Setter.Value>
    </Setter>
    <Setter Property="BorderBrush" TargetName="Border">
      <Setter.Value>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="{DynamicResource BorderMediumColor}" Offset="0" />
          <GradientStop Color="Transparent" Offset="1" />
        </LinearGradientBrush>
      </Setter.Value>
    </Setter>
  </Trigger>
<Trigger Property="IsEnabled" Value="false">
  <Setter Property="Foreground">
    <Setter.Value>
      <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
    </Setter.Value>
  </Setter>
</Trigger>
</ControlTemplate.Triggers>

 Trigger는 어떤 조건이나 이벤트 등이 주어졌을 때 Control의 상태 또는 이벤트 핸들러 등을 호출하는 기능을 의미합니다. 예제에서는 아래와 같이 설정되었습니다.

  • Icon 값이 null일 경우 Icon의 Visibility를 Collapsed로 변경합니다.
  • IsChecked 값이 true일 경우 CheckMark의 Visibility를 Visible로 변경합니다.
  • IsCheckable 값이 true일 경우 Check와 Icon의 Visibility를 Visible과 Hidden으로 변경합니다.
  • IsHighlighted 값이 true일 경우 Border의 Background와 BorderBrush를 그라데이션색으로 변경합니다.
  • IsEnabled 값이 false일 경우 Foreground를 DisabledForegoundColor로 변경합니다.

👀 그라데이션 색에 대해서 알고 싶으신 분은 이 페이지를 참고하시길 바랍니다.

 

 

 


 

 

 

전체 코드

더보기
<!--#region 오류 방지 부족한 부분 추가 -->
<Geometry x:Key="UpArrow">M 0,4 L 3.5,0 L 7,4 Z</Geometry>
<Geometry x:Key="DownArrow">M 0,0 L 3.5,4 L 7,0 Z</Geometry>
<Style x:Key="MenuScrollButton" BasedOn="{x:Null}" TargetType="{x:Type RepeatButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type RepeatButton}">
                <Border x:Name="Border" BorderThickness="0" Background="Transparent">
                    <ContentPresenter x:Name="ContentContainer" HorizontalAlignment="Center" Margin="2" VerticalAlignment="Center"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="Border" Property="Background">
                            <Setter.Value>
                                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStopCollection>
                                            <GradientStop Color="{StaticResource ControlLightColor}" />
                                            <GradientStop Color="{StaticResource ControlMouseOverColor}" Offset="1.0" />
                                        </GradientStopCollection>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<!--#endregion-->

<Style x:Key="{x:Type Menu}"
       TargetType="{x:Type Menu}">
  <Setter Property="OverridesDefaultStyle"
          Value="True" />
  <Setter Property="SnapsToDevicePixels"
          Value="True" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Menu}">
        <Border BorderThickness="1">
          <Border.BorderBrush>
            <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="0,1">
              <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                  <GradientStop Color="{DynamicResource BorderLightColor}"
                                Offset="0.0" />
                  <GradientStop Color="{DynamicResource BorderDarkColor}"
                                Offset="1.0" />
                </GradientStopCollection>
              </LinearGradientBrush.GradientStops>
            </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 ClipToBounds="True"
                      Orientation="Horizontal"
                      IsItemsHost="True" />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
<Style x:Key="{x:Static MenuItem.SeparatorStyleKey}"
       TargetType="{x:Type Separator}">
  <Setter Property="Height"
          Value="1" />
  <Setter Property="Margin"
          Value="0,4,0,4" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type Separator}">
        <Border BorderThickness="1">
          <Border.BorderBrush>
            <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
          </Border.BorderBrush>
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

<!-- TopLevelHeader -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelHeaderTemplateKey}"
                 TargetType="{x:Type MenuItem}">
  <Border x:Name="Border">
    <Grid>
      <ContentPresenter Margin="6,3,6,3"
                        ContentSource="Header"
                        RecognizesAccessKey="True" />
      <Popup x:Name="Popup"
             Placement="Bottom"
             IsOpen="{TemplateBinding IsSubmenuOpen}"
             AllowsTransparency="True"
             Focusable="False"
             PopupAnimation="Fade">
        <Border x:Name="SubmenuBorder"
                SnapsToDevicePixels="True"
                BorderThickness="1"
                Background="{DynamicResource MenuPopupBrush}">
          <Border.BorderBrush>
            <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
          </Border.BorderBrush>
          <ScrollViewer CanContentScroll="True"
                        Style="{StaticResource MenuScrollViewer}">
            <StackPanel IsItemsHost="True"
                        KeyboardNavigation.DirectionalNavigation="Cycle" />
          </ScrollViewer>
        </Border>
      </Popup>
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsSuspendingPopupAnimation"
             Value="true">
      <Setter TargetName="Popup"
              Property="PopupAnimation"
              Value="None" />
    </Trigger>
    <Trigger Property="IsHighlighted"
             Value="true">
      <Setter TargetName="Border"
              Property="BorderBrush"
              Value="Transparent" />
      <Setter Property="Background"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0"
                               EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="{StaticResource ControlLightColor}" />
                <GradientStop Color="{StaticResource ControlMouseOverColor}"
                              Offset="1.0" />
              </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>

        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger SourceName="Popup"
             Property="AllowsTransparency"
             Value="True">
      <Setter TargetName="SubmenuBorder"
              Property="CornerRadius"
              Value="0,0,4,4" />
      <Setter TargetName="SubmenuBorder"
              Property="Padding"
              Value="0,0,0,3" />
    </Trigger>
    <Trigger Property="IsEnabled"
             Value="False">
      <Setter Property="Foreground">
        <Setter.Value>
          <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- TopLevelItem -->
<ControlTemplate x:Key="{x:Static MenuItem.TopLevelItemTemplateKey}"
                 TargetType="{x:Type MenuItem}">
  <Border x:Name="Border">
    <Grid>
      <ContentPresenter Margin="6,3,6,3"
                        ContentSource="Header"
                        RecognizesAccessKey="True" />
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="IsHighlighted"
             Value="true">
      <Setter Property="Background"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush StartPoint="0,0"
                               EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="{StaticResource ControlLightColor}" />
                <GradientStop Color="{StaticResource ControlMouseOverColor}"
                              Offset="1.0" />
              </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>

        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger Property="IsEnabled"
             Value="False">
      <Setter Property="Foreground">
        <Setter.Value>
          <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- SubmenuItem -->
<ControlTemplate x:Key="{x:Static MenuItem.SubmenuItemTemplateKey}"
                 TargetType="{x:Type MenuItem}">
  <Border x:Name="Border"
          BorderThickness="1">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"
                          SharedSizeGroup="Icon" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto"
                          SharedSizeGroup="Shortcut" />
        <ColumnDefinition Width="13" />
      </Grid.ColumnDefinitions>
      <ContentPresenter x:Name="Icon"
                        Margin="6,0,6,0"
                        VerticalAlignment="Center"
                        ContentSource="Icon" />
      <Border x:Name="Check"
              Width="13"
              Height="13"
              Visibility="Collapsed"
              Margin="6,0,6,0"
              BorderThickness="1">
        <Border.BorderBrush>
          <LinearGradientBrush StartPoint="0,0"
                               EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="{DynamicResource BorderLightColor}"
                              Offset="0.0" />
                <GradientStop Color="{DynamicResource BorderDarkColor}"
                              Offset="1.0" />
              </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>

        </Border.BorderBrush>
        <Border.Background>
          <LinearGradientBrush StartPoint="0,0"
                               EndPoint="0,1">
            <LinearGradientBrush.GradientStops>
              <GradientStopCollection>
                <GradientStop Color="{DynamicResource ControlLightColor}" />
                <GradientStop Color="{DynamicResource ControlMediumColor}"
                              Offset="1.0" />
              </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
          </LinearGradientBrush>
        </Border.Background>
        <Path x:Name="CheckMark"
              Width="7"
              Height="7"
              Visibility="Hidden"
              SnapsToDevicePixels="False"
              StrokeThickness="2"
              Data="M 0 0 L 7 7 M 0 7 L 7 0">
          <Path.Stroke>
            <SolidColorBrush Color="{DynamicResource GlyphColor}" />
          </Path.Stroke>
        </Path>
      </Border>
      <ContentPresenter x:Name="HeaderHost"
                        Grid.Column="1"
                        ContentSource="Header"
                        RecognizesAccessKey="True" />
      <TextBlock x:Name="InputGestureText"
                 Grid.Column="2"
                 Text="{TemplateBinding InputGestureText}"
                 Margin="5,2,0,2"
                 DockPanel.Dock="Right" />
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="ButtonBase.Command"
             Value="{x:Null}" />
    <Trigger Property="Icon"
             Value="{x:Null}">
      <Setter TargetName="Icon"
              Property="Visibility"
              Value="Hidden" />
    </Trigger>
    <Trigger Property="IsChecked"
             Value="true">
      <Setter TargetName="CheckMark"
              Property="Visibility"
              Value="Visible" />
    </Trigger>
    <Trigger Property="IsCheckable"
             Value="true">
      <Setter TargetName="Check"
              Property="Visibility"
              Value="Visible" />
      <Setter TargetName="Icon"
              Property="Visibility"
              Value="Hidden" />
    </Trigger>
    <Trigger Property="IsHighlighted"
             Value="true">
      <Setter Property="Background"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush EndPoint="0.5,1"
                               StartPoint="0.5,0">
            <GradientStop Color="Transparent"
                          Offset="0" />
            <GradientStop Color="{DynamicResource ControlMouseOverColor}"
                          Offset="1" />
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
      <Setter Property="BorderBrush"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush EndPoint="0.5,1"
                               StartPoint="0.5,0">
            <GradientStop Color="{DynamicResource BorderMediumColor}"
                          Offset="0" />
            <GradientStop Color="Transparent"
                          Offset="1" />
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger Property="IsEnabled"
             Value="false">
      <Setter Property="Foreground">
        <Setter.Value>
          <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<ControlTemplate x:Key="{x:Static MenuItem.SubmenuHeaderTemplateKey}"
                 TargetType="{x:Type MenuItem}">
  <Border x:Name="Border"
          BorderThickness="1">
    <Grid>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"
                          SharedSizeGroup="Icon" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto"
                          SharedSizeGroup="Shortcut" />
        <ColumnDefinition Width="13" />
      </Grid.ColumnDefinitions>
      <ContentPresenter x:Name="Icon"
                        Margin="6,0,6,0"
                        VerticalAlignment="Center"
                        ContentSource="Icon" />
      <ContentPresenter x:Name="HeaderHost"
                        Grid.Column="1"
                        ContentSource="Header"
                        RecognizesAccessKey="True" />
      <TextBlock x:Name="InputGestureText"
                 Grid.Column="2"
                 Text="{TemplateBinding InputGestureText}"
                 Margin="5,2,2,2"
                 DockPanel.Dock="Right" />
      <Path Grid.Column="3"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Data="M 0 0 L 0 7 L 4 3.5 Z">
        <Path.Fill>
          <SolidColorBrush Color="{DynamicResource GlyphColor}" />
        </Path.Fill>
      </Path>
      <Popup x:Name="Popup"
             Placement="Right"
             HorizontalOffset="-4"
             IsOpen="{TemplateBinding IsSubmenuOpen}"
             AllowsTransparency="True"
             Focusable="False"
             PopupAnimation="Fade">
        <Border x:Name="SubmenuBorder"
                SnapsToDevicePixels="True"
                Background="{DynamicResource MenuPopupBrush}"
                BorderThickness="1">
          <Border.BorderBrush>
            <SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
          </Border.BorderBrush>
          <ScrollViewer CanContentScroll="True"
                        Style="{StaticResource MenuScrollViewer}">
            <StackPanel IsItemsHost="True"
                        KeyboardNavigation.DirectionalNavigation="Cycle" />
          </ScrollViewer>
        </Border>
      </Popup>
    </Grid>
  </Border>
  <ControlTemplate.Triggers>
    <Trigger Property="Icon"
             Value="{x:Null}">
      <Setter TargetName="Icon"
              Property="Visibility"
              Value="Collapsed" />
    </Trigger>
    <Trigger Property="IsHighlighted"
             Value="true">
      <Setter Property="Background"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush EndPoint="0.5,1"
                               StartPoint="0.5,0">
            <GradientStop Color="Transparent"
                          Offset="0" />
            <GradientStop Color="{DynamicResource ControlMouseOverColor}"
                          Offset="1" />
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
      <Setter Property="BorderBrush"
              TargetName="Border">
        <Setter.Value>
          <LinearGradientBrush EndPoint="0.5,1"
                               StartPoint="0.5,0">
            <GradientStop Color="{DynamicResource BorderMediumColor}"
                          Offset="0" />
            <GradientStop Color="Transparent"
                          Offset="1" />
          </LinearGradientBrush>
        </Setter.Value>
      </Setter>
    </Trigger>
    <Trigger SourceName="Popup"
             Property="AllowsTransparency"
             Value="True">
      <Setter TargetName="SubmenuBorder"
              Property="CornerRadius"
              Value="4" />
      <Setter TargetName="SubmenuBorder"
              Property="Padding"
              Value="0,3,0,3" />
    </Trigger>
    <Trigger Property="IsEnabled"
             Value="false">
      <Setter Property="Foreground">
        <Setter.Value>
          <SolidColorBrush Color="{StaticResource DisabledForegroundColor}" />
        </Setter.Value>
      </Setter>
    </Trigger>
  </ControlTemplate.Triggers>
</ControlTemplate>

<!-- MenuItem Style -->
<Style x:Key="{x:Type MenuItem}"
       TargetType="{x:Type MenuItem}">
  <Setter Property="OverridesDefaultStyle"
          Value="True" />
  <Style.Triggers>
    <Trigger Property="Role"
             Value="TopLevelHeader">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.TopLevelHeaderTemplateKey}}" />
      <Setter Property="Grid.IsSharedSizeScope"
              Value="true" />
    </Trigger>
    <Trigger Property="Role"
             Value="TopLevelItem">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.TopLevelItemTemplateKey}}" />
    </Trigger>
    <Trigger Property="Role"
             Value="SubmenuHeader">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.SubmenuHeaderTemplateKey}}" />
    </Trigger>
    <Trigger Property="Role"
             Value="SubmenuItem">
      <Setter Property="Template"
              Value="{StaticResource {x:Static MenuItem.SubmenuItemTemplateKey}}" />
    </Trigger>
  </Style.Triggers>
</Style>
<!--ScrollViewer for a MenuItem-->
<MenuScrollingVisibilityConverter x:Key="MenuScrollingVisibilityConverter" />

<Style x:Key="MenuScrollViewer"
       TargetType="{x:Type ScrollViewer}"
       BasedOn="{x:Null}">
  <Setter Property="HorizontalScrollBarVisibility"
          Value="Hidden" />
  <Setter Property="VerticalScrollBarVisibility"
          Value="Auto" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ScrollViewer}">
        <Grid SnapsToDevicePixels="True">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
          <Border Grid.Row="1"
                  Grid.Column="0">
            <ScrollContentPresenter Margin="{TemplateBinding Padding}" />
          </Border>
          <RepeatButton Style="{StaticResource MenuScrollButton}"
                        Grid.Row="0"
                        Grid.Column="0"
                        Command="{x:Static ScrollBar.LineUpCommand}"
                        CommandTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
                        Focusable="False">
            <RepeatButton.Visibility>
              <MultiBinding FallbackValue="Visibility.Collapsed"
                            Converter="{StaticResource MenuScrollingVisibilityConverter}"
                            ConverterParameter="0">
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ComputedVerticalScrollBarVisibility" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="VerticalOffset" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ExtentHeight" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ViewportHeight" />
              </MultiBinding>
            </RepeatButton.Visibility>
            <Path Fill="{DynamicResource {x:Static SystemColors.MenuTextBrushKey}}"
                  Data="{StaticResource UpArrow}" />
          </RepeatButton>
          <RepeatButton Style="{StaticResource MenuScrollButton}"
                        Grid.Row="2"
                        Grid.Column="0"
                        Command="{x:Static ScrollBar.LineDownCommand}"
                        CommandTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"
                        Focusable="False">
            <RepeatButton.Visibility>
              <MultiBinding FallbackValue="Visibility.Collapsed"
                            Converter="{StaticResource MenuScrollingVisibilityConverter}"
                            ConverterParameter="100">
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ComputedVerticalScrollBarVisibility" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="VerticalOffset" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ExtentHeight" />
                <Binding RelativeSource="{RelativeSource TemplatedParent}"
                         Path="ViewportHeight" />
              </MultiBinding>
            </RepeatButton.Visibility>
            <Path Fill="{DynamicResource {x:Static SystemColors.MenuTextBrushKey}}"
                  Data="{StaticResource DownArrow}" />
          </RepeatButton>
        </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/menu-styles-and-templates?view=netframeworkdesktop-4.8 

 

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

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

docs.microsoft.com

 

반응형

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

NavigationWindow①  (0) 2022.06.11
Menu④  (0) 2022.06.09
Menu②  (0) 2022.06.07
Menu①  (0) 2022.06.03
ListView②  (0) 2022.06.01