ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • WPF 최소화 최대화 종료 버튼 만들기
    C#/WPF 2018. 4. 27. 11:00

    윈도우 프로그램들은 기본적으로 가지고 있는 ㅡㅁX 버튼이 있습니다.


    이 버튼을 임의적으로 구현해야 할 때가 있습니다. (Custom Title Bar)


    사실 기능을 구현하는 것보다 버튼을 그리는 것이 더 복잡..합니다.



    먼저 기능을 구현하는 부분입니다. .cs 파일에 추가해 주시면 됩니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    private void Maximize_Click(object sender, RoutedEventArgs e)
    {
        this.WindowState = (this.WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
    }
     
    private void Close_Click(object sender, RoutedEventArgs e)
    {
        this.Close();
    }
     
    private void Mimimize_Click(object sender, RoutedEventArgs e)
    {
        this.WindowState = WindowState.Minimized;
    }
     
    private void Window_StateChanged(object sender, EventArgs e)
    {
        if (this.WindowState == WindowState.Maximized)
        {
            rectMax.Visibility = Visibility.Hidden;
            rectMin.Visibility = Visibility.Visible;
        }
        else
        {
            rectMax.Visibility = Visibility.Visible;
            rectMin.Visibility = Visibility.Hidden;
        }
    }
    cs


    기능은 기본적인 Window에 있는 내용을 다루기 때문에 짧습니다.


    각 함수들은 각각 버튼의 Click Event Handler가 됩니다.



    Window_StateChanged 함수는 최대화 버튼이 윈도우의 상태에 따라 모양이 변하기 때문에 바꾸어 주기 위해 필요합니다.





    이제 각 버튼을 XAML을 통해 구현하는데, 총 코드를 쓴 뒤 부분부분 설명하겠습니다.


    별도의 Image 파일을 사용하지 않고 구현하기 위해 Canvas, Rectangle등을 사용했습니다.


    전체 코드 입니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    <Grid HorizontalAlignment="Right" Background="White">
        <Grid.Resources>
            <Style TargetType="{x:Type Button}" x:Key="systemButton">
                <Setter Property="Padding" Value="0"/>
                <Setter Property="Width" Value="35"/>
                <Setter Property="Height" Value="25"/>
                <Setter Property="HorizontalAlignment" Value="Right"/>
                <Setter Property="VerticalAlignment" Value="Top"/>
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type Button}">
                            <Border Background="{TemplateBinding Background}"  BorderThickness="0">
                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="Button.IsMouseOver" Value="True">
                        <Setter Property="Button.Background" Value="LightGray" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <Button Click="Close_Click">
            <Button.Style>
                <Style TargetType="Button" BasedOn="{StaticResource systemButton}">
                    <Style.Triggers>
                        <Trigger Property="Button.IsMouseOver" Value="True">
                            <Setter Property="Button.Background" Value="Red" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
            <Canvas Height="25" Width="35">
                <Line    
                    X1="12" Y1="8" 
                    X2="22" Y2="18"    
                    Stroke="Black" StrokeThickness="0.75"/>
                <Line    
                    X1="12" Y1="18"    
                    X2="22" Y2="8"  
                    Stroke="Black" StrokeThickness="0.75"/>
            </Canvas>
        </Button>
        <Button Margin="0,0,35,0" Click="Maximize_Click"  Style="{DynamicResource systemButton}">
            <Grid>
                <Rectangle Name="rectMax" Width="11" Height="11"
                        Stroke="Black"
                        StrokeThickness="0.75"/>
                <Canvas Name="rectMin"  Visibility="Hidden">
                    <Polyline Points="2.375,2 2.375,0.375 10.625,0.375 10.625,8.625 9,8.625"
                                StrokeThickness="0.75" Stroke="Black"/>                                    
                    <Rectangle Width="9" Height="9"
                        Stroke="Black"
                        StrokeThickness="0.75" Margin="0,2,2,0"/>                
                </Canvas>
            </Grid>
        </Button>
        <Button Margin="0,0,70,0" Click="Mimimize_Click"  Style="{DynamicResource systemButton}">
            <Rectangle Width="11"
                        Stroke="Black"
                        StrokeThickness="0.75"/>
        </Button>
    </Grid>
    cs



    세 버튼을 모아놓기 위해 Grid 안에 넣었습니다.





    먼저 버튼의 크기와 내용, 배경, 정렬, Trigger 설정 등을 설정하기 위해 Resources에 Style을 추가합니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <Grid.Resources>
        <Style TargetType="{x:Type Button}" x:Key="systemButton">
            <Setter Property="Padding" Value="0"/>
            <Setter Property="Width" Value="35"/>
            <Setter Property="Height" Value="25"/>
            <Setter Property="HorizontalAlignment" Value="Right"/>
            <Setter Property="VerticalAlignment" Value="Top"/>
            <Setter Property="Background" Value="Transparent"/>

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Background="{TemplateBinding Background}"  BorderThickness="0">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

            <Style.Triggers>
                <Trigger Property="Button.IsMouseOver" Value="True">
                    <Setter Property="Button.Background" Value="LightGray" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </Grid.Resources>
    cs



    Template, Trigger 설정을 제외하고는 기본적인 설정입니다.


    Template 설정을 하는 이유는 Trigger 설정을 변경하기 위해서는 Template을 만져주어야 Trigger가 반영되기 때문입니다.



    Trigger는 버튼에 마우스를 올렸을 때의 버튼의 바탕색을 바꾸기 위해 추가해 줍니다.





    닫기 버튼 입니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <Button Click="Close_Click">
        <Button.Style>
            <Style TargetType="Button" BasedOn="{StaticResource systemButton}">
                <Style.Triggers>
                    <Trigger Property="Button.IsMouseOver" Value="True">
                        <Setter Property="Button.Background" Value="Red" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        <Canvas Height="25" Width="35">
            <Line    
                X1="12" Y1="8" 
                X2="22" Y2="18"    
                Stroke="Black" StrokeThickness="0.75"/>
            <Line    
                X1="12" Y1="18"    
                X2="22" Y2="8"  
                Stroke="Black" StrokeThickness="0.75"/>
        </Canvas>
    </Button>
    cs



    위에서 지정한 Style을 바탕으로 닫기 버튼은 마우스를 올렸을 때 빨간색으로 바뀌기 때문에 Style을 편집해 줍니다.


    X자를 그리기 위해 Canvas를 Content로 놓은 뒤 Line 2개를 통해 X를 그려줍니다.





    Maximize 버튼입니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <Button Margin="0,0,35,0" Click="Maximize_Click"  Style="{DynamicResource systemButton}">
        <Grid>
            <Rectangle Name="rectMax" Width="11" Height="11"
                    Stroke="Black"
                    StrokeThickness="0.75"/>
            <Canvas Name="rectMin"  Visibility="Hidden">
                <Polyline Points="2.375,2 2.375,0.375 10.625,0.375 10.625,8.625 9,8.625"
                            StrokeThickness="0.75" Stroke="Black"/>                                    
                <Rectangle Width="9" Height="9"
                    Stroke="Black"
                    StrokeThickness="0.75" Margin="0,2,2,0"/>                
            </Canvas>
        </Grid>
    </Button>
    cs



    기본적인 Button Style에서 변경할 내용은 없습니다.


    ㅁ을 그리기 위해 Content로 Rectangle을 그리고, 그 위에 겹쳐서 Canvas를 통해 ㅁ이 2개 겹친 모양()을 그립니다. 


    Rectangle과 Polyline을 통해 그려주며 두께가 0.75여야 실제 프로그램에서 선이 매끄럽게 나옵니다.


    Maximize와 Normal때마다 버튼의 모양이 바뀌기 때문에 Visibility를 설정해줍니다.



    그리고 이 Visibility를 바꾸어 주는 함수가 필요합니다.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private void Window_StateChanged(object sender, EventArgs e)
    {
        if (this.WindowState == WindowState.Maximized)
        {
            rectMax.Visibility = Visibility.Hidden;
            rectMin.Visibility = Visibility.Visible;
        }
        else
        {
            rectMax.Visibility = Visibility.Visible;
            rectMin.Visibility = Visibility.Hidden;
        }
    }
    cs


    Window에서 StateChanged Event Handler이며 StateChanged Event에 추가해 놓으시면 됩니다.





    Minimize 버튼 입니다.


    1
    2
    3
    4
    5
    <Button Margin="0,0,70,0" Click="Mimimize_Click"  Style="{DynamicResource systemButton}">
        <Rectangle Width="11"
                    Stroke="Black"
                    StrokeThickness="0.75"/>
    </Button>
    cs



    마찬가지로 Style을 바꿀 필요는 없으며 Rectangle을 Height가 없게 하여 ㅡ를 구현했습니다.





    Margin을 넣은 이유는 Grid에 버튼 3개를 넣었기 때문에 위치를 조정해주기 위해서인데,

    StackPanel 등을 사용하시고 Margin을 지우셔도 됩니다.



    결국 이런 버튼을 쓰는 곳은 Title Bar를 만들기 위해서가 가장 많을 것 같습니다... (WPF Window Title Bar 만들기)

    댓글

GiGong