WPF фигурные окна приложений

Все исходники /  Язык программирования C# /  OS Windows /  Desktop /  WPF программирование / WPF фигурные окна приложений

Заголовок

Windows Presentation Foundation (WPF) - это рекомендуемая платформа для пользовательского интерфейса приложений Windows, позволяющая использовать все преимущества современного графического оборудования.

Среди многочисленных графических возможностей WPF - создание приложений с непрямоугольными окнами. Фигурные окна используются для создания, например: splash-заставок, анимационных картинок или текстовых оповещений поверх всех окон на дисплее. WPF позволяет использовать для создания фигурных окон разнообразную геометрию, полупрозрачные и прозрачные изображения, символы текста визуальных элементов управления.

Исходники приложений с непрямоугольной формой окон

Статья описывает исходники приложений имеющих сложные фигурные формы окон. Первое приложение использует для формирования контура окна несколько геометрических фигур. Второе приложение динамично изменяет форму окна, создавая анимацию изящного передвижения самой быстрой кошки планеты. Третье приложение не менее интересно - выводит окно в форме текста поверх всех окон Windows. На основе данных исходников возможно написание прикладных программ и игр.

Условия для создания окон фигурной формы

Для создания окон произвольных форм необходимо присвоить некоторым свойствам класса Window определенные значения: установить стиль окна без рамки, разрешить клиентской части становится прозрачной, и конечно же, задний фон окна установить прозрачным.

Суть создания различных форм окон приложений на платформе WPF - сделать само окно прозрачным, но размещаемые на нём элементы оставить видимыми. В результате окно приложения может принимать самые витиеватые формы на основе своих дочерних элементов.

Настройка свойств для прозрачности окна в разметке XAML:

<Window 
	. . .
	Background="#000000FF" 
	WindowStyle="None" 
	AllowsTransparency="True" . . .>
   . . .
</Window>

Фигурное окно на классе Shape

Windows окно виде эллипса, ромба, треугольника

Непрямоугольные окна первого приложения построены на геометрических фигурах базового класса Shape. Окно в форме эллипса плавно перетекает в форму ромба и далее окно становится треугольным.

Классы Ellipse и Polygon в своей классовой иерархии являются еще и наследниками класса FrameworkElement и потому их можно помещать непосредственно в главный контейнер при помощи минимального программного кода.

XAML файл внешнего вида приложения демонстрации фигурных форм окна:

<Window x:Class="WpfFigureWindows.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:WpfFigureWindows"
        mc:Ignorable="d"
        Title="FigureWindow" Height="400" Width="800" 
		Background="#000000FF" WindowStyle="None" 
		AllowsTransparency="True" Topmost="True" 
		MouseDown="Window_MouseDown" 
		MouseMove="Window_MouseMove" 
		MouseUp="Window_MouseUp">

    <Grid>
        <Ellipse x:Name="MyEllipse" Stretch="Fill"  Fill="#FFDADA14" Stroke="#FF150BF3" StrokeThickness="10"/>

        <Polygon x:Name="PolyRhombus" Stretch="Fill" Fill="Chocolate" Stroke="#FF25A04D" StrokeThickness="10">
            <Polygon.Points>
                <Point X="400" Y="0"/>
                <Point X="800" Y="200"/>
                <Point X="400" Y="400"/>
                <Point X="0" Y="200"/>
            </Polygon.Points>
        </Polygon>

        <Polygon x:Name="PolyTriangle" Stretch="Fill" Fill="Indigo" Stroke="Olive" StrokeThickness="10">
            <Polygon.Points>
                <Point X="400" Y="0"/>
                <Point X="800" Y="400"/>
                <Point X="0" Y="400"/>
            </Polygon.Points>
        </Polygon>
    </Grid>
</Window>

Плавное изменение форм окна реализовано программным способом. Анимация инкремента и декремента прозрачности фигур построена на событиях таймера DispatcherTimer. Плавное исчезание одного элемента происходит синхронно с увеличением видимости другого, обеспечивая динамичную смену форм окна приложения.

Программный код реализации синхронного изменения прозрачности элементов формы окна:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // Предварительно скрываем фигуры окна.
        MyEllipse.Opacity = 0;
        PolyRhombus.Opacity = 0;
        PolyTriangle.Opacity = 0;

        // Настройка работы таймера анимации.
        DispatcherTimer timer = new()
        {
            Interval = TimeSpan.FromSeconds(0.03)
        };
        timer.Tick += Timer_Tick;
        timer.Start();
    }

    // Управление изменениями фигуры окна приложения.
    double counterOpacity = 1;
    int counterElement = 1;
    private void Timer_Tick(object? sender, EventArgs e)
    {
        counterOpacity -= 0.005;

        switch (counterElement)
        {
            case 1:
                // Эллипс плавно исчезает
                MyEllipse.Opacity = counterOpacity;
                // Ромб плавно появляется
                PolyRhombus.Opacity = 1 - counterOpacity;
                break;
            case 2:
                // Далее: ромб плавно исчезает
                PolyRhombus.Opacity = counterOpacity;
                // Плавно появляется треугольник
                PolyTriangle.Opacity = 1 - counterOpacity;
                break;
            case 3:
                // Треугольник плавно исчезает
                PolyTriangle.Opacity = counterOpacity;
                // Эллипс плавно появляется.
                MyEllipse.Opacity = 1 - counterOpacity;
                break;
        }

        // Строки обеспечения цикла изменения фигуры окна приложения.
        if (counterOpacity <= 0)
        {
            _ = counterElement == 3 ? counterElement = 1 : counterElement++;
            counterOpacity = 1;
        }
    }
}

Непрямоугольное окно на классе Image

Окно приложения в виде анимации бега гепарда

Класс Image библиотеки WPF позволяет отображать изображения различных типов: .bmp, .gif, ICO, .jpg, .png, WDP и TIFF. Изображение загружается в элемент управления Image посредством свойства Image.Source. Меняя источники изображений для этого свойства, можно создавать различные формы окна приложения. В следующем примере непрямоугольного окна для создания формы используется последовательность картинок, создающих анимацию бега гепарда. Получается такая вот анимационная форма окна приложения.

Загрузка картинок и анимация созданы полностью программным методом. Файл разметки приложения XAML содержит только минимальный набор кода создания прозрачного окна. В исходном коде файла XAML показанном ниже, содержится только определение свойств окна и главный контейнер, рабочий код поочередного показа картинок находится в программном модуле. Файл XAML определения окна приложения:

<Window x:Class="WpfTextWindows.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:WpfTextWindows"
        mc:Ignorable="d"
        Title="FigureWindow" Height="200" Width="300" 
        Background="#000000FF" WindowStyle="None" 
        AllowsTransparency="True" Topmost="True" 
        MouseDown="Window_MouseDown" MouseMove="Window_MouseMove" 
        MouseUp="Window_MouseUp">

    <Grid x:Name="mainGrid"></Grid>

</Window>

Создание анимации серии картинок происходит в цикле. Для возможности циклического наполнения объекта анимации пути к файлам картинок объединены в массив string[]. В качестве объекта анимации используется экземпляр класса ObjectAnimationUsingKeyFrames.

Суть работы анимации. В ObjectAnimationUsingKeyFrames, в качестве ключевых кадров (DiscreteObjectKeyFrame) загружаются источники изображений для элемента управления Image. Для каждого ключевого кадра определяется время, когда его значение (DiscreteObjectKeyFrame.Value) становится выходным объекта анимации. Переключением от кадра к кадру визуально изменяется форма окна приложения. Если в качестве изображений выбрать покадровые картинки, на экране дисплея поверх всех окон создаётся иллюзия движения.

Программный код анимации использует внешние картинки и построен так, что можно легко создавать новые анимации с другим количеством кадров-изображений.

public partial class MainWindow : Window
{
    // Количество кадров картинок фигуры окна.
    readonly int numberFrames = 0;
    // Расположение картинок для обеспечения 
    // анимационного изменения фигуры окна.
    readonly string[] uriSources = {
        "anim-1.png",
        "anim-2.png", "anim-3.png", "anim-4.png",
        "anim-5.png", "anim-6.png"
    };

    public MainWindow()
    {
        InitializeComponent();

        numberFrames = uriSources.Length;

        Animation();
    }

    private void Animation()
    {
        ObjectAnimationUsingKeyFrames objectAnimation = new()
        {   
            // Общее время анимации.
            Duration = new Duration(TimeSpan.FromSeconds(1.2)),
            RepeatBehavior = RepeatBehavior.Forever
        };

        for (int i = 0; i < numberFrames; i++)
        {  
            // Распределение времени для каждой картинки-кадра.
            double quota = (double)i / numberFrames;

            objectAnimation.KeyFrames.Add(
                new DiscreteObjectKeyFrame()
                {
                    // Установка картинки текущего кадра.
                    Value = new BitmapImage(new Uri(uriSources[i], UriKind.Relative)),
                    // Время запуска кадра.
                    KeyTime = KeyTime.FromPercent(quota)
                }
            );
        }

        System.Windows.Controls.Image image = new()
        {
            Margin = new Thickness(0, 0, 0, 0)
        };
        // Добавление изображения-контейнера для картинок
       // в состав родительской панели.
        mainGrid.Children.Add(image);
        // Запуск анимации.
        image.BeginAnimation(System.Windows.Controls.Image.SourceProperty, objectAnimation);
    }
}

Форма окна в виде текста

Форма окна приложения в виде текста

На платформе WPF просто создать окно с формой в виде текста. Таким способом можно выводить текстовые надписи поверх всех окон на дисплее.

Третий исходник содержит программный код отображения окна в виде текста для операционной системы Windows. Форму окна определяет элемент вывода надписи Label. Для повышения занимательности текстовой формы окна вывод символов происходит в виде анимации.

Элемент управления Label и его свойства определяются в XAML файле приложения. Управление символами происходит в программном коде класса окна. Ниже показана полная XAML разметка приложения:

<Window x:Class="WpfTextWindows.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:WpfTextWindows"
        mc:Ignorable="d"
        Title="FigureWindow" Height="500" Width="600" Background="#000000FF" 
		WindowStyle="None" AllowsTransparency="True" Topmost="True" 
		MouseDown="Window_MouseDown" MouseMove="Window_MouseMove" 
		MouseUp="Window_MouseUp">
    <Grid>
        <Label Name="label1" Visibility="Visible" Content="Hello World!" 
            FontSize="70" FontFamily="Times New Roman" 
            HorizontalAlignment="Center" VerticalAlignment="Center" 
            FontWeight="Bold" ClipToBounds="True" 
            Background="{x:Null}" >
            <Label.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFF70707"/>
                    <GradientStop Color="#FFF0F10D" Offset="1"/>
                </LinearGradientBrush>
            </Label.Foreground>
            <Label.Effect>
                <DropShadowEffect Color="#FFF9F3F3" BlurRadius="5" RenderingBias="Performance" ShadowDepth="2"/>
            </Label.Effect>
        </Label>
    </Grid>
</Window>

Строка текста выводится посимвольно в событии таймера. После вывода полной строки текст исчезает и процесс вывода символов начинается заново. Когда появляется текст его можно захватить курсором мыши и перемещать по экрану монитора. Фон элемента Label определен прозрачным, видимостью обладают только символы.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DispatcherTimer timer = new()
        {
            Interval = TimeSpan.FromSeconds(0.5)
        };
        timer.Tick += Timer_Tick;
        timer.Start();
    }

    readonly string hw = "Hello World!";
    int counter = 0;
    string temp = "";
    private void Timer_Tick(object? sender, EventArgs e)
    {
        // Циклически собираем полный текст по одному символу.
        temp += hw[counter];

        label1.Content = temp;

        counter++;
        // Запуск следующей итерации цикла посимвольного вывода текста.
        if (counter == hw.Length)
        {
            counter = 0;
            temp = "";
        }
    }
}

Исходники приложений с фигурными окнами

Файл прикрепленного ниже архива содержит три проекта описанных выше приложений. Исходники написаны на языке C# на платформе WPF, в среде программирования MS Visual Studio 2022.

Скачать исходник