포스트

WPF, Window Chrome Style

WPF, Window Chrome Style

제가 사용하고 있는 WindowChome Style 전체 코드를 공유합니다.
이 스타일을 Template 으로 만들어 사용하면 빠르고 예쁜 윈도우 사용이 가능합니다.

1. MainWindow.xaml

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<Window x:Class="WpfMyTemplate1.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:WpfMyTemplate1"
        
        xmlns:cv="clr-namespace:WpfMyTemplate1.Converters"
        
        WindowStyle="None"
        AllowsTransparency="True"
        Background="Transparent"
        
        mc:Ignorable="d"
        Title="{Binding Title}" Height="450" Width="800">

    <Window.Resources>
        <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>
    </Window.Resources>

    <WindowChrome.WindowChrome>
        <WindowChrome x:Name="xWindowChomre"
                      CaptionHeight="40"
                      GlassFrameThickness="0"
                      ResizeBorderThickness="16"/>
    </WindowChrome.WindowChrome>

    <Border x:Name="xOuterBorder"
            Margin="10"
            CornerRadius="10"
            Background="Transparent">

        <Border.Effect>
            <DropShadowEffect BlurRadius="10"
                              ShadowDepth="4"
                              Opacity="0.5"/>
        </Border.Effect>

        <Border x:Name="xInnerBoder"
                Background="White"
                BorderThickness="2"
                BorderBrush="#B6B6B6"
                CornerRadius="10">
            <Grid Background="Transparent">
                <Grid.RowDefinitions>
                    <RowDefinition Height="40"/>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>

                <Grid.Clip>
                    <RectangleGeometry RadiusX="{Binding Path=CornerRadius, ElementName=xInnerBoder, Converter={cv:GridRaidusClipConverter}}"
                                       RadiusY="{Binding Path=CornerRadius, ElementName=xInnerBoder, Converter={cv:GridRaidusClipConverter}}">
                        <RectangleGeometry.Rect>
                            <MultiBinding Converter="{cv:GridClipConverter}">
                                <Binding Path="ActualWidth" RelativeSource="{RelativeSource AncestorType={x:Type Grid}}"/>
                                <Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type Grid}}"/>
                            </MultiBinding>
                        </RectangleGeometry.Rect>
                    </RectangleGeometry>
                </Grid.Clip>

                <Grid Grid.Row="0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0"
                               Text="{Binding Title}"
                               VerticalAlignment="Center"
                               Margin="10 0 0 0"/>
                    <Button Grid.Column="1"
                            Style="{StaticResource ControlBoxButtonStyle}"
                            Content="🗕" 
                            Click="MinimizeButton_Click"/>
                    <Button x:Name="xMaximizeButton"
                            Grid.Column="2"
                            Style="{StaticResource ControlBoxButtonStyle}"
                            Content="🗖"
                            Click="MaximizeButton_Click"/>
                    <Button Grid.Column="3"
                            Style="{StaticResource ControlBoxButtonStyle}"
                            Content="🗙"
                            Click="ExitButton_Click"/>
                </Grid>

                <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>

                <!--Main Content-->
                <Grid Grid.Row="2">
                    
                </Grid>

            </Grid>
        </Border>
    </Border>

</Window>

2. MainWindow.xaml.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
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
67
using System.ComponentModel;
using System.Windows;
using WpfMyTemplate1.ViewModels;

namespace WpfMyTemplate1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
            {
                return;
            }
            DataContext = App.Current.Services.GetService(typeof(MainViewModel));

            MaxHeight = SystemParameters.WorkArea.Height + 7;
            StateChanged += MainWindow_StateChanged;
        }

        private void MinimizeButton_Click(object sender, RoutedEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }
        private void MaximizeButton_Click(object sender, RoutedEventArgs e)
        {
            if (WindowState == WindowState.Maximized)
            {
                WindowState = WindowState.Normal;
            }
            else
            {
                WindowState = WindowState.Maximized;
            }
        }
        private void ExitButton_Click(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void MainWindow_StateChanged(object? sender, EventArgs e)
        {
            if (WindowState == WindowState.Maximized)
            {
                xMaximizeButton.Content = "🗗";
                xOuterBorder.Margin = new Thickness(7, 0, 7, 0);
                xOuterBorder.CornerRadius = new CornerRadius(0);
                xInnerBoder.CornerRadius = new CornerRadius(0);

                xWindowChomre.ResizeBorderThickness = new Thickness(0);
            }
            else
            {
                xMaximizeButton.Content = "🗖";
                xOuterBorder.Margin = new Thickness(10);
                xOuterBorder.CornerRadius = new CornerRadius(10);
                xInnerBoder.CornerRadius = new CornerRadius(10);

                xWindowChomre.ResizeBorderThickness = new Thickness(16);
            }
        }
    }
}

3. GridCipConverter.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
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
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace WpfMyTemplate1.Converters
{
    public class GridClipConverter : MarkupExtension, IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values.Length == 2 && values[0] is double width && values[1] is double height)
            {
                return new Rect(0, 0, width, height);
            }
            return Rect.Empty;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }

    public class GridRaidusClipConverter : MarkupExtension, IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is CornerRadius radius)
            {
                if (radius == new CornerRadius())
                {
                    return 0;
                }
                else
                {
                    return 10;
                }
            }
            return 10;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    }
}
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.