Форум программистов, компьютерный форум, киберфорум
Nord790
Войти
Регистрация
Восстановить пароль
Оценить эту запись

C# WPF Не стандартное окно с применением стиля в проекте Приложение WPF.

Запись от Nord790 размещена 28.06.2021 в 00:18
Метки c#, netframework, wpf

В этой записи я расскажу, как сделать не стандартное окно с применением стиля в проекте Приложение WPF.
Создадим проект в Visual Studio Приложение WPF.
После того, как у нас сформировался проект, создадим папку в обозревателе решений и назовем Style и в ней же создадим еще папку под именем Window, и в ней добавим файл Словарь ресурсов (WPF). Далее жмем ПКМ>Добавить>Словарь ресурсов (WPF)... и присваиваем ему имя WindowStyle.xaml.
Теперь к этому документу нужно привязать код, для этого в папке Style\Window добавляем Класс и называем его WindowStyle.cs, и установить класс partial. Открываем файл WindowStyle.xaml и в теге ResourceDictionary добавляем атрибут x:Class="Project.Style.Window.WindowStyle".

Файл WindowStyle.xaml - это конструктор для визуального отображения стиля, где будут описываться все визуальные эффекты, объекты, анимация и много другое.
Файл WindowStyle.cs - это наш функционал, где мы будем описывать все задачи связанные с работой кнопок Закрыть, Развернуть, Минимизировать и т.д.

Приступим к написанию конструктора стиля, открываем файл WindowStyle.xaml, в теге ResourceDictionary, добавляем следующий тег:
XML
1
<Style x:Key="WindowStyle" TargetType="{x:Type Window}"></Style>
Сбрасываем следующие параметры окна:
XML
1
2
3
4
5
<Style x:Key="WindowStyle" TargetType="{x:Type Window}">
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="Background" Value="Transparent"/>
</Style>
Далее мы присвоим к окну параметр WindowChrome, он позволит расширить содержимое в неклиентскую область окна. Т.е. даст нам возможность расширять, разворачивать и сворачивать окно без всяких дополнительных написаний команд.
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome
                    NonClientFrameEdges="None"
                    GlassFrameThickness="0"
                    ResizeBorderThickness="7"
                    CaptionHeight="36"
                />
            </Setter.Value>
        </Setter>
    </Style>
Кликните здесь для просмотра всего текста
NonClientFrameEdges = "None" - Получает или задает значение, указывающее, какие границы рамки окна не принадлежат клиенту.
GlassFrameThickness="0" - Получает или задает значение, указывающее ширину стеклянной границы окна.
ResizeBorderThickness="7" - Получает или задает значение, указывающее ширину границы для изменения размера окна.
CaptionHeight="36" - Получает или задает высоту области названия в верхней части окна.


После этого начнем размещать визуальные элементы на форме, для этого добавим следующие сеттер:

XML
1
2
3
4
5
6
<Setter Property="Template">
  <Setter.Value>
    <ControlTemplate TargetType="{x:Type Window}">
    </ControlTemplate>
  </Setter.Value>
</Setter>
В ControlTemplate добавляем элемент Border и присваиваем ему параметры x:Name="PART_Container" Padding="7", этот элемент будет в роли контейнера.

XML
1
2
3
4
<ControlTemplate TargetType="{x:Type Window}">
   <Border x:Name="PART_Container" Padding="7">
   </Border>
</ControlTemplate>
Добавим эффект тени
XML
1
2
3
<Border.Effect>
  <DropShadowEffect Color="Black" Opacity="0.4" BlurRadius="10" ShadowDepth="0" Direction="0"/>
</Border.Effect>
В PART_Container добавим еще один элемент Border, он будет в роли границы.
XML
1
2
3
4
5
<Border x:Name="PART_Container" Padding="7">
  <Border x:Name="PART_Border" Background="White" BorderBrush="#FFAAAAAA" BorderThickness="1">
                            
  </Border>
</Border>
В PART_Border разместите элемент Grid, на нем и будут размещаться элементы окна.
XML
1
2
3
4
5
<Border x:Name="PART_Border" Background="White" BorderBrush="#FFAAAAAA" BorderThickness="1">
 <Grid x:Name="PART_Content">
                                
 </Grid>
</Border>
Теперь сделаем шапку, в которой будут размещены иконка приложения, кнопки и заголовок, для этого добавляем строку в PART_Content с высотой на 36.
XML
1
2
3
4
5
6
<Grid x:Name="PART_Content">
  <Grid.RowDefinitions>
    <RowDefinition Height="36"/>
    <RowDefinition/>
  </Grid.RowDefinitions>
</Grid>
В PART_Content добавьте элемент StackPanel и установите для него выравнивание по горизонтали с право, а по вертикале растянуть, ориентация по горизонтали, и расположение элементов с право на лево.
XML
1
2
3
4
5
6
7
8
<Grid x:Name="PART_Content">
  <Grid.RowDefinitions>
    <RowDefinition Height="36"/>
    <RowDefinition/>
  </Grid.RowDefinitions>
  <StackPanel HorizontalAlignment="Right" VerticalAlignment="Stretch" Orientation="Horizontal" FlowDirection="RightToLeft" WindowChrome.IsHitTestVisibleInChrome="True">
  </StackPanel>
