WPF

[WPF] WindowChrome 와 Shadow 를 가진 창 만들기 [1/2]

Chanhongv 2024. 10. 11. 11:09

WPF 에서 기본 제공하는 WindowStyle 은 마음에 들지 않기때문에

Window Style 을 None 으로 하고 만드는 것이 일반적이다.

 

WPF 자체에서 제공하는 WindowChrome 이라는 것이 있는데, 이걸 사용하면 Title border 를 만들고 비하인드코드에서 MouseMove 이러 것을 안 만들어도 창을 움직일 수 있다.

 

Level 1. WindowChorme Style 적용

<Window x:Class="WindowChorme.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WindowChorme"
        mc:Ignorable="d"
        
        WindowStyle="None"
        AllowsTransparency="True"
        
        Title="MainWindow" Height="450" Width="800">

    <WindowChrome.WindowChrome>
        <WindowChrome CaptionHeight="40"
                      GlassFrameThickness="0"
                      CornerRadius="10"
                      ResizeBorderThickness="16"/>
    </WindowChrome.WindowChrome>
    
    <Grid>

    </Grid>
</Window>

 

WPF Application 프로젝트를 만든 후 위와 같이만 작성해도 Window Chrome Style 을 조금 적용했다고 볼 수 있다.

상세 설명은 아래와 같다.

WindowStyle="None"	// Window Style 을 Custom 하겠다는 의미
AllowsTransparency="True"	// Transparent 배경을 허용한다는 의미

<WindowChrome.WindowChrome>
    <WindowChrome CaptionHeight="40"			// 마우스 드래그로 창을 이동 시킬 수 있는 타이틀 바 범위
                  GlassFrameThickness="0"		// 0 으로 해야 CornerRadius 가 적용됨
                   CornerRadius="10"			// 테두리 가장자리들의 둥근 정도
                   ResizeBorderThickness="16"/>	// 창 크기 사이즈 조정할 수 있는 두께
</WindowChrome.WindowChrome>

 

 

하지만 아직 만족할 수 없는 스타일이다.

윈도우 탐색창에 비해 테두리도 없고 그림자도 없고 마음에 들지 않기 때문에 더 꾸며보도록 한다.

 

Level 2. 그림자 적용

<Window x:Class="WindowChorme.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WindowChorme"
        mc:Ignorable="d"
        
        WindowStyle="None"
        AllowsTransparency="True"
        Background="Transparent"
        
        Title="MainWindow" Height="450" Width="800">

    <WindowChrome.WindowChrome>
        <WindowChrome CaptionHeight="40"
                      GlassFrameThickness="0"
                      ResizeBorderThickness="16"/>
    </WindowChrome.WindowChrome>

    <Border Margin="10"
            CornerRadius="10"
            Background="Transparent">

        <Border.Effect>
            <DropShadowEffect BlurRadius="10"
                              ShadowDepth="4"
                              Opacity="0.5"/>
        </Border.Effect>
        
        <Border Background="White"
                BorderThickness="2"
                BorderBrush="#B6B6B6"
                CornerRadius="10">
            <Grid Background="Transparent">
                <!--Content-->
            </Grid>
        </Border>
    </Border>
    
</Window>

 

테두리도 생기고, 그림자도 생긴 이쁜 창이 생겼다.

여기까지만 해도 활용도가 무궁무진할 것 같다.

 

한 걸음 더 나아가서 타이틀바 밑에 그라데이션으로 줄을 그어보고 싶다.

 

Level 3. Titlebar 꾸미기

 

ControlBox Button 들도 추가하고, Titlebar 경계선도 만들겁니다.

Control Box Icon 을 특수 문자로도 사용 가능하다. 복사해서 사용하시길...!

🗕 🗖 🗗 🗙

 

Grid 의 Row 를 3개로 설정한다.

1: Title bar 에 Text, Controlbox Button 를 만든다.

<Style TargetType="{x:Type Button}" x:Key="ControlBoxButtonStyle">
    <Setter Property="Width" Value="40"/>
    <Setter Property="Cursor" Value="Hand"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border x:Name="border"
                        BorderThickness="0"
                        Background="{TemplateBinding Background}"> 
                    <TextBlock Text="{TemplateBinding Content}"
                               VerticalAlignment="Center"
                               HorizontalAlignment="Center"
                               TextAlignment="Center"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="#EFEFEF"/>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsMouseOver" Value="True"/>
                            <Condition Property="Content" Value="🗙"/>
                        </MultiTrigger.Conditions>
                        <Setter TargetName="border" Property="CornerRadius" Value="0 10 0 0"/>
                        <Setter Property="Background" Value="#FF0000"/>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Grid Grid.Row="0">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0"
               Text="Window Chorme Style Test"
               VerticalAlignment="Center"
               Margin="10 0 0 0"/>
    <Button Grid.Column="1"
            Style="{StaticResource ControlBoxButtonStyle}"
            Content="🗕"/>
    <Button Grid.Column="2"
            Style="{StaticResource ControlBoxButtonStyle}"
            Content="🗖"/>
    <Button Grid.Column="3"
            Style="{StaticResource ControlBoxButtonStyle}"
            Content="🗙"/>
</Grid>

2: 경계선을 만든다.

  <Border Grid.Row="1" Height="6" BorderThickness="0 0.2 0 0">
      <Border.BorderBrush>
          <LinearGradientBrush StartPoint="0,0" EndPoint="1, 0">
              <GradientStop Color="#FFFFFF" Offset="0.0" />
              <GradientStop Color="#686868" Offset="0.5" />
              <GradientStop Color="#FFFFFF" Offset="1.0" />
          </LinearGradientBrush>
      </Border.BorderBrush>

      <Border.Background>
          <LinearGradientBrush StartPoint="0,0" EndPoint="0, 1">
              <GradientStop Color="#FAFAFA" Offset="0.0" />
              <GradientStop Color="#FFFFFF" Offset="1.0" />
          </LinearGradientBrush>
      </Border.Background>
  </Border>

3: Main Content

 

그럼 다음 사진과 같이 이쁘게 만들어진다.

기본 모양은 다 만들었다.

이제 해야하는 부분은...

 1. ControlBox 기능 만들기

 2. 최대화버튼 시 스타일 조정하기.

 - 최대화시 화면이 맞지 않는 부분이 있다.

 

다음 포스팅에 이어가도록하자.