2D Графіка та Мультимедіа у WPF
2D Графіка та Мультимедіа у WPF
WPF — це не просто фреймворк для кнопок та текстових полів. Це потужна графічна система, побудована на DirectX, що дозволяє створювати складну векторну графіку, градієнти, трансформації та навіть відтворювати відео прямо в інтерфейсі.
Уявіть: ви можете намалювати будь-яку фігуру через Path з SVG-подібним синтаксисом, застосувати градієнтний фон з кількома кольорами, обернути елемент на 45 градусів, і все це буде масштабуватися без втрати якості, бо це вектор. Або вставити відео як фон для кнопки через MediaElement. WPF робить це природно та елегантно.
У цій статті ми детально розберемо всі графічні можливості WPF: від базових фігур (Rectangle, Ellipse) до складних Path з кривими Безьє, від простих кольорів до радіальних градієнтів, від статичних зображень до відео. Ви навчитесь створювати професійні візуальні ефекти без зовнішніх бібліотек.
Shapes: базові геометричні фігури
WPF надає набір готових фігур через класи, що успадковуються від Shape.
Rectangle: прямокутник
<Rectangle Width="200" Height="100"
Fill="#3b82f6"
Stroke="#1e40af"
StrokeThickness="2"
RadiusX="8"
RadiusY="8"/>
Властивості:
Fill— заповнення (колір або Brush)Stroke— обведення (колір або Brush)StrokeThickness— товщина обведенняRadiusX,RadiusY— заокруглення кутів
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="16" HorizontalAlignment="Center">
<TextBlock Text="📐 Rectangle Shapes"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="16">
<!-- Звичайний прямокутник -->
<Rectangle Width="100" Height="80"
Fill="#3b82f6"
Stroke="#1e40af"
StrokeThickness="2"/>
<!-- З заокругленими кутами -->
<Rectangle Width="100" Height="80"
Fill="#22c55e"
Stroke="#16a34a"
StrokeThickness="2"
RadiusX="12"
RadiusY="12"/>
<!-- Лише обведення -->
<Rectangle Width="100" Height="80"
Stroke="#f59e0b"
StrokeThickness="3"
RadiusX="8"
RadiusY="8"/>
</StackPanel>
</StackPanel>
</Border>
Ellipse: коло та еліпс
<!-- Коло -->
<Ellipse Width="100" Height="100"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"/>
<!-- Еліпс -->
<Ellipse Width="150" Height="80"
Fill="#8b5cf6"
Stroke="#7c3aed"
StrokeThickness="2"/>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="16" HorizontalAlignment="Center">
<TextBlock Text="⭕ Ellipse Shapes"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="16" HorizontalAlignment="Center">
<!-- Коло -->
<Ellipse Width="80" Height="80"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"/>
<!-- Еліпс горизонтальний -->
<Ellipse Width="120" Height="80"
Fill="#8b5cf6"
Stroke="#7c3aed"
StrokeThickness="2"/>
<!-- Еліпс вертикальний -->
<Ellipse Width="80" Height="120"
Fill="#06b6d4"
Stroke="#0891b2"
StrokeThickness="2"/>
</StackPanel>
</StackPanel>
</Border>
Line: лінія
<Line X1="0" Y1="0" X2="200" Y2="100"
Stroke="#64748b"
StrokeThickness="2"/>
Властивості:
X1,Y1— початкова точкаX2,Y2— кінцева точкаStroke— колір лініїStrokeThickness— товщина
Polygon: багатокутник (замкнений)
<!-- Трикутник -->
<Polygon Points="50,0 100,100 0,100"
Fill="#f59e0b"
Stroke="#d97706"
StrokeThickness="2"/>
<!-- П'ятикутник -->
<Polygon Points="50,0 100,38 81,100 19,100 0,38"
Fill="#10b981"
Stroke="#059669"
StrokeThickness="2"/>
Points формат: "x1,y1 x2,y2 x3,y3 ..." — список координат вершин.
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="16" HorizontalAlignment="Center">
<TextBlock Text="🔺 Polygon Shapes"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="24" HorizontalAlignment="Center">
<!-- Трикутник -->
<Polygon Points="50,0 100,86 0,86"
Fill="#f59e0b"
Stroke="#d97706"
StrokeThickness="2"/>
<!-- Квадрат (через Polygon) -->
<Polygon Points="0,0 80,0 80,80 0,80"
Fill="#3b82f6"
Stroke="#1e40af"
StrokeThickness="2"/>
<!-- Зірка -->
<Polygon Points="50,0 61,35 98,35 68,57 79,91 50,70 21,91 32,57 2,35 39,35"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"/>
</StackPanel>
</StackPanel>
</Border>
Polyline: ламана лінія (незамкнена)
<Polyline Points="0,50 50,0 100,50 150,0 200,50"
Stroke="#3b82f6"
StrokeThickness="3"
Fill="Transparent"/>
Різниця з Polygon: Polyline не замикає фігуру автоматично.
StrokeDashArray: пунктирні лінії
<!-- Пунктирна лінія -->
<Line X1="0" Y1="0" X2="200" Y2="0"
Stroke="#64748b"
StrokeThickness="2"
StrokeDashArray="4,2"/>
<!-- Штрих-пунктирна -->
<Line X1="0" Y1="0" X2="200" Y2="0"
Stroke="#64748b"
StrokeThickness="2"
StrokeDashArray="8,2,2,2"/>
StrokeDashArray формат: "dash,gap,dash,gap,..." — довжина штриха та проміжку.
Path та PathGeometry: складні фігури
Path — це універсальна фігура, що може описати будь-яку форму через PathGeometry. Синтаксис схожий на SVG.
Базовий синтаксис
<Path Stroke="#3b82f6" StrokeThickness="2" Fill="#93c5fd">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="10,50">
<LineSegment Point="50,10"/>
<LineSegment Point="90,50"/>
<LineSegment Point="50,90"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Mini-language: компактний синтаксис
Замість багатослівного XML, WPF підтримує компактний синтаксис через Data атрибут:
<Path Data="M 10,50 L 50,10 L 90,50 L 50,90 Z"
Stroke="#3b82f6"
StrokeThickness="2"
Fill="#93c5fd"/>
Команди mini-language:
| Команда | Опис | Приклад |
|---|---|---|
M x,y | Move to (переміститися) | M 10,20 |
L x,y | Line to (лінія до) | L 50,60 |
H x | Horizontal line (горизонтальна лінія) | H 100 |
V y | Vertical line (вертикальна лінія) | V 80 |
C x1,y1 x2,y2 x,y | Cubic Bezier curve (кубічна крива) | C 20,20 40,20 50,10 |
Q x1,y1 x,y | Quadratic Bezier curve (квадратична крива) | Q 30,30 50,10 |
A rx,ry angle large sweep x,y | Arc (дуга) | A 30,30 0 0 1 50,50 |
Z | Close path (замкнути фігуру) | Z |
Малі літери (m, l, h, v, c, q, a) — відносні координати (від поточної позиції).
Приклад: серце
<Path Data="M 50,20 C 50,10 40,0 30,0 C 15,0 0,15 0,30 C 0,45 15,60 50,90 C 85,60 100,45 100,30 C 100,15 85,0 70,0 C 60,0 50,10 50,20 Z"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"/>
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="20" HorizontalAlignment="Center">
<TextBlock Text="💎 Path Shapes"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="24" HorizontalAlignment="Center">
<!-- Серце -->
<Path Data="M 50,20 C 50,10 40,0 30,0 C 15,0 0,15 0,30 C 0,45 15,60 50,90 C 85,60 100,45 100,30 C 100,15 85,0 70,0 C 60,0 50,10 50,20 Z"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"
Width="80"
Height="80"
Stretch="Uniform"/>
<!-- Зірка (через Path) -->
<Path Data="M 50,0 L 61,35 L 98,35 L 68,57 L 79,91 L 50,70 L 21,91 L 32,57 L 2,35 L 39,35 Z"
Fill="#f59e0b"
Stroke="#d97706"
StrokeThickness="2"
Width="80"
Height="80"
Stretch="Uniform"/>
<!-- Хмара -->
<Path Data="M 20,40 C 20,30 30,20 40,20 C 45,20 50,22 53,25 C 56,18 63,13 71,13 C 82,13 91,22 91,33 C 91,34 91,35 90,36 C 96,38 100,44 100,51 C 100,60 93,67 84,67 L 20,67 C 9,67 0,58 0,47 C 0,38 6,30 15,28 C 16,28 17,28 18,28 C 18,33 19,37 20,40 Z"
Fill="#06b6d4"
Stroke="#0891b2"
StrokeThickness="2"
Width="80"
Height="60"
Stretch="Uniform"/>
</StackPanel>
</StackPanel>
</Border>
SVG → Path Data
Багато графічних редакторів (Figma, Illustrator, Inkscape) експортують SVG. Ви можете скопіювати d атрибут з SVG <path> і вставити в WPF Path.Data:
SVG:
<svg>
<path d="M 10,10 L 50,50 L 10,90 Z" fill="blue"/>
</svg>
WPF:
<Path Data="M 10,10 L 50,50 L 10,90 Z" Fill="Blue"/>
Brushes: способи заповнення
Brush визначає, як заповнюється фігура або фон елемента. WPF підтримує кілька типів Brush.
SolidColorBrush: однотонний колір
<Rectangle Fill="#3b82f6"/>
<!-- Або через об'єкт -->
<Rectangle>
<Rectangle.Fill>
<SolidColorBrush Color="#3b82f6"/>
</Rectangle.Fill>
</Rectangle>
LinearGradientBrush: лінійний градієнт
<Rectangle Width="200" Height="100">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#3b82f6" Offset="0"/>
<GradientStop Color="#8b5cf6" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
Властивості:
StartPoint,EndPoint— напрямок градієнта (0,0 = верхній лівий, 1,1 = нижній правий)GradientStop— колір на певній позиції (Offset від 0 до 1)
Напрямки градієнта:
<!-- Горизонтальний (зліва направо) -->
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<!-- Вертикальний (зверху вниз) -->
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<!-- Діагональний -->
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<!-- Знизу вгору -->
<LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="16" HorizontalAlignment="Center">
<TextBlock Text="🎨 Linear Gradients"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Spacing="12">
<!-- Горизонтальний градієнт -->
<Border Width="300" Height="60" CornerRadius="8">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#3b82f6" Offset="0"/>
<GradientStop Color="#8b5cf6" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Horizontal"
Foreground="White"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<!-- Вертикальний градієнт -->
<Border Width="300" Height="60" CornerRadius="8">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#22c55e" Offset="0"/>
<GradientStop Color="#06b6d4" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Vertical"
Foreground="White"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<!-- Діагональний градієнт -->
<Border Width="300" Height="60" CornerRadius="8">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#f59e0b" Offset="0"/>
<GradientStop Color="#ef4444" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Diagonal"
Foreground="White"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
<!-- Багатоколірний градієнт -->
<Border Width="300" Height="60" CornerRadius="8">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#ef4444" Offset="0"/>
<GradientStop Color="#f59e0b" Offset="0.25"/>
<GradientStop Color="#22c55e" Offset="0.5"/>
<GradientStop Color="#3b82f6" Offset="0.75"/>
<GradientStop Color="#8b5cf6" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<TextBlock Text="Rainbow"
Foreground="White"
FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Border>
</StackPanel>
</StackPanel>
</Border>
RadialGradientBrush: радіальний градієнт
<Ellipse Width="200" Height="200">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#ffffff" Offset="0"/>
<GradientStop Color="#3b82f6" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
Властивості:
Center— центр градієнта (за замовчуванням 0.5,0.5)RadiusX,RadiusY— радіус градієнтаGradientOrigin— точка початку градієнта
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="16" HorizontalAlignment="Center">
<TextBlock Text="🌟 Radial Gradients"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="20" HorizontalAlignment="Center">
<!-- Центрований радіальний градієнт -->
<Ellipse Width="120" Height="120">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#ffffff" Offset="0"/>
<GradientStop Color="#3b82f6" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Зміщений центр -->
<Ellipse Width="120" Height="120">
<Ellipse.Fill>
<RadialGradientBrush Center="0.3,0.3" GradientOrigin="0.3,0.3">
<GradientStop Color="#ffffff" Offset="0"/>
<GradientStop Color="#22c55e" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Багатоколірний -->
<Ellipse Width="120" Height="120">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="#fef3c7" Offset="0"/>
<GradientStop Color="#fbbf24" Offset="0.5"/>
<GradientStop Color="#f59e0b" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</StackPanel>
</StackPanel>
</Border>
ImageBrush: зображення як заповнення
<Rectangle Width="200" Height="200">
<Rectangle.Fill>
<ImageBrush ImageSource="/Assets/pattern.png"
TileMode="Tile"
Viewport="0,0,0.25,0.25"/>
</Rectangle.Fill>
</Rectangle>
Властивості:
ImageSource— шлях до зображенняStretch— як масштабувати (None, Fill, Uniform, UniformToFill)TileMode— режим повторення (None, Tile, FlipX, FlipY, FlipXY)Viewport— розмір плитки при TileMode="Tile"
VisualBrush: рендеринг іншого Visual
VisualBrush дозволяє використовувати будь-який WPF елемент як текстуру. Це потужна можливість для створення ефектів дзеркала, повторюваних патернів з UI-елементів, тощо.
<Grid>
<!-- Оригінальний елемент -->
<StackPanel x:Name="OriginalContent" Width="200">
<TextBlock Text="Hello WPF!" FontSize="24" FontWeight="Bold"/>
<Button Content="Click Me"/>
</StackPanel>
<!-- Використання як Brush -->
<Rectangle Width="200" Height="200" Margin="250,0,0,0">
<Rectangle.Fill>
<VisualBrush Visual="{Binding ElementName=OriginalContent}"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
Приклад: Повторюваний патерн з кнопки
<Border Width="400" Height="300">
<Border.Background>
<VisualBrush TileMode="Tile" Viewport="0,0,0.2,0.2">
<VisualBrush.Visual>
<Button Content="🎨" Width="50" Height="50"/>
</VisualBrush.Visual>
</VisualBrush>
</Border.Background>
</Border>
Geometries: математичні форми без візуалізації
Geometry — це математичний опис форми без візуального представлення. Використовується для Clip (обрізання), Data у Path, або як основа для Drawing.
RectangleGeometry, EllipseGeometry
<!-- Обрізання елемента по колу -->
<Image Source="/Assets/photo.jpg" Width="200" Height="200">
<Image.Clip>
<EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
</Image.Clip>
</Image>
<!-- Обрізання по прямокутнику з заокругленими кутами -->
<Border Background="Blue" Width="200" Height="100">
<Border.Clip>
<RectangleGeometry Rect="0,0,200,100" RadiusX="20" RadiusY="20"/>
</Border.Clip>
</Border>
CombinedGeometry: комбінування форм
<Path Stroke="Black" StrokeThickness="2" Fill="#3b82f6">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,100,100"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="50,50" RadiusX="40" RadiusY="40"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
GeometryCombineMode:
Union— об'єднання (A + B)Intersect— перетин (A ∩ B)Xor— виключне АБО (A ⊕ B)Exclude— різниця (A - B)
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="20" HorizontalAlignment="Center">
<TextBlock Text="🔀 Combined Geometries"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="24" HorizontalAlignment="Center">
<!-- Union -->
<StackPanel Spacing="8">
<Path Stroke="#1e40af" StrokeThickness="2" Fill="#3b82f6" Width="100" Height="100">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="35,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="65,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<TextBlock Text="Union" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Intersect -->
<StackPanel Spacing="8">
<Path Stroke="#16a34a" StrokeThickness="2" Fill="#22c55e" Width="100" Height="100">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Intersect">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="35,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="65,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<TextBlock Text="Intersect" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Exclude -->
<StackPanel Spacing="8">
<Path Stroke="#dc2626" StrokeThickness="2" Fill="#ef4444" Width="100" Height="100">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="35,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="65,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<TextBlock Text="Exclude" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Xor -->
<StackPanel Spacing="8">
<Path Stroke="#7c3aed" StrokeThickness="2" Fill="#8b5cf6" Width="100" Height="100">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Xor">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="35,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="65,50" RadiusX="35" RadiusY="35"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<TextBlock Text="Xor" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
PathGeometry: складні геометрії
<PathGeometry>
<PathFigure StartPoint="10,50" IsClosed="True">
<LineSegment Point="50,10"/>
<ArcSegment Point="90,50" Size="40,40" SweepDirection="Clockwise"/>
<LineSegment Point="50,90"/>
</PathFigure>
</PathGeometry>
DrawingGroup та DrawingImage: векторні зображення
Drawing — це легковаговий спосіб створення векторної графіки без повноцінних UI-елементів. Використовується для іконок, складних векторних зображень.
GeometryDrawing
<Image Width="100" Height="100">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<!-- Коло -->
<GeometryDrawing Brush="#3b82f6">
<GeometryDrawing.Geometry>
<EllipseGeometry Center="50,50" RadiusX="40" RadiusY="40"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<!-- Трикутник всередині -->
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure StartPoint="35,60" IsClosed="True">
<LineSegment Point="50,35"/>
<LineSegment Point="65,60"/>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
Переваги Drawing над Shape:
- Легковаговіший (менше пам'яті)
- Швидший рендеринг
- Можна використовувати як ImageSource
- Ідеально для іконок
Недоліки:
- Немає інтерактивності (події, hover)
- Немає Layout (фіксовані координати)
Transforms: трансформації елементів
Transforms дозволяють обертати, масштабувати, переміщувати та нахиляти елементи.
RotateTransform: обертання
<Rectangle Width="100" Height="50" Fill="#3b82f6">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" CenterX="50" CenterY="25"/>
</Rectangle.RenderTransform>
</Rectangle>
Властивості:
Angle— кут обертання в градусахCenterX,CenterY— точка обертання
ScaleTransform: масштабування
<Button Content="Scaled">
<Button.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" CenterX="50" CenterY="25"/>
</Button.RenderTransform>
</Button>
Властивості:
ScaleX,ScaleY— коефіцієнт масштабування (1 = 100%, 2 = 200%, 0.5 = 50%)CenterX,CenterY— точка масштабування
TranslateTransform: переміщення
<Ellipse Width="50" Height="50" Fill="#22c55e">
<Ellipse.RenderTransform>
<TranslateTransform X="100" Y="50"/>
</Ellipse.RenderTransform>
</Ellipse>
Властивості:
X,Y— зміщення по осях
SkewTransform: нахил
<Rectangle Width="100" Height="50" Fill="#f59e0b">
<Rectangle.RenderTransform>
<SkewTransform AngleX="20" AngleY="0"/>
</Rectangle.RenderTransform>
</Rectangle>
Властивості:
AngleX,AngleY— кут нахилу по осях
TransformGroup: комбінування
<Border Width="100" Height="100" Background="#8b5cf6">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.2" ScaleY="1.2"/>
<RotateTransform Angle="15"/>
<TranslateTransform X="50" Y="20"/>
</TransformGroup>
</Border.RenderTransform>
</Border>
Порядок застосування: Трансформації застосовуються в порядку, в якому вони визначені в TransformGroup.
Loading Avalonia WebAssembly...
Downloading .NET runtime (10MB)...
<Border Background="#f8fafc" Padding="40" CornerRadius="8">
<StackPanel Spacing="24" HorizontalAlignment="Center">
<TextBlock Text="🔄 Transforms"
FontSize="20" FontWeight="Bold"
Foreground="#1e293b"
HorizontalAlignment="Center"/>
<StackPanel Orientation="Horizontal" Spacing="32" HorizontalAlignment="Center">
<!-- Оригінал -->
<StackPanel Spacing="8">
<Rectangle Width="80" Height="80" Fill="#3b82f6" Stroke="#1e40af" StrokeThickness="2"/>
<TextBlock Text="Original" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Rotate -->
<StackPanel Spacing="8">
<Rectangle Width="80" Height="80" Fill="#22c55e" Stroke="#16a34a" StrokeThickness="2">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" CenterX="40" CenterY="40"/>
</Rectangle.RenderTransform>
</Rectangle>
<TextBlock Text="Rotate 45°" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Scale -->
<StackPanel Spacing="8">
<Rectangle Width="80" Height="80" Fill="#f59e0b" Stroke="#d97706" StrokeThickness="2">
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="0.7" ScaleY="1.3" CenterX="40" CenterY="40"/>
</Rectangle.RenderTransform>
</Rectangle>
<TextBlock Text="Scale" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Skew -->
<StackPanel Spacing="8">
<Rectangle Width="80" Height="80" Fill="#8b5cf6" Stroke="#7c3aed" StrokeThickness="2">
<Rectangle.RenderTransform>
<SkewTransform AngleX="20" AngleY="0"/>
</Rectangle.RenderTransform>
</Rectangle>
<TextBlock Text="Skew" FontSize="12" Foreground="#64748b" HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
MediaElement: відео та аудіо
MediaElement дозволяє відтворювати відео та аудіо файли прямо в WPF інтерфейсі.
Базовий синтаксис
<MediaElement x:Name="VideoPlayer"
Source="/Assets/video.mp4"
LoadedBehavior="Manual"
Width="640"
Height="360"/>
<StackPanel Orientation="Horizontal">
<Button Content="Play" Click="Play_Click"/>
<Button Content="Pause" Click="Pause_Click"/>
<Button Content="Stop" Click="Stop_Click"/>
</StackPanel>
private void Play_Click(object sender, RoutedEventArgs e)
{
VideoPlayer.Play();
}
private void Pause_Click(object sender, RoutedEventArgs e)
{
VideoPlayer.Pause();
}
private void Stop_Click(object sender, RoutedEventArgs e)
{
VideoPlayer.Stop();
}
Властивості MediaElement
| Властивість | Опис |
|---|---|
Source | Шлях до медіа-файлу (локальний або URL) |
LoadedBehavior | Поведінка при завантаженні (Manual, Play, Pause, Stop) |
UnloadedBehavior | Поведінка при вивантаженні |
Volume | Гучність (0.0 - 1.0) |
IsMuted | Вимкнути звук |
Position | Поточна позиція відтворення (TimeSpan) |
SpeedRatio | Швидкість відтворення (1.0 = нормальна, 2.0 = 2x) |
Stretch | Як масштабувати відео (None, Fill, Uniform, UniformToFill) |
Події MediaElement
VideoPlayer.MediaOpened += (s, e) =>
{
// Медіа завантажено, можна отримати Duration
var duration = VideoPlayer.NaturalDuration.TimeSpan;
Console.WriteLine($"Duration: {duration}");
};
VideoPlayer.MediaEnded += (s, e) =>
{
// Відтворення завершено
VideoPlayer.Position = TimeSpan.Zero; // Повернутися на початок
};
VideoPlayer.MediaFailed += (s, e) =>
{
// Помилка завантаження
MessageBox.Show($"Error: {e.ErrorException.Message}");
};
Приклад: Відеоплеєр з контролами
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Відео -->
<MediaElement x:Name="VideoPlayer"
Source="/Assets/video.mp4"
LoadedBehavior="Manual"
Stretch="Uniform"/>
<!-- Контроли -->
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10">
<Button Content="▶" Width="40" Click="Play_Click"/>
<Button Content="⏸" Width="40" Click="Pause_Click"/>
<Button Content="⏹" Width="40" Click="Stop_Click"/>
<Slider x:Name="PositionSlider"
Width="300"
Margin="10,0"
ValueChanged="PositionSlider_ValueChanged"/>
<TextBlock x:Name="TimeText"
Text="00:00 / 00:00"
VerticalAlignment="Center"
Margin="10,0"/>
</StackPanel>
</Grid>
private bool _isUserDraggingSlider = false;
private void VideoPlayer_MediaOpened(object sender, RoutedEventArgs e)
{
if (VideoPlayer.NaturalDuration.HasTimeSpan)
{
PositionSlider.Maximum = VideoPlayer.NaturalDuration.TimeSpan.TotalSeconds;
// Оновлення позиції кожні 100ms
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(100) };
timer.Tick += (s, args) =>
{
if (!_isUserDraggingSlider)
{
PositionSlider.Value = VideoPlayer.Position.TotalSeconds;
UpdateTimeText();
}
};
timer.Start();
}
}
private void PositionSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_isUserDraggingSlider)
{
VideoPlayer.Position = TimeSpan.FromSeconds(PositionSlider.Value);
}
}
private void UpdateTimeText()
{
var current = VideoPlayer.Position;
var total = VideoPlayer.NaturalDuration.HasTimeSpan
? VideoPlayer.NaturalDuration.TimeSpan
: TimeSpan.Zero;
TimeText.Text = $"{current:mm\\:ss} / {total:mm\\:ss}";
}
MediaTimeline: анімація через Storyboard
<MediaElement x:Name="VideoPlayer" LoadedBehavior="Manual">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<MediaTimeline Source="/Assets/video.mp4"
Storyboard.TargetName="VideoPlayer"
BeginTime="0:0:2"
Duration="0:0:10"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
MediaTimeline дозволяє контролювати відтворення через Storyboard (затримка, тривалість, повторення).
Практичні завдання
Рівень 1: Набір геометричних фігур
Мета: Навчитися використовувати базові Shape елементи.
Завдання:
Створіть композицію з геометричних фігур:
- Фігури:
- Коло (Ellipse) — червоне
- Квадрат (Rectangle) — синій
- Трикутник (Polygon) — зелений
- Зірка (Polygon або Path) — жовта
- Стилізація:
- Кожна фігура має Fill та Stroke
- StrokeThickness = 2
- Розташуйте фігури в Grid або StackPanel
- Додатково:
- Додайте підписи під кожною фігурою
- Використайте градієнтне заповнення для однієї з фігур
- Додайте hover ефект (зміна кольору при наведенні)
Критерії успіху:
- Всі 4 фігури відображаються правильно
- Використано Fill та Stroke
- Композиція виглядає акуратно
- Додаткові ефекти працюють
Підказка:
<StackPanel Orientation="Horizontal" Spacing="20" HorizontalAlignment="Center">
<!-- Коло -->
<StackPanel Spacing="8">
<Ellipse Width="80" Height="80"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"/>
<TextBlock Text="Circle" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Квадрат -->
<StackPanel Spacing="8">
<Rectangle Width="80" Height="80"
Fill="#3b82f6"
Stroke="#1e40af"
StrokeThickness="2"/>
<TextBlock Text="Square" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Трикутник -->
<StackPanel Spacing="8">
<Polygon Points="40,0 80,80 0,80"
Fill="#22c55e"
Stroke="#16a34a"
StrokeThickness="2"/>
<TextBlock Text="Triangle" HorizontalAlignment="Center"/>
</StackPanel>
<!-- Зірка -->
<StackPanel Spacing="8">
<Polygon Points="40,0 49,28 78,28 55,45 64,73 40,56 16,73 25,45 2,28 31,28"
Fill="#f59e0b"
Stroke="#d97706"
StrokeThickness="2"/>
<TextBlock Text="Star" HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
Рівень 2: SVG-подібний малюнок через Path
Мета: Навчитися створювати складні фігури через Path та PathGeometry.
Завдання:
Створіть іконку або логотип через Path:
- Варіанти:
- Іконка будинку
- Іконка серця
- Іконка хмари
- Власний дизайн
- Вимоги:
- Використайте Path з Data mini-language
- Мінімум 5 команд (M, L, C, A, Z)
- Fill та Stroke
- Розмір 100x100 або більше
- Додатково:
- Створіть кілька варіантів з різними кольорами
- Додайте градієнтне заповнення
- Додайте анімацію (обертання або пульсація)
Критерії успіху:
- Path відображається правильно
- Використано mini-language синтаксис
- Фігура виглядає акуратно
- Додаткові ефекти працюють
Підказка (іконка будинку):
<Path Width="100" Height="100" Stretch="Uniform"
Fill="#3b82f6"
Stroke="#1e40af"
StrokeThickness="2">
<Path.Data>
<!-- Дах -->
M 10,50 L 50,10 L 90,50
<!-- Стіни -->
L 90,90 L 10,90 Z
<!-- Двері -->
M 35,90 L 35,60 L 65,60 L 65,90
<!-- Вікно -->
M 25,40 L 25,25 L 40,25 L 40,40 Z
</Path.Data>
</Path>
Підказка (іконка серця):
<Path Data="M 50,20 C 50,10 40,0 30,0 C 15,0 0,15 0,30 C 0,45 15,60 50,90 C 85,60 100,45 100,30 C 100,15 85,0 70,0 C 60,0 50,10 50,20 Z"
Fill="#ef4444"
Stroke="#dc2626"
StrokeThickness="2"
Width="100"
Height="100"
Stretch="Uniform"/>
Рівень 3: Градієнтний фон із VisualBrush ефектом
Мета: Навчитися створювати складні візуальні ефекти через Brushes.
Завдання:
Створіть складний фон для вікна або панелі:
- Базовий фон:
- LinearGradientBrush або RadialGradientBrush
- Мінімум 3 кольори
- Плавні переходи
- VisualBrush патерн:
- Створіть повторюваний патерн через VisualBrush
- Використайте геометричні фігури або Path
- TileMode="Tile"
- Напівпрозорість для накладання на градієнт
- Додатково:
- Додайте анімацію градієнта (зміна кольорів)
- Створіть кілька варіантів фону (світлий/темний)
- Додайте ефект паралакса (різна швидкість анімації для шарів)
Критерії успіху:
- Градієнтний фон відображається правильно
- VisualBrush патерн працює
- Композиція виглядає професійно
- Додаткові ефекти працюють
Підказка:
<Grid>
<!-- Базовий градієнт -->
<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#667eea" Offset="0"/>
<GradientStop Color="#764ba2" Offset="0.5"/>
<GradientStop Color="#f093fb" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<!-- VisualBrush патерн -->
<Rectangle Opacity="0.1">
<Rectangle.Fill>
<VisualBrush TileMode="Tile" Viewport="0,0,0.1,0.1">
<VisualBrush.Visual>
<Canvas Width="100" Height="100">
<Ellipse Width="40" Height="40"
Fill="White"
Canvas.Left="30"
Canvas.Top="30"/>
<Rectangle Width="20" Height="20"
Fill="White"
Canvas.Left="10"
Canvas.Top="10"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
<!-- Вміст -->
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="Beautiful Background"
FontSize="48"
FontWeight="Bold"
Foreground="White"
Effect="{StaticResource DropShadowEffect}"/>
</StackPanel>
</Grid>
Додатково (анімація градієнта):
// В code-behind
private void AnimateGradient()
{
var gradient = (LinearGradientBrush)MyGrid.Background;
var animation = new ColorAnimation
{
To = Colors.Orange,
Duration = TimeSpan.FromSeconds(2),
AutoReverse = true,
RepeatBehavior = RepeatBehavior.Forever
};
gradient.GradientStops[0].BeginAnimation(GradientStop.ColorProperty, animation);
}
Підсумок
WPF надає потужні інструменти для роботи з 2D графікою та мультимедіа. Від простих фігур до складних векторних зображень, від однотонних кольорів до радіальних градієнтів, від статичних елементів до відео — все це доступно "з коробки".
Ключові висновки:
📐 Shapes
🎨 Path
🌈 Brushes
🔀 Geometries
🔄 Transforms
🎬 MediaElement
Що далі?
Наступна стаття — Avalonia Graphics покаже відмінності в графічній системі Avalonia.