</Grid>
Перед тем как добавить кнопки управления окном, нужно добавить стиль для этих кнопок. Возвращаемся к ControlTempate, и добавляем в него ControlTemplate.Resources
XML
1
2
3
4
5
6
<ControlTemplate TargetType="{x:Type Window}">
  <!--PART_Container-->
  <ControlTemplate.Resources>
                        
  </ControlTemplate.Resources>
</ControlTemplate>
И добавляем в него следующие стили для кнопок. P.S. Описание работы конструктора внутри.
Кликните здесь для просмотра всего текста

Кнопка "Закрыть"
XML
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
                        <!--Делаем все также, как и при создании стиля для Window, указываем только другой тип.-->
                        <Style x:Key="CloseButton" TargetType="{x:Type Button}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type Button}">
                                        <!--Grid нам нужен для того чтобы разместить в нем визуальные элементы-->
                                        <Grid>
                                            <!--Добавляем Rectangle c округленным краями-->
                                            <Rectangle x:Name="CloseButton_Rect" Fill="Transparent" RadiusX="6" RadiusY="6" SnapsToDevicePixels="True"/>
                                            <!--ContentPresenter нужен для отображения элементов расположенных на самом родительском элементе-->
                                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                                        </Grid>
                                        <!--Тригеры нужны для оживления кнопки-->
                                        <ControlTemplate.Triggers>
                                            <!--EventTrigger определяет анимацию и, если событие происходит, запускает ее на выполнение-->
                                            <!--Действие при наведении мыши на кнопку-->
                                            <EventTrigger RoutedEvent="Mouse.MouseEnter">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <!--Меняем цвет фона-->
                                                            <ColorAnimation Duration="0:0:0.1"  Storyboard.TargetName="CloseButton_Rect" Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" To="#ff4d4d"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <!--Меняем цвет текста-->
                                                            <ColorAnimation Duration="0:0:0.1" Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="White"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                            <!--Действие при нажатии на кнопку-->
                                            <EventTrigger RoutedEvent="Button.Click">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <!--CloseButton_Rect эффект Push-->
                                                            <ThicknessAnimation Duration="0:0:0.1"  Storyboard.TargetName="CloseButton_Rect"  Storyboard.TargetProperty="Margin"  From="0" To="4" AutoReverse="True"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                            <!--Действие при отводе мыши от кнопки-->
                                            <EventTrigger RoutedEvent="Mouse.MouseLeave">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <!--Меняем цвет фона-->
                                                            <ColorAnimation Duration="0:0:0.1"  Storyboard.TargetName="CloseButton_Rect" Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" To="Transparent"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <!--Меняем цвет текста-->
                                                            <ColorAnimation Duration="0:0:0.1"  Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)" To="Black"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
Остальные кнопки
XML
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
<Style x:Key="CaptionButton" TargetType="{x:Type Button}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type Button}">
                                        <Grid>
                                            <Rectangle x:Name="CaptionButton_Rect" Fill="White" RadiusX="6" RadiusY="6" SnapsToDevicePixels="True"/>
                                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="True"/>
                                        </Grid>
                                        <ControlTemplate.Triggers>
                                            <EventTrigger RoutedEvent="Mouse.MouseEnter">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <ColorAnimation Duration="0:0:0.1"  Storyboard.TargetName="CaptionButton_Rect" Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" To="#e5e5e5"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                            <EventTrigger RoutedEvent="Button.Click">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <ThicknessAnimation Duration="0:0:0.1"  Storyboard.TargetName="CaptionButton_Rect"  Storyboard.TargetProperty="Margin" From="0" To="4" AutoReverse="True"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                            <EventTrigger RoutedEvent="Mouse.MouseLeave">
                                                <EventTrigger.Actions>
                                                    <BeginStoryboard>
                                                        <Storyboard>
                                                            <ColorAnimation Duration="0:0:0.1"  Storyboard.TargetName="CaptionButton_Rect" Storyboard.TargetProperty="Fill.(SolidColorBrush.Color)" To="Transparent"/>
                                                        </Storyboard>
                                                    </BeginStoryboard>
                                                </EventTrigger.Actions>
                                            </EventTrigger>
                                        </ControlTemplate.Triggers>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
</Style>

Теперь вернемся обратно и добавим три кнопки это Свернуть, Развернуть/Восстановить и Закрыть.
В StackPanel добавляем три кнопки и присваиваем к ним стили.
XML
1
2
3
<Button x:Name="CloseButton" Content="r" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="4,0,2,0" Style="{DynamicResource CloseButton}"/>
<Button x:Name="MaxRestoreButton" Content="1" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="2,0,2,0" Style="{DynamicResource CaptionButton}"/>
<Button x:Name="MinimizeButton" Content="0" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="2,0,2,0" Style="{DynamicResource CaptionButton}"/>
Теперь разместим заголовок окна. В Grid PART_Content добавьте TextBlock
XML
1
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Title}"/>
Если хотите добавить иконку приложения, то добавьте в Gird PART_Content элемент Image
XML
1
<Image Source="{TemplateBinding Icon}" HorizontalAlignment="Left" VerticalAlignment="Center" Width="16" Height="16" Margin="6,0,0,0"/>
Теперь нужно разместить все элементы которые расположены в родительском окне. Для этого нужно добавить ContentPresenter в Gird PART_Content
XML
1
<ContentPresenter Grid.Row="1"/>
В принципе стиль готов, но кнопки еще не работают, для этого для каждой кнопки указываем событие Click
XML
1
2
3
4
5
6
<Button x:Name="CloseButton" Content="r" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="6,0,2,0" Style="{DynamicResource CloseButton}"
Click="CloseButton_Click"/>
<Button x:Name="MaxRestoreButton" Content="1" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="2,0,2,0" Style="{DynamicResource CaptionButton}"
Click="MaxRestoreButton_Click"/>
<Button x:Name="MinimizeButton" Content="0" FontFamily="Webdings" Foreground="Black" Width="26" Height="28" Margin="2,0,2,0" Style="{DynamicResource CaptionButton}"
Click="MinimizeButton_Click"/>
Теперь нужно сделать так, чтобы при разворачивание и восстановлении окна менялась кнопка Развернуть\Восстановить, делаем следующее, переходим на тег Style в файле WindowStyle.xaml, добавляем EventSetter.
XML
1
<EventSetter Event="Loaded" Handler="Window_Loaded"/>
C#
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
 
namespace Project.Style.Window {
    partial class WindowStyle {
 
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            (sender as System.Windows.Window).StateChanged += Window_StateChanged;
        }
 
        private void Window_StateChanged(object sender, EventArgs e) {
            System.Windows.Window me = (sender as System.Windows.Window);
            Button maximizeCaptionButton = me.Template.FindName("MaxRestoreButton", me) as Button;
            if (maximizeCaptionButton is not null) {
                maximizeCaptionButton.Content = me.WindowState == WindowState.Maximized ? "2" : "1";
            }
        }
 
        private void CloseButton_Click(object sender, RoutedEventArgs e) {
            ((sender as FrameworkElement).TemplatedParent as System.Windows.Window).Close();
        }
 
        private void MaxRestoreButton_Click(object sender, RoutedEventArgs e) {
            ((sender as FrameworkElement).TemplatedParent as System.Windows.Window)
                .WindowState = (((sender as FrameworkElement).TemplatedParent as System.Windows.Window)
                .WindowState == WindowState.Normal) ? WindowState.Maximized : WindowState.Normal;
        }
 
        private void MinimizeButton_Click(object sender, RoutedEventArgs e) {
            ((sender as FrameworkElement).TemplatedParent as System.Windows.Window)
                .WindowState = WindowState.Minimized;
        }
    }
}
Стиль готов, теперь его нужно разместить, делаем следующее открываем App.xaml и в Application.Resources добавляем
XML
1
2
3
4
5
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Style\Window\WindowStyle.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
Открываем наше окно, выбираем Window, жмем ПКМ>Правка шаблона>Применить ресурс>

Запускам проект и получаем вот такое окно.

Если захотелось добавить еще дополнительную конку в шапку заголовка и в стиле таких же кнопок, то вот код.
C#
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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Shell;
 
namespace Project {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
 
        //Создадим StackPanel для размещение дополнительных кнопок, и разместим его по левому краю.
        StackPanel stackPanelButtons = new StackPanel() {
            HorizontalAlignment = HorizontalAlignment.Left,
            VerticalAlignment = VerticalAlignment.Stretch,
            Orientation = Orientation.Horizontal,
            Margin = new Thickness(4, 0, 0, 0)
        };
        //Дополнительная кнопка.
        Button infoButton = new Button() {
            Width = 26,
            Height = 28,
            Content = "i",
            FontFamily = new FontFamily("Webdings")
        };
 
        public MainWindow() {
            InitializeComponent();
        }
 
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            infoButton.Click += InfoButton_Click; //Устанавливем событие Click
            infoButton.Style = Template.Resources["CaptionButton"] as System.Windows.Style; //Установливаем стиль CaptionButton
            stackPanelButtons.Children.Add(infoButton); //Добавляем кнопку в StackPanel
 
 
            Grid PART_Content = Template.FindName("PART_Content", this) as Grid; //Ищем элемент PART_Content в текущем стиле
            WindowChrome.SetIsHitTestVisibleInChrome(stackPanelButtons, true); //Не забываем про WindowChrome
            PART_Content.Children.Add(stackPanelButtons); // Добавляем StackPanel в PART_Content;
 
        }
 
        private void InfoButton_Click(object sender, RoutedEventArgs e) {
            MessageBox.Show("Эта кнопак была создана динамически и добавлена в шапку загаловка данного окна.");
        }
    }
}
Вложения
Тип файла: zip Project.zip (224.2 Кб, 409 просмотров)
Размещено в C# Исходники
Показов 604 Комментарии 0
Всего комментариев 0
Комментарии
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.