You are on page 1of 126

WPF

1. Особливості платформи WPF


2. Початок роботи з WPF
3. Калькулятор
4. Вступ у мову XAML
5. Компоновка у WPF
6. Елементи управління
7. Події у проектах WPF
8. Робота з графікою. Геометрії. Трансформації
9. Анімація
Особливості платформи WPF
Технологія WPF (Windows Presentation Foundation) є частина екосистеми платформи .NET
являє собою підсистему для побудови графічних інтерфейсів.
Якщо при створенні традиційних додатків на основі WinForms за малювання елементів
управління і графіки відповідали такі частини ОС Windows, як User32 і GDI , програми
WPF засновані на DirectX. В цьому полягає ключова особливість рендеринга графіки в
WPF: використовуючи WPF, значна частина роботи з візуалізації графіки, як
найпростіших кнопочок, так і складних 3D-моделей, лягати на графічний процесор
відеокарти, що також дозволяє скористатися апаратним прискоренням графіки. Однією
з важливих особливостей є використання декларативної мови розмітки інтерфейсу
XAML, заснованого на XML:
Особливості платформи WPF
Переваги WPF! Що вам, як розробнику, пропонує WPF?
- Використання традиційних мов .NET-платформи - C# і VB.NET для створення логіки
програми
- Можливість декларативного визначення графічного інтерфейсу за допомогою
спеціальної мови розмітки XAML, заснований на xml і представляє альтернативу
програмного створення графіки та елементів керування, а також можливість
комбінувати XAML і C#/VB.NET
- Незалежність від дозволу екрану: оскільки в WPF всі елементи вимірюються в
незалежних від пристрою одиницях, додатки на WPF легко масштабуються під різні
екрани з різним дозволом.
Особливості платформи WPF
- Нові можливості, яких складно було досягти в WinForms, наприклад, створення тривимірних
моделей, прив'язка даних, використання таких елементів, як стилі, шаблони, теми та ін.
- Хороша взаємодія з WinForms, завдяки чому, наприклад, в додатках WPF можна використовувати
традиційні елементи управління з WinForms.
- Багаті можливості по створенню різних програм: це і мультимедіа, і двовимірна і тривимірна графіка,
і багатий набір вбудованих елементів управління, а також можливість самим створювати нові
елементи, створення анімацій, прив'язка даних, стилі, шаблони, теми та багато іншого
- Апаратне прискорення графіки - незалежно від того, чи працюєте ви з 2D або 3D графікою або
текстом, всі компоненти програми транслюються в об'єкти, зрозумілі Direct3D, і потім візуалізуються
за допомогою процесора на відеокарті, що підвищує продуктивність, робить графіку більш плавною.
- Створення додатків під безліч ОС сімейства Windows від Windows XP до Windows 10
Особливості платформи WPF
У теж час WPF має певні обмеження. Незважаючи на підтримку тривимірної
візуалізації, для створення додатків з великою кількістю тривимірних
зображень, насамперед ігор, краще використовувати інші засоби - DirectX або
спеціальні фреймворки, такі як Monogame або Unity.
Також варто враховувати, що порівняно з додатками на Windows Forms обсяг
програм на WPF і споживання ними пам'яті в процесі роботи в середньому
трохи вище. Але це з лишком компенсується більш широкими графічними
можливостями і провышенной продуктивністю при візуалізації графіки.
Особливості платформи WPF

Історія розвитку
WPF є частиною екосистеми .NET і розвивається разом з
фреймворком .NET і має ті ж версії. Перша версія WPF 3.0 вийшла разом
з .NET 3.0 і операційною системою Windows Vista в 2006 році. З тих пір
платформа послідовно розвивається. Остання версія WPF 4.6 вийшла
паралельно з .NET 4.6 у липні 2015 року, ознаменувавши дев'ятиріччя
даної платформи.
Початок роботи з WPF
Відкриємо Visual Studio Express 2015 і в меню File (Файл) виберемо пункт New (Створити)
-> Project... (...). Перед нами відкриється діалогове вікно створення проекту, в якому ми
виберемо шаблон WPF Application:
За замовчуванням студія відкриває створює і відкриває нам два файли: файл
декларативною розмітки інтерфейсу MainWindow.xaml і файл пов'язаного з розміткою
коду MainWindow.xaml.cs. Файл MainWindow.xaml має два подання: візуальне подання
WYSIWIG відображає весь графічний інтерфейс даного вікна програми, і під ним
декларативне оголошення інтерфейсу в XAML. Якщо ми змінимо декларативну розмітку,
наприклад, визначимо там кнопку, то ці зміни відображено у візуальному поданні.
Калькулятор. Файл MainWindow.xaml
<Window x:Class="FirstWpfApp.MainWindow" <Grid.ColumnDefinitions>
xmlns="http://schemas.microsoft.com/winfx/2006 <ColumnDefinition />
/xaml/presentation" xmlns:x= <ColumnDefinition />
http://schemas.microsoft.com/winfx/2006/xaml <ColumnDefinition />
Title="Калькулятор" Height="250" Width="300"> <ColumnDefinition />
<Grid x:Name="LayoutRoot« Background="White"> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <TextBlock x:Name="textBlock" Grid.Column="0"
<RowDefinition /> Grid.ColumnSpan="4" />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
Калькулятор. Файл MainWindow.xaml
<Button Grid.Column="0" Grid.Row="1">1</Button> <Button Grid.Column="1" Grid.Row="3">0</Button>
<Button Grid.Column="1" Grid.Row="1">2</Button> <Button Grid.Column="2" Grid.Row="3">+</Button>
<Button Grid.Column="2" Grid.Row="1">3</Button> <Button Grid.Column="3" Grid.Row="3">-</Button>
<Button Grid.Column="3" Grid.Row="1">4</Button> <Button Grid.Column="0" Grid.Row="4">*</Button>
<Button Grid.Column="0" Grid.Row="2">5</Button> <Button Grid.Column="1" Grid.Row="4">/</Button>
<Button Grid.Column="1" Grid.Row="2">6</Button> <Button Grid.Column="2" Grid.Row="4">=</Button>
<Button Grid.Column="2" Grid.Row="2">7</Button> <Button Grid.Column="3"
<Button Grid.Column="3" Grid.Row="2">8</Button> Grid.Row="4">CLEAR</Button>
<Button Grid.Column="0" Grid.Row="3">9</Button> </Grid>
</Window>
Калькулятор. Файл MainWindow.xaml.cs
using System; InitializeComponent();
using System.Windows; // Додаємо обробник для всіх кнопок
using System.Windows.Controls; на гріді
namespace FirstWpfApp { foreach (UIElement c in
public partial class MainWindow : Window { LayoutRoot.Children) {
string leftop = ""; // Левый операнд if (c is Button) {
string operation = ""; // Знак операции ((Button)c).Click += Button_Click;
string rightop = ""; // Правый операнд }
public MainWindow() { }
}
Калькулятор. Файл MainWindow.xaml.cs
private void Button_Click(object sender, // Якщо операція не задано
RoutedEventArgs e) { if (operation == "") {
// Отримуємо текст кнопки // Додаємо до лівому операнду
string s = (string) leftop += s;
((Button)e.OriginalSource).Content; } else {
// Додаємо його в текстове поле // Інакше до правого операнду
textBlock.Text += s; rightop += s;
int num; }
// Намагаємося перетворити його в число }
bool result = Int32.TryParse(s, out num);
// Якщо текст - це число
if (result == true) {
Калькулятор. Файл MainWindow.xaml.cs
else { // Якщо було введено не число operation = ""; textBlock.Text = "";
// Якщо одно, то виводимо результат } else {
операції // Отримуємо операцію. Якщо правий операнд вже є,
if (s == "=") { то присвоюємо його значення лівому. операнду, а
Update_RightOp(); правий операнд очищаємо
textBlock.Text += rightop; if (rightop != "") {
operation = ""; Update_RightOp();
} leftop = rightop;
// Очищаємо поле та змінні rightop = "";
else if (s == "CLEAR") { }
leftop = ""; rightop = ""; operation = s;
} } }
Калькулятор. Файл MainWindow.xaml.cs
// Оновлюємо значення правого операнда break;
private void Update_RightOp() { case "*":
int num1 = Int32.Parse(leftop); rightop = (num1 * num2).ToString();
int num2 = Int32.Parse(rightop); break;
// І виконуємо операцію case "/":
switch (operation) { rightop = (num1 / num2).ToString();
case "+": break;
rightop = (num1 + num2).ToString(); }
break; }
case "-": }
rightop = (num1 - num2).ToString(); }
Калькулятор.
Вступ у мову XAML
XAML (eXtensible Application Markup Language) - мова розмітки, яка використовується для
ініціалізації об'єктів в технологіях на платформі .NET. Стосовно до WPF (а також до
Silverlight) ця мова використовується насамперед для створення користувальницького
інтерфейсу декларативним шляхом. Хоча функціональність XAML тільки графічними
інтерфейсами не обмежується: ця мова також використовується в технологіях WCF і WF,
де він ніяк не пов'язаний з графічним інтерфейсом. Тобто його область ширше. Стосовно
до WPF ми будемо говорити про нього найчастіше саме як про мову розмітки, яка
дозволяє створювати декларативним шляхом інтерфейс, зразок HTML в веб-
програмуванні. Однак знову ж таки повторюся, зводити XAML до одного інтерфейсу було
б неправильно, і далі на прикладах ми це побачимо.
Вступ у мову XAML
XAML - не є обов'язковою частиною програми, ми взагалі можемо обходитися без нього,
створюючи всі елементи в файлі пов'язаного з ним коду на мові C#. Однак використання
XAML все-таки несе деякі переваги:
- Можливість відокремити графічний інтерфейс від логіки програми, завдяки чому над
різними частинами програми можуть відносно автономно працювати різні фахівці: над
інтерфейсом - дизайнери, над кодом логіки - програмісти.
- Компактність, зрозумілість, код на XAML відносно легко підтримувати.
- При компіляції програми в Visual Studio код в xaml-файли також компілюється в
бінарне представлення коду xaml, яке називається BAML (Binary Application Markup
Language). І потім код baml вбудовується в фінальну збірку програми - exe або dll-файл.
Вступ у мову XAML
При створенні нового проекту WPF він вже містить файли з кодом xaml. Так, створюваний за замовчуванням в проекті файл

MainWindow.xaml буде мати наступну розмітку:

<Window x:Class="XamlApp.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:XamlApp"

mc:Ignorable="d"

Title="MainWindow" Height="350" Width="525">

<Grid>

</Grid>

</Window>
Вступ у мову XAML
Якщо ви зовсім не знайомі з xaml і з xml, то навіть цей невеликий мінімальний код вікна може
викликати труднощі.
Подібно структурі веб-сторінці на html, тут є певна ієрархія елементів. Елементів верхнього рівня є
Window, який являє собою вікно програми. При створенні інших вікон у додатку нам доведеться
завжди починати оголошення інтерфейсу з елемента Window, оскільки це елемент самого верхнього
рівня.
Крім Window існує ще два елемента верхнього рівня:
- Page
- Application
Елемент Window має вкладений порожній елемент Grid, а також подібно html-елементів ряд атрибутів
(Назва, Width, Height) - вони задають заголовок, ширину і висоту вікна відповідно.
Вступ у мову XAML
Важливо розуміти, що ці простори імен не еквівалентні тим просторів імен, які підключаються
за допомогою директиви using в c#. Так, наприклад,
http://schemas.microsoft.com/winfx/2006/xaml/presentation підключає в проект з простору імен:
System.Windows, System.Windows.Automation, System.Windows.Controls,
System.Windows.Controls.Primitives, System.Windows.Data, System.Windows.Documents,
System.Windows.Forms.Integration, System.Windows.Ink, System.Windows.Input,
System.Windows.Media, System.Windows.Media.Animation, System.Windows.Media.Effects,
System.Windows.Media.Imaging, System.Windows.Media.Media3D,
System.Windows.Media.TextFormatting, System.Windows.Navigation, System.Windows.Shapes,
System.Windows.Shell
Вступ у мову XAML
XAML пропонує дуже просту і ясну схему визначення різних елементів і їх
властивостей. Кожен елемент, як і будь-який елемент XML, повинен мати
відкритий і закритий тег, як у випадку з елементом Window:
<Window></Window>
Елемент може мати сокращенню форму з закриваючим слешем в кінці зразок:
<Window />
Але на відміну від елементів xml кожен елемент в XAML відповідає певному класу
C#. Наприклад, елемент Button відповідає класу System.Windows.Controls.Button. А
властивості цього класу відповідають атрибутам елемента Button.
Вступ у мову XAML
Наприклад, додамо кнопку у створювану за замовчуванням розмітку вікна:

<Window x:Class="XamlApp.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:XamlApp"

mc:Ignorable="d"

Title="MainWindow" Height="350" Width="525">

<Grid x:Name="grid1">

<Button x:Name="button1" Width="100" Height="30" Content="Кнопка" /> </Grid> </Window>


Вступ у мову XAML
При визначенні інтерфейсу в XAML ми можемо зіткнутися з деякими обмеженнями. В частості, ми не
можемо використовувати спеціальні символи, такі як символ амперсанда &, лапки " і кутові дужки <>.
Наприклад, ми хочемо, щоб текст кнопки був наступним: <"Hello">. У кнопки є властивість Content, яке
задає вміст кнопки. І можна припустити, що нам треба написати так:
<Button Content="<"Hello">" />
Але такий варіант є помилковим і навіть не скомпилирутся. У цьому випадку нам треба
використовувати спеціальні коди символів:
< &lt;
> &gt;
& &amp;
" &quot;
Вступ у мову XAML
Наприклад:
<Button Content="&lt;&quot;Hello&quot;&gt;" />
Ще одна проблема, з якою ми можемо зіткнутися в XAML - додавання прогалин. Візьмемо, наприклад,
таке визначення кнопки:
<Button> Hello World </Button>
Тут властивість Content задається неявно у вигляді вмісту між тегами <Button>....</Button>. Але незважаючи
на те, що у нас кілька пробілів між словами "Hello" і "World", XAML за замовчуванням буде прибирати всі
ці прогалини. І щоб зберегти прогалини, нам треба використовувати атрибут xml:space="preserve":
<Button xml:space="preserve">
Hello World
</Button>
Взаємодія XAML та С#

<Window x:Class="XamlApp.MainWindow” – MainWindow.xaml


namespace XamlApp
{
public partial class MainWindow : Window - MainWindow.xaml.cs
{
public MainWindow()
{
InitializeComponent();
}
}
}
Взаємодія XAML та С#
<Window x:Class="XamlApp.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:XamlApp"

mc:Ignorable="d"

Title="MainWindow" Height="350" Width="525">

<Grid x:Name="grid1">

<TextBox x:Name="textBox1" Width="150" Height="30" VerticalAlignment="Top" Margin="20" />

<Button x:Name="button1" Width="100" Height="30" Content="Кнопка" Click="Button_Click" />

</Grid> </Window>
Взаємодія XAML та С#
using System.Windows;

namespace XamlApp {

public partial class MainWindow : Window {

public MainWindow() {

InitializeComponent();

private void Button_Click(object sender, RoutedEventArgs e) {

string text = textBox1.Text;

if (text != "") {

MessageBox.Show(text);

} } } }
Взаємодія XAML та С#. Динамічне додавання
<Grid x:Name="layoutGrid"> – MainWindow.xaml

using System.Windows;

using System.Windows.Controls; - MainWindow.xaml.cs

namespace XamlApp {

public partial class MainWindow : Window {

public MainWindow() {

InitializeComponent();

Button myButton = new Button();

myButton.Width = 100; myButton.Height = 30;

myButton.Content = "Кнопка"; layoutGrid.Children.Add(myButton);

} } }
Складні типи. Конвертери типів
У попередніх темах було розглянуто створення елементів в XAML. Наприклад,
ми могли б визначити кнопку наступним чином:
<Button x:Name="myButton" Width="120" Height="40" Content="Кнопка"
HorizontalAlignment="Center" Background="Red" />
З допомогою атрибутів ми можемо задати різні властивості кнопки. Height і
Width є простими властивостями. Вони зберігають числове значення. А
наприклад, властивості HorizontalAlignment або Background є більш складними
за своєю структурою. Так, якщо ми будемо визначати цю ж кнопку в коді c#, то
нам треба використовувати наступний набір інструкцій:
Складні типи. Конвертери типів
Button myButton = new Button();
myButton.Content = "Кнопка";
myButton.Width = 120; myButton.Height = 40;
myButton.HorizontalAlignment = HorizontalAlignment.Center;
myButton.Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
Щоб вирівняти кнопку по центру, застосовується перерахування HorizontalAlignment, а для установки
фонового кольору - клас SolidColorBrush. Хоча в коді XAML ми нічого такого не побачили і
встановлювали ці властивості набагато простіше за допомогою рядків: Background="Red". Справа в
тому, що по відношенню до коду XAML застосовуються спеціальні об'єкти - type conventer або
конвертори типів, які можуть перетворити значення з XAML до тих типів тих об'єктів, які
використовуються в коді C#.
Складні типи. Конвертери типів
В WPF є вбудовані конвертери для більшості типів даних: Brush, Color, FontWeight і т. д. Всі
конвертери типів є похідними від класу TypeConverter. Наприклад, конкретно для
перетворення значення
Background="Red" в об'єкт SolidColorBrush використовується похідний клас BrushConverter.
При необхідності можна створити свої конвертери для якихось власних типів даних.
Фактично установка значення в XAML Background="Red" зводилася б до наступного
виклику в коді С#:
myButton.Background = (Brush)System.ComponentModel.TypeDescriptor
.GetConverter(typeof(Brush)).ConvertFromInvariantString("Red");
Складні типи. Конвертери типів
В даному випадку програма намагається отримати конвертер для типу
Brush (базового класу для SolidColorBrush) і потім перетворити рядок "Red"
в конкретний колір. Для отримання потрібного конвертера, програма
звертається до метаданих класу Brush. Зокрема, він має наступний атрибут:
[TypeConverter(typeof(BrushConverter))]
public abstract class Brush
Даний атрибут дозволяє системі визначити, який тип конвертера
використовувати.
Складні типи. Конвертери типів
У той же час ми можемо більш явно використовувати ці об'єкти в коді XAML:
<Button x:Name="myButton" Width="120" Height="40" Content="Кнопка">
<Button.HorizontalAlignment>
<HorizontalAlignment>Center</HorizontalAlignment>
</Button.HorizontalAlignment>
<Button.Background>
<SolidColorBrush Opacity="0.5" Color="Red" />
</Button.Background>
</Button>
Перевагою такого підходу є те, що у об'єктів ми можемо встановити додаткові параметри.
Простори імен із C# в XAML
За замовчуванням в WPF в XAML підключається встановлений набір просторів імен
xml. Але ми можемо задіяти будь-які інші простори імен і їх функціональність в тому
числі і стандартні простору імен платформи .NET, наприклад, System або
System.Collections. Наприклад, за замовчуванням у визначенні елемента Window
підключається локальне простір імен:
xmlns:local="clr-namespace:XamlApp"
Локальне простір імен, як правило, називається по імені проекту (в моєму випадку
проект називається XamlApp) і дозволяє підключити всі класи, які визначені в коді C#
в нашому проекті. Наприклад, додамо в проект наступний клас:
Простори імен із C# в XAML
public class Phone
{
public string Name { get; set; }
public int Price { get; set; }

public override string ToString()


{
return $"Смартфон {this.Name}; цена: {this.Price}";
}
}
Простори імен із C# в XAML
<Window x:Class="XamlApp.MainWindow" xmlns= <Button.Content>
http://schemas.microsoft.com/winfx/2006/xaml/presen <local:Phone Name="Lumia 950" Price="700"/>
tation </Button.Content>
</Button>
xmlns:x="http://schemas.microsoft.com/winfx/2006/xa </Grid>
ml" </Window>
xmlns:d="http://schemas.microsoft.com/expression/ble
nd/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup
-compatibility/2006"
xmlns:local="clr-namespace:XamlApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="layoutGrid">
Простори імен із C# в XAML
Вступ в компоновку
Щоб перейти вже безпосередньо до створення красивих інтерфейсів та їх компонентів,
спочатку необхідно познайомитися з компонуванням. Компонування (layout) являє собою
процес розміщення елементів всередині контейнера. Можливо, ви звертали увагу, що
одні програми і веб-сайти на різних екранах з різним дозволом виглядають по-різному:
десь краще, десь гірше. В більшості своїй такі програми використовують жорстко
закодовані в коді розміри елементів управління. WPF йде від такого підходу на користь так
званого "гумового дизайну", де весь процес позиціонування елементів здійснюється за
допомогою компонування.
Завдяки компонуванню ми можемо зручним нам чином налаштувати елементи
інтерфейсу, позиціонувати їх певним чином. Наприклад, елементи компоновки в WPF
дозволяють при ресайзе - стиску або розтягу масштабувати елементи, що дуже зручно, а
візуально не створює жодних нерівностей типу незаповнених порожнин на формі.
Вступ в компоновку
В WPF компонування здійснюється за допомогою спеціальних контейнерів.
Фреймворк надає нам такі
контейнери: Grid, UniformGrid, StackPanel, WrapPanel, DockPanel и Canvas.
Різні контейнери можуть містити усередині себе інші контейнери. Крім
даних контейнерів існує ще ряд елементів, такі як TabPanel, які можуть
включати інші елементи і навіть контейнери компонування, однак на саму
компонування не настільки впливають на відміну від вище перерахованих.
Крім того, якщо нам не вистачає стандартних контейнерів, ми можемо
визначити свої з потрібною функціональністю нам.
Контейнери компонування дозволяють ефективно розподілити доступне
простір між елементами, знайти для нього найбільш бажані розміри.
Вступ в компоновку
Наочним прикладом застосування компонування може бути зроблене у
першій главі додаток калькулятора, де ми не вказуємо явним чином
розміри кнопок, а покладаємося на контейнер Grid, який і здійснює всю
розстановку і масштабування дочірніх елементів.
Вступ в компоновку
В WPF при компонуванні і розташуванні елементів всередині вікна нам треба
дотримуватися наступних принципів:
• Небажано вказувати явні розміри елементів (за виключенням мінімальних і
максимальних розмірів). Розміри повинні визначатися контейнерами.
• Небажано вказувати явні позицію і координати елементів всередині вікна.
Позиціонування елементів цілком повинно бути прерогативою контейнерів. І
контейнер сам повинен визначати, як елемент буде розташовуватися. Якщо нам
треба створити складну систему компоновки, то ми можемо вкладати один в інший
контейнер, щоб домогтися максимально зручного розташування елементів
управління.
Вступ в компоновку
Процес компонування
Процес компонування проходить два етапи: вимірювання (measure) і
розстановка (arrange). На етапі вимірювання контейнер виробляє вимір
бажаного для дочірніх елементів місця. Однак не завжди контейнер має
достатньо місця, щоб розставити всі елементи за їх переважним
розміром, тому їх розміри доводиться усекать. Потім відбувається етап
безпосередньої розстановки дочірніх елементів всередині контейнера.
Компоновка. Grid
Це найбільш потужний і часто використовуваний контейнер, що нагадує звичайну таблицю. Він містить

стовпці і рядки, кількість яких визначає розробник. Для визначення рядків використовується властивість

 RowDefinitions, а для визначення стовпців - властивість ColumnDefinitions:

<Grid.RowDefinitions>

<RowDefinition></RowDefinition> <RowDefinition></RowDefinition>

<RowDefinition></RowDefinition>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition>

<ColumnDefinition></ColumnDefinition>

</Grid.ColumnDefinitions>
Компоновка. Grid
<Grid ShowGridLines="True">

<Grid.RowDefinitions>

<RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition>

</Grid.ColumnDefinitions>

<Button Grid.Column="0" Grid.Row="0" Content="Рядок 0 Стовпець 0" />

<Button Grid.Column="0" Grid.Row="1" Content="Об'єднання трьох стовпців" Grid.ColumnSpan="3" />

<Button Grid.Column="2" Grid.Row="2" Content="Рядок 2 Стовпець 2" />

</Grid>
Компоновка. Grid
Встановлення розмірів
Але якщо в попередньому випадку у нас рядки і стовпці були рівні один одному, то тепер спробуємо
їх налаштувати стовпчики по ширині, а рядки - по висоті. Є кілька варіантів настройки розмірів.
Автоматичні розміри
Тут стовпець або рядок займає те місце, яке їм потрібно
<ColumnDefinition Width="Auto" />
<RowDefinition Height="Auto" />
Абсолютні розміри
В даному випадку висота і ширина зазначаються в одиницях, незалежних від пристрою:
<ColumnDefinition Width="150" />
<RowDefinition Height="150" />
Компоновка. Grid

Також абсолютні розміри можна задати в пікселях, дюймах, сантиметрах або


точках:
Пікселі - px
Дюйми - in
Сантиметри - cm
Точки - pt
Наприклад,
<ColumnDefinition Width="1 in" />
<RowDefinition Height="10 px" />
Компоновка. Grid
Пропорційні розміри.
Наприклад, нижче задаються два стовпці, другий з яких має ширину чверть від ширини першого:
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.25*" />
Якщо рядок або стовпець має висоту, рівну *, то дана рядок або стовпець буде займати все місце,
що залишилося. Якщо у нас є кілька сток або стовпців, висота яких дорівнює *, то все доступне
місце ділиться порівну між усіма такими термінами та стовпців. Використання коефіцієнтів
(0.25*) дозволяє зменшити або збільшити виділене місце на цей коефіцієнт. При цьому всі
коефіцієнти складаються (коефіцієнт * аналогічний 1*) і потім весь простір ділиться на суму
коефіцієнтів.
Компоновка. Grid
Наприклад, якщо у нас три колонки:
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="1.5*" />
В цьому випадку сума коефіцієнтів дорівнює 1* 0.5* 1.5* = 3*. Якщо у нас грід
має ширину 300 одиниць, то коефіцієнт для 1* буде відповідати простору 300 /
3 = 100 одиниць. Тому перший стовпець буде мати ширину в 100 одиниць,
другий - 100*0.5=50 одиниць, а третій - 100 * 1.5 = 150 одиниць.
Компоновка. Grid. Поєднання розмірів
Компоновка. GridSplitter

Елемент GridSplitter допомагає створювати інтерфейси на зразок


елемента SplitContainer в WinForms, тільки більш функціональні. Він являє
собою певний роздільник між стовпцями або рядками, шляхом зсуву
якого можна регулювати ширину стовпців і висоту рядків. В якості
прикладу можна навести стандартний інтерфейс провідника Windows, де
розділювальна смуга відокремлює деревовидний список папок від панелі
зі списком файлів. Наприклад,
Компоновка. GridSplitter
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Ліва кнопка" />
<GridSplitter Grid.Column="1" ShowsPreview="False" Width="3"
HorizontalAlignment="Center" VerticalAlignment="Stretch" />
<Button Grid.Column="2" Content="Права кнопка" />
</Grid>
Компоновка. GridSplitter Рухаючи центральну лінію, що
розділяє праву і ліву частини, ми
можемо встановлювати їх
ширину.
Отже, щоб використовувати
елемент GridSplitter, нам треба
помістити його в клітинку Gride.
По суті це звичайний елемент,
такий же, як кнопка. Як вище, у
нас три клітинки (так як три
стовпця і один рядок), і GridSplitter
поміщений у другу комірку.
Компоновка. StackPanel
<StackPanel>
<Button Background="Blue" Content="1" />
<Button Background="White" Content="2" />
<Button Background="Red" Content="3" />
</StackPanel>
Компоновка. StackPanel
<StackPanel Orientation="Horizontal">
<Button Background="Blue"
MinWidth="30" Content="1" />
<Button Background="White"
MinWidth="30" Content="2" />
<Button Background="Red"
MinWidth="30" Content="3" />
</StackPanel>
Компоновка. DockPanel
Цей контейнер притискає свій вміст до певної стороні зовнішнього контейнера. Для цього у
вкладених елементів треба встановити сторону, до якої вони будуть притискатися з допомогою
властивості DockPanel.Dock. Наприклад,
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Top" Background="AliceBlue" Content="Верхня кнопка" />
<Button DockPanel.Dock="Bottom" Background="BlanchedAlmond" Content="Нижня кнопка" />
<Button DockPanel.Dock="Left" Background="Aquamarine" Content="Ліва кнопка" />
<Button DockPanel.Dock="Right" Background="DarkGreen" Content="Права кнопка" />
<Button Background="LightGreen" Content="Центр" />
</DockPanel>
Компоновка.
DockPanel
Компоновка. WrapPanel
Ця панель, подібно StackPanel, має всі елементи в одному рядку або стовпчику в залежності від того, яке

значення має властивість Orientation - Horizontal або Vertical. Головна відмінність від StackPanel - якщо елементи

не поміщаються в рядку або стовпці, створюються нові стовпець або рядок для не помістилися елементів.

<WrapPanel>

<Button Background="AliceBlue" Content="Кнопка 1" />

<Button Background="Blue" Content="Кнопка 2" />

<Button Background="Aquamarine" Content="Кнопка 3" Height="30"/>

<Button Background="DarkGreen" Content="Кнопка 4" Height="20"/>

<Button Background="LightGreen" Content="Кнопка 5"/>

<Button Background="RosyBrown" Content="Кнопка 6" Width="80" />

<Button Background="GhostWhite" Content="Кнопка 7" />

</WrapPanel>
Компоновка.
WrapPanel
Компоновка. Canvas
Контейнер Canvas є найбільш простим контейнером. Для розміщення на ньому необхідно вказати для
елементів точні координати відносно сторін Canvas. Для встановлення координат елементів
використовуються властивості Canvas.Left, Canvas.Right, Canvas.Bottom, Canvas.Top. Наприклад, властивість
Canvas.Left вказує, на скільки одиниць від лівої сторони контейнера буде знаходитися елемент, а
властивість Canvas.Top - наскільки одиниць нижче верхньої межі контейнера знаходиться елемент.

При цьому в якості одиниць використовуються пікселі, а незалежні від пристрою одиниці, які допомагають
ефективно управляти масштабуванням елементів. Кожна така одиниця дорівнює 1 /96 дюйма, і при
стандартній установці в 96 dpi ця незалежна від пристрою одиниця буде дорівнює фізичній пікселю, так як
1/96 дюйма * 96 dpi (96 точок на дюйм) = 1. У теж час при роботі на інших моніторах або при інших
встановлених розміри, встановлені у додатку, будуть ефективно масштабуватися. Наприклад, при дозволі
120 dpi одна умовна одиниця дорівнює 1,25 пікселя, так як 1/96 дюйма * 120 dpi= 1,25 пікселя.
Компоновка. Canvas
Якщо елемент не використовує властивості Canvas.Top і інші, то за замовчуванням властивості Canvas.Left і

Canvas.Top будуть дорівнюють нулю, тобто він буде перебувати у верхньому лівому куті.

Також треба враховувати, що не можна одночасно ставити Canvas.Left і Canvas.Right або Canvas.Bottom і

Canvas.Top. Якщо подібне станеться, то останнім задану властивість не буде враховуватися. Наприклад:

<Canvas Background="Lavender">

<Button Background="AliceBlue" Content="Top 20 Left 40" Canvas.Top="20" Canvas.Left="40" />

<Button Background="LightSkyBlue" Content="Top 20 Right 20" Canvas.Top="20" Canvas.Right="20"/>

<Button Background="Aquamarine" Content="Bottom 30 Left 20" Canvas.Bottom="30" Canvas.Left="20"/>

<Button Background="LightCyan" Content="Bottom 20 Right 40" Canvas.Bottom="20" Canvas.Right="40"/>

</Canvas>
Компоновка. Canvas
Властивості компоновки елементів
Ширина і висота

У елемента можна встановити ширину за допомогою властивості Width і висоту з допомогою


властивості Height. Ці властивості приймають значення типу double. Хоча загальна
рекомендація полягає в тому, що бажано уникати жорстко закодованих в коді ширини та
висоти.

Також ми можемо визначити можливий діапазон ширини та висоти за допомогою властивостей


MinWidth/MaxWidth и MinHeight/MaxHeight. І при розтягуванні або стисненні контейнерів
елементи з даними заданими властивостями не будуть виходити за межі встановлених значень.
Властивості компоновки елементів
Можливо, виникає питання, а в яких одиницях виміру встановлюються ширина і висота?
Та й загалом які одиниці вимірювання використовуються? В WPF можна
використовувати декілька одиниць виміру: сантиметри (cm), пункти (pt), дюйми (in) і
пікселі (px). Наприклад, задамо розміри в інших одиницях: <Button Content="Кнопка"
Width="5cm" Height="0.4in" />

Якщо одиниця вимірювання не задана явно, а просто стоїть число, то за умовчанням


використовуються пікселі. Але ці пікселі не дорівнюють звичайним пікселям, а є свого
роду "логічних пікселями", незалежними від конкретного пристрою. Кожен піксель
являє 1/96 дюйма незалежно від дозволу екрану.
Властивості компоновки елементів
Вирівнювання. HorizontalAlignment

З допомогою спеціальних властивостей ми можемо вирівняти елемент відносно визначеної сторони контейнера по

горизонталі або вертикалі.

Свойство HorizontalAlignment вирівнює елемент по горизонталі щодо правої або лівої сторони контейнера і відповідно

може приймати значення Left, Right, Center (положення по центру), Stretch (розтягнення по всій ширині). Наприклад:

<Grid>

<Button Content="Left" Width="60" Height="30" HorizontalAlignment="Left" />

<Button Content="Center" Width="60" Height="30" HorizontalAlignment="Center" />

<Button Content="Right" Width="60" Height="30" HorizontalAlignment="Right" />

<Button Content="Stretch" Height="30" HorizontalAlignment="Stretch" Margin="10 -80 10 0" />

</Grid>
Властивості компоновки елементів
VerticalAlignment
<Grid>
<Button Content="Bottom" Width="60" Height="30" VerticalAlignment="Bottom" />
<Button Content="Center" Width="60" Height="30" VerticalAlignment="Center" />
<Button Content="Top" Width="60" Height="30" VerticalAlignment="Top" />
<Button Content="Stretch" Width="60" VerticalAlignment="Stretch" Margin="150 10 0 10" />
</Grid>
Властивості компоновки елементів
Відступи margin
Властивість Margin встановлює відступи навколо елемента. Синтаксис:
Margin="левый_отступ верхний_отступ правый_отступ нижний_отступ". Наприклад,
встановимо відступи у однієї кнопки зліва і зверху, а в іншої кнопки праворуч і знизу:
<Grid>
<Button Content="15 10 0 0" Width="60" Height="30" Margin ="15 10 0 0"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Button Content="0 0 20 10" Width="60" Height="30" Margin ="0 0 20 10"
HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
Властивості компоновки елементів
Властивості компоновки елементів
За замовчуванням для всіх нових елементів Panel.ZIndex="0". Однак призначивши
даної властивості більш високе значення, ми можемо пересунути його на передній
план. Елементи з більшим значенням цієї властивості будуть перекривати ті елементи,
у яких менше значення цієї властивості:
<Grid>
<Button Width="60" Height="30" Panel.ZIndex="2" Margin="10 10 0 0">Один</Button>
<Button Width="60" Height="30" Panel.ZIndex="1" Margin="45 45 0 0">Два</Button>
<Button Width="60" Height="30" Panel.ZIndex="0" Margin="75 75 0 0">Три</Button>
</Grid>
Властивості компоновки елементів
Елементи управління
Щоб якось взаємодіяти з користувачем, отримувати від користувача введення з
клавіатури або миші і використовувати введені дані в програмі, нам потрібні елементи
управління. WPF пропонує нам багатий стандартний набір елементів управління
Всі елементи управління можуть бути умовно розділені на кілька підгруп:
- Елементи керування вмістом, наприклад кнопки (Button), мітки (Label)
- Спеціальні контейнери, які містять інші елементи, але на відміну від елементів Grid
або Canvas не є контейнерами компонування - ScrollViewer,GroupBox
- Декоратори, чиє призначення створення певного фону навколо вкладених елементів,
наприклад, Border або Viewbox.
Елементи управління
Елементи керування списками, наприклад, ListBox, ComboBox.
Текстові елементи управління, наприклад, TextBox, RichTextBox.
Елементи, засновані на діапазонах значень, наприклад, ProgressBar, Slider.
Елементи для робіт з датами, наприклад, DatePicker і Calendar.
Інші елементи управління, які не увійшли у попередні підгрупи, наприклад,
Image.
Всі елементи управління успадковуються від загального класу
System.Window.Controls.Control і мають ряд загальних властивостей. А загальну
ієрархію елементів управління можна представити наступним чином:
Елементи управління
Name

Напевно найважливіша властивість. За встановленим імені згодом можна буде звертатися до

елементу, як в коді, так і в розмітки xaml. Наприклад, в xaml-коді у нас визначена наступна кнопка:

<Button x:Name="button1" Width="60" Height="30" Content="Текст" Click="button1_Click" />

Тут у нас заданий атрибут Click з назвою методу обробника button1_Click, який буде визначений у

файлі коду C# і буде викликатися по натисненню кнопки. Тоді у зв'язаному файлі C# код ми можемо

звернутися до цієї кнопки:

private void button1_Click(object sender, RoutedEventArgs e) {

button1.Content = "Привіт!";

}
Елементи управління
FieldModifier
Свойство FieldModifier задает модификатор доступа к объекту:
<StackPanel>
<Button x:FieldModifier="private" x:Name="button1" Content="Hello World" />
<Button x:FieldModifier="internal" x:Name="button2" Content="Hello WPF" />
</StackPanel>
В якості значення використовуються стандартні клавіші доступу мови C#: private, protected, internal,
protected internal і public. У цьому разі оголошення кнопок з модифікаторами буде рівноцінно наступного їх
визначення в коді:
private Button button1;
internal Button button2;
Якщо для елемента не визначений атрибут x:FieldModifier, то за замовчуванням він дорівнює "protected
internal".
Елементи управління
Властивості налаштування шрифтів
FontFamily - визначає сімейство шрифту (наприклад, Arial, Verdana і т. д.)
FontSize - визначає висоту шрифту
FontStyle - визначає нахил шрифту, приймає одне з трьох значень - Normal,
Italic,Oblique.
FontWeight - визначає товщину шрифту і приймає ряд значень, як Black,Bold
та ін.
FontStretch - визначає, як буде розтягувати або стискати текст, наприклад,
значення Condensed стискає текст, а Expanded - расстягивает.
Елементи управління
Cursor
Це властивість дозволяє нам отримати або встановити курсор для елемента керування в одне із
значень, наприклад, Hand, Arrow, Wait та ін Наприклад, установка курсору в коді С#:
button1.Cursor=Cursors.Hand;
FlowDirection
Дана властивість визначає напрямок тексту. Якщо воно дорівнює RightToLeft, текст починається з
правого краю, якщо - LeftToRight, то з лівого.
<StackPanel>
<TextBlock FlowDirection="RightToLeft">RightToLeft</TextBlock>
<TextBlock FlowDirection="LeftToRight">LeftToRight</TextBlock>
</StackPanel>
Елементи управління
Кольори фону і шрифту
Властивості Background і Foreground задають відповідно колір фону і тексту в елементі
керування.
Найпростіший спосіб завдання кольору в коді xaml: Background="#ffffff". В якості
значення властивість Background (Foreground) може приймати запис у вигляді
шістнадцяткового значення в форматі #rrggbb, де rr - червона складова, gg - зелена
складова, а bb - синя. Також можна задати колір у форматі #aarrggbb. Або можна
використовувати безпосередньо назви кольорів:
<Button Width="60" Height="30" Background="LightGray" Foreground="DarkRed"
Content="Цвет" />
Події у WPF

Підключення обробників подій


Підключити обробники подій можна декларативно у файлі xaml-коду, а
можна стандартним способом у файлі відокремленого коду.
Декларативне підключення:
<Button x:Name="Button1" Content="Click" Click="Button_Click" />
І підключимо ще один обробник в коді, щоб при натисканні на кнопку
спрацьовували відразу два обробника:
Події у WPF
public partial class MainWindow : Window {

public MainWindow() {

InitializeComponent();

Button1.Click += Button1_Click;

private void Button_Click(object sender, RoutedEventArgs e) { // обробник, що підключається в XAML

MessageBox.Show("Hi from Button_Click");

private void Button1_Click(object sender, RoutedEventArgs e) { // обробник, що підключається в конструкторі

MessageBox.Show("Hi from Button1_Click");

} }
Події у WPF
Маршрутизація подій

Модель подій WPF відрізняється від подій WinForms не тільки декларативним підключенням. Події,

виникнувши на одному елементі, можуть оброблятися на іншому. Події можуть підніматися і опускатися по

дереву елементів.

Так, маршрутизовані події поділяються на три види:

Прямі (direct events) - вони виникають і отрабытывают на одному елементі і нікуди далі не передаються. Діють

як звичайні події.

Піднімаються (киплячому events) - виникають на одному елементі, а потім передаються далі до батьківського

елементу-контейнера і далі, поки не досягне найвищого батька в дереві елементів. Опускаються, тунельні

(tunneling events) - починає відпрацьовувати в кореневому елементі вікна програми і йде далі по вкладених

елементів, поки не досягне елемента, що викликав цю подію.


Події у WPF. Події, які піднімаються
<Grid> <Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" />

<ColumnDefinition />

</Grid.ColumnDefinitions>

<StackPanel Grid.Column="0" VerticalAlignment="Center" MouseDown="Control_MouseDown">

<Button x:Name="button1" Width="80" Height="50" MouseDown="Control_MouseDown" Margin="10" >

<Ellipse Width="30" Height="30" Fill="Red" MouseDown="Control_MouseDown" />

</Button>

</StackPanel>

<TextBlock x:Name="textBlock1" Grid.Column="1" Padding="10" />

</Grid>
Події у WPF. Події, які піднімаються
private void Control_MouseDown(object sender, MouseButtonEventArgs e) {
textBlock1.Text = textBlock1.Text + "sender: " + sender.ToString() + "\n";
textBlock1.Text = textBlock1.Text + "source: " + e.Source.ToString() + "\n\n";
}
Події у WPF. Тунельні події.
<StackPanel Grid.Column="0" VerticalAlignment="Center" PreviewMouseDown="Control_MouseDown">
<Button x:Name="button1" Width="80" Height="50" PreviewMouseDown="Control_MouseDown"
Margin="10" >
<Ellipse Width="30" Height="30" Fill="Red" PreviewMouseDown="Control_MouseDown" />
</Button> </StackPanel>
Події у WPF. Прикріплюючі події.

<StackPanel x:Name="menuSelector" Grid.Column="0" RadioButton.Checked="RadioButton_Click">


<RadioButton GroupName="menu" Content="Салат Олів'є" />
<RadioButton GroupName="menu" Content="Котлета по-київськи" />
<RadioButton GroupName="menu" Content="Піца з овочами" />
<RadioButton GroupName="menu" Content="М'ясний рулет" />
</StackPanel>
private void RadioButton_Click(object sender, RoutedEventArgs e) {
RadioButton selectedRadio = (RadioButton)e.Source;
textBlock1.Text = "Ви вибрали: " + selectedRadio.Content.ToString();
}
Події у WPF

KeyDown, PreviewKeyDown, KeyUp, PreviewKeyUp, TextInput,


PreviewTextInput – події клавіатури

MouseMove, MouseWheel, MouseUp, MouseDown, MouseLeave,


MouseEnter, DragEnter, DragOver, GotFocus, LostFocus … - події миші
та фокусу
Робота з графікою. Фігури

Одним із способів побудови двовимірної графіки у вікні - це використання


фігур. Фігури фактично є звичайними елементами як наприклад кнопка
або текстове поле. До фігур відносять такі елементи як Polygon
(Багатокутник), Ellipse (овал), Rectangle (прямокутник), Line (звичайна
лінія), Polyline (кілька зв'язаних ліній).
Робота з графікою. Фігури
<Ellipse Width="200"
Height="200" Fill="LightPink"
StrokeThickness="5"
StrokeDashArray="4 2"
Stroke="Gray"
StrokeDashCap="Round" />
Робота з графікою. Фігури
Програмне малювання
Створення фігур програмним чином здійснюється так само, як і створюються й додаються всі
інші елементи:
Ellipse el = new Ellipse();
el.Width = 50;
el.Height = 50;
el.VerticalAlignment = VerticalAlignment.Top;
el.Fill = Brushes.Green;
el.Stroke = Brushes.Red;
el.StrokeThickness = 3;
grid1.Children.Add(el);
Робота з графікою. Координатна площина
Line vertL =new Line(); horL.Stroke = Brushes.Black;
vertL.X1 = 10; grid1.Children.Add(horL);
vertL.Y1 = 150; for(byte i = 2;i< 14;i++)
vertL.X2 = 10; {
vertL.Y2 = 10; Line a =new Line();
vertL.Stroke = Brushes.Black; a.X1 = i * 10;
grid1.Children.Add(vertL); a.X2 = i * 10;
Line horL =new Line(); a.Y1 = 155;
horL.X1 = 10; a.Y2 = 145;
horL.X2 = 150; a.Stroke = Brushes.Black;
horL.Y1 = 150; grid1.Children.Add(a);
horL.Y2 = 150; }
Робота з графікою. Координатна площина
for(byte i = 2;i< 14;i++) { vertArr.Points.Add(new Point(10, 10));
Line a =new Line(); vertArr.Points.Add(new Point(15, 15));
a.X1 = 5; a.X2 = 15; vertArr.Stroke = Brushes.Black;
a.Y1 = i * 10; grid1.Children.Add(vertArr);
a.Y2 = i * 10; Polyline horArr =new Polyline();
a.Stroke = Brushes.Black; horArr.Points = new PointCollection();
grid1.Children.Add(a); horArr.Points.Add(new Point(145, 145));
} horArr.Points.Add(new Point(150, 150));
Polyline vertArr =new Polyline(); horArr.Points.Add(new Point(145, 155));
vertArr.Points = new PointCollection(); horArr.Stroke = Brushes.Black;
vertArr.Points.Add(new Point(5, 15)); grid1.Children.Add(horArr);
Геометрії
Клас Geometry - абстрактний, тому в якості об'єкта використовується один з похідних
класів:
- LineGeometry представляє лінію, еквівалент фігури Line
- RectangleGeometry являє прямокутник, еквівалент фігури Rectangle
- EllipseGeometry представляє еліпс, еквівалент фігуриEllipse
- PathGeometry являє шлях, утворює складну геометричну фігуру з найпростіших
фігур
- GeometryGroup створює фігуру, що складається з кількох об'єктів Geometry
- CombinedGeometry створює фігуру, що складається з двох об'єктів Geometry
- StreamGeometry - спеціальний об'єкт Geometry, призначений для збереження
всього геометричного шляху в пам'яті
Геометрії

<StackPanel> <Path Fill="LightPink">


<Path Fill="LightBlue"> <Path.Data>
<Path.Data> <RectangleGeometry Rect="100,20 100,50"
<RectangleGeometry Rect="100,20 100,50" /> RadiusX="10" RadiusY="10" />
</Path.Data> </Path.Data>
</Path> </Path>
</StackPanel>
Геометрії. Комбінація геометрій
CombinedGeometry
CombinedGeometry складається з двох геометрій. У цьому він схожий на GeometryGroup,
який також може об'єднувати дві геометрії. Проте між ними є відмінності. Відмінність
полягає в тому, що об'єкт CombinedGeometry має властивість GeometryCombinedMode,
яке вказує модель перекриття двох геометрій:
- Union: фігура включає обидві геометрії
- Intersect: фігура включає область, яка одночасно належить обом геометриям
- Xor: фігура включає тільки непересекающие області геометрій
- Exclude: фігура включає першу геометрію з винятком тих областей, які належать також і
другий геометрії
Геометрії. Комбінація геометрій
<Grid> <CombinedGeometry.Geometry1>
<Grid.RowDefinitions> <EllipseGeometry Center="50,60"
<RowDefinition /> RadiusX="50" RadiusY="50" />
<RowDefinition /> </CombinedGeometry.Geometry1>
<RowDefinition /> <CombinedGeometry.Geometry2>
<RowDefinition /> <RectangleGeometry Rect="60, 20 120,80" />
</Grid.RowDefinitions> </CombinedGeometry.Geometry2>
<Path Fill="LightPink" Stroke="LightBlue"> </CombinedGeometry>
<Path.Data> </Path.Data>
<CombinedGeometry </Path>
GeometryCombineMode="Union">
<Path Grid.Row="1" Fill="LightPink" </Path.Data> </Path>
Stroke="LightBlue"> <Path Grid.Row="2" Fill="LightPink"
<Path.Data> Stroke="LightBlue">
<CombinedGeometry <Path.Data>
GeometryCombineMode="Xor"> <CombinedGeometry
<CombinedGeometry.Geometry1> GeometryCombineMode="Intersect">
<EllipseGeometry Center="50,60" RadiusX="50" <CombinedGeometry.Geometry1>
RadiusY="50" /> <EllipseGeometry Center="50,60" RadiusX="50"
</CombinedGeometry.Geometry1> RadiusY="50" /> </CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2> <CombinedGeometry.Geometry2>
<RectangleGeometry Rect="60, 20 <RectangleGeometry Rect="60, 20
120,80" /> 120,80" />
</CombinedGeometry.Geometry2> </CombinedGeometry.Geometry2>
</CombinedGeometry> </CombinedGeometry> </Path.Data> </Path>
Геометрії. Комбінація геометрій
<Path Grid.Row="3" Fill="LightPink" <RectangleGeometry Rect="60,
Stroke="LightBlue"> 20 120,80" />
<Path.Data> </CombinedGeometry.Geometry2>
<CombinedGeometry </CombinedGeometry>
GeometryCombineMode="Exclude"> </Path.Data>
<CombinedGeometry.Geometry1> </Path>
<EllipseGeometry Center="50,60" </Grid>
RadiusX="50" RadiusY="50" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
Геометрії.
Комбінація
геометрій
Геометрії. PathGeometry

PathGeometry дозволяє створювати більш складні за характером


геометрії. PathGeometry містить один або кілька компонентів PathFigure.
Об'єкт PathFigure в свою чергу формується з сегментів. Всі сегменти
успадковуються від класу PathSegment і бувають декількох видів:
- LineSegment задає відрізок прямої лінії між двома точками
- ArcSegment задає дугу
- BezierSegment задає криву Безьє
- QuadraticBezierSegment задає квадратичну криву Безьє
Геометрії. PathGeometry
- PolyLineSegment задає сегмент з декількох ліній
- PolyBezierSegment задає сегмент з декількох кривих Безьє
- PolyQuadraticBezierSegment задає сегмент з декількох квадратичних кривих Безьє
Ці сегменти становлять властивість Segment об'єкта PathFigure. Крім того, PathFigure має ще
кілька важливих властивостей:
- StartPoint - точка початку першої фігури
- IsClosed - якщо значення true, то перша і остання точки (якщо вони не збігаються) з'єднуються
- IsFilled - якщо значення true, то площа всередині шляху забарвлюється пензлем, заданою
властивістю Fill у об'єкта Path
Трансформації
Трансформації представляють інструмент зміни положення або елементів WPF.
Трансформації можуть бути корисні в тих ситуаціях, коли треба змінити положення
елемента, або анімувати. Всі трансформації успадковуються від абстрактного базового
класу System.Windows.Media.Transform і представляють наступні класи:
- TranslateTransform: зсуває елементи по горизонталі і вертикалі
- RotateTransform: обертає елемент
- ScaleTransform: виконує операції масштабування
- SkewTransform: змінює позицію елемента шляхом нахилу на певну кількість градусів-
MatrixTransform: змінює координатну систему у відповідності з певною матрицею
- TransformGroup: представляє групу трансформацій
Трансформації. RotateTransform
RotateTransform повертає елемент навколо осі на певну
кількість градусів. Даний об'єкт приймає три основних
параметра:
Angle: кут повороту
CenterX: встановлює центр обертання по осі X
CenterY: встановлює центр обертання по осіY
<Rectangle Width="100" Height="30" Stroke="Blue"
Fill="LightBlue">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" />
</Rectangle.RenderTransform>
</Rectangle>
Трансформації. ScaleTransform
Забезпечує масштабування елемента на певну
величину. Для зміни ширини треба задати
властивість ScaleX, а для зміни довжини -
властивість ScaleY. Крім того, також є властивості
CenterX і CenterY, що дозволяють позиціонувати
елемент.
<Rectangle Width="100" Height="30" Stroke="Blue"
Fill="LightBlue">
<Rectangle.RenderTransform>
<ScaleTransform ScaleX="1.5" ScaleY="1.5" />
</Rectangle.RenderTransform> </Rectangle>
Трансформації. SkewTransform
SkewTransform дозволяє задати нахил
елемента уздовж осі X за допомогою
властивості AngleX, і Y за допомогою
властивості AngleY. А з допомогою
властивостей CenterX і CenterY можна
змінити положення елемента щодо осй X і Y:
<Rectangle Width="100" Height="30"
Stroke="Blue" Fill="LightBlue">
<Rectangle.RenderTransform>
<SkewTransform AngleX="45"/>
</Rectangle.RenderTransform>
</Rectangle>
Трансформації. MatrixTransform
Здійснює матричне перетворення елемента.
Властивості Matrix ми задаємо перші два
стовпці, які застосовуються при
перетворенні. Останній стовпець за
замовчуванням має значення {0 0 1}.
<Rectangle Width="100" Height="30"
Stroke="Blue" Fill="LightBlue">
<Rectangle.RenderTransform>
<MatrixTransform Matrix="1 0 1 2 1 -3"/>
</Rectangle.RenderTransform>
</Rectangle>
Анімація
Наявність вбудованих можливостей анімації представляють одну з ключових особливостей
платформи WPF. Анімації в WPF - це действіетельно потужний засіб, яке при цьому дуже легко
використовувати. Але перед тим, як перейти до створення анімацій, відразу треба сказати про
обмеження:

Одна анімація виконується тільки для одного властивості залежностей

Для анімації властивості необхідний клас анімації, який би підтримував тип цього властивості.
Наприклад, для зміни таких властивостей, як довжина, ширина, які представляють тип double,
призначений клас DoubleAnimation. Для зміни кольору фону або шрифту - ColorAnimation, для
зміни властивості Margin - ThiknessAnimation.
Анімація
За анімацію в WPF відповідає простір імен
System.Windows.Media.Animation. Воно містить досить великий набір класів, що
дозволяють анімувати різні властивості. Але в реальності всі класи анімацій можна
розділити умовно на три групи:

- Класи, які виробляють лінійну інтерполяцію значень, завдяки чому при анімації
властивість плавно змінює своє значення. Як правило, такі класи називаються по
шаблону TypeAnimation, де Type - тип даних, який представляє анимируемое
властивості, наприклад, DoubleAnimation, ByteAnimation, DecimalAnimation,
Int32Animation,
Анімація
- Класи, які виробляють анімацію по ключовим кадрам або фреймами
(покадрова анімація). Такі класи, як правило, називаються по шаблону
TypeAnimationUsingKeyFrames, наприклад, DoubleAnimationUsingKeyFrames,
BooleanAnimationUsingKeyFrames, DecimalAnimationUsingKeyFrames,
ObjectAnimationUsingKeyFrames …
- Класи, які використовують для анімації об'єкт PathGeometry. Такі класи, як
правило, називаються по шаблону TypeAnimationUsingPath, наприклад,
DoubleAnimationUsingPath, MatrixAnimationUsingPath, PointAnimationUsingPath
Анімація
Програмна анімація
Нехай в XAML визначена кнопка:
<Button x:Name="helloButton" Width="70" Height="30" Content="Hello" />
Проанимируем її властивість Width:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace AnimationApp
{
Анімація
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
DoubleAnimation buttonAnimation = new DoubleAnimation();
buttonAnimation.From = helloButton.ActualWidth;
buttonAnimation.To = 150;
buttonAnimation.Duration = TimeSpan.FromSeconds(3);
helloButton.BeginAnimation(Button.WidthProperty, buttonAnimation);
}
}
}
Анімація
У будь-якого класу лінійної анімації є набір властивостей, за допомогою яких ми можемо керувати
анімацією:
From: початкове значення, з якого починається анімація, To: кінцеве значення, Duration: час анімації у
вигляді об'єкта TimeSpan, By: значення, яке вказує, наскільки повинна збільшитися анимируемое
властивість. Властивість By використовується замість властивості To
RepeatBehavior: дозволяє встановити, як анімація буде повторюватися, AccelerationRatio: задає
прискорення анімації, DecelerationRatio: встановлює уповільнення анімації
SpeedRatio: встановлює швидкість анімації. За замовчуванням значення 1.0
AutoReverse: при значенні true анімація виконується в протилежну сторону
FillBehavior: определеяет поведінка після окночания анімації. Якщо воно має значення Stop, то після
закінчення анімації об'єкт повертає колишні значення: buttonAnimation.FillBehavior = FillBehavior.Stop.
Якщо ж воно має значення HoldEnd, то анімація присвоює анимируемому властивості нове значення.
Анімація
Якщо ми хочемо повторення анімації, які можна використовувати властивість RepeatBehavior:
buttonAnimation.RepeatBehavior = new RepeatBehavior(2);
Також ми можемо задати час повторення:
buttonAnimation.RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(7));
Щоб задати плавне зміна властивості у зворотний бік, застосуємо властивість
AutoReverse:
buttonAnimation.AutoReverse = true;
При завершенні анімації генерується подія Completed, яке ми можемо обробити:
private void ButtonAnimation_Completed(object sender, EventArgs e) {
MessageBox.Show("Анімація завершена");
}
Анімація
Для визначення анімації в XAML застосовується об'єкт EventTrigger або тригер
подій. Цей об'єкт має властивість Actions, яке визначає ряд дій, що виникають
в результаті генерації події. Саме виникає дія описується через елемент
BeginStoryboard, який і запускає анімацію.

Безпосередньо для визначення анімації використовується об'єкт Storyboard.


Він оголошує об'єкт анімації з усіма її властивостями і параметрами.
Наприклад, проанимируем ширину кнопки:
Анімація
<Window.Triggers> </Storyboard>
<EventTrigger RoutedEvent="Loaded"> </BeginStoryboard>
<EventTrigger.Actions> </EventTrigger.Actions>
<BeginStoryboard> </EventTrigger>
<Storyboard TargetProperty="Width" </Window.Triggers>
TargetName="helloButton"> <Grid>
<DoubleAnimation From="70" <Button x:Name="helloButton" Width="70"
To="150"
AutoReverse="True" Height="30" Content="Hello" />
RepeatBehavior="0:0:10" </Grid>
Duration="0:0:3"

Completed="ButtonAnimation_Completed" />
Анімація
У об'єкта EventTrigger з допомогою атрибута RoutedEvent визначається подія, яке
буде запускати анімацію. В даному випадку це подія Loaded - завантаження вікна.
Ряд налаштувань анімації встановлює елемент Storyboard: TargetName задає
анимируемый елемент, а TargetProperty визначає властивість елемента, яке буде
анимироваться. В принципі ці параметри також можна було б винести в об'єкт
анімації у вигляді прикріплюються властивостей:
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Width"
Storyboard.TargetName="helloButton"
From="70" To="150" ...>
Анімація
І далі в самому об'єкті Storyboard визначається об'єкт анімації DoubleAnimation з рядом налаштувань. Всі
налаштування в прицнипе тут ті ж, що використовувалися для анімації в минулій темі. Правда, при
визначенні значень властивостей тут є деякі відмінності.
Так, властивість RepeatBehavior ініціалізується часом - "0:0:10", яке буде повторюватися анімація. Щоб
вказати число повторів, структуру RepeatBehavior треба ініціалізувати так: RepeatBehavior="2x", де 2 -
кількість повторів, а x - просто префікс, що вказує, що мова йде про кількість ітерацій, без нього б число
інтерпретувалося як кількість днів. Третій спосіб завдання цієї властивості - RepeatBehavior="Forever" - в
цьому випадку анімація буде продовжуватися весь час роботи програми.
Наприклад, нижче встановлено RepeatBehavior="Forever", а властивість DecelerationRatio уповільнює
анімацію, що створює ефект підскоку кулі в верх, де він, досягаючи максимальної точки, втрачає
швидкість, а при падінні знову збільшує її:
<Window.Triggers> <Grid.RowDefinitions>
<EventTrigger RoutedEvent="Button.Click"> <RowDefinition />
<EventTrigger.Actions> <BeginStoryboard> <RowDefinition Height="Auto" />
<Storyboard </Grid.RowDefinitions>
Timeline.DesiredFrameRate="60"> <DoubleAnimation <Canvas Background="LightPink"> <Ellipse
Storyboard.TargetName="ball" Name="ball" Fill="Red" Stroke="Black" Width="15"
Storyboard.TargetProperty="(Canvas.Bottom) " Height="15" Canvas.Left="130" Canvas.Bottom="0" />
From="0" To="160" AutoReverse="True" </Canvas>
Duration="0:0:2.5" RepeatBehavior="Forever« <Button Width="70" Height="25"
DecelerationRatio="1"/> Content="Кнопка" Grid.Row="1" Margin="10" />
</Storyboard> </Grid>
</BeginStoryboard> </EventTrigger.Actions>
</EventTrigger>
</Window.Triggers>
<Grid>
Анімація

Анімація властивостей вкладених об'єктів


Тут властивість Fill елемента Ellipse ініціалізується пензлем
RadialGradientBrush, яка має колекцію GradientStops. Анімація ж
застосовується до другого об'єкту колекції та його властивості Color
Анімація. Анімація шляху.
Ще один вид анімацій - це анімація шляху (path-based animation). Вона також
анімує певну властивість. Її особливість у тому, що для анімації властивості
використовується об'єкт PathGeometry.
Анімації шляху представлені трьома класами: DoubleAnimationUsingPath,
MatrixAnimationUsingPath, PointAnimationUsingPath.
Кожен об'єкт анімації за допомогою властивості PathGeometry встановлює
посилання на об'єкт PathGeometry, а властивість Source отримує або задає
аспект об'єкта анімації PathGeometry, що визначає її вихідне значення. Особливо
корисні такі анімації при позиціонуванні об'єкта у вікні додатка:
Анімація. Анімація шляху.
<Window x:Class="AnimationApp.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:AnimationApp"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="300">
Анімація. Анімація шляху.
<Window.Resources>
<PathGeometry x:Key="geometryPath">
<PathFigure IsClosed="True" StartPoint="10, 10">
<PolyLineSegment Points="220,10 220,175 10,175" />
</PathFigure>
</PathGeometry>
</Window.Resources>
<Canvas Background="Black">
<Path Stroke="Red" Data="{StaticResource geometryPath}" Canvas.Top="10"
Canvas.Left="10" />
<Ellipse Width="15" Height="15" Canvas.Top="177" Canvas.Left="120">
Анімація. Анімація шляху.
<Ellipse.Fill> <RadialGradientBrush RadiusX="1" RadiusY="1" GradientOrigin="0.3, 0.3">

<GradientStop Color="White" Offset="0" />

<GradientStop Color="Black" Offset="1" />

</RadialGradientBrush>

</Ellipse.Fill>

<Ellipse.Triggers>

<EventTrigger RoutedEvent="Window.Loaded">

<BeginStoryboard>

<Storyboard>

<DoubleAnimationUsingPath Storyboard.TargetProperty="(Canvas.Top)"

Duration="0:0:5" RepeatBehavior="Forever"

PathGeometry="{StaticResource geometryPath}" Source="Y" >


Анімація. Анімація шляху.
</DoubleAnimationUsingPath>
<DoubleAnimationUsingPath Storyboard.TargetProperty="(Canvas.Left)"
Duration="0:0:5" RepeatBehavior="Forever"
PathGeometry="{StaticResource geometryPath}" Source="X" >
</DoubleAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
</Canvas>
</Window>
Анімація. Анімація шляху.

При запуску ми
побачимо, як невеликий
кулька бігає по
прямокутному контуру:
Анімація. Анімація шляху.
Тут одна із застосовуваних анімацій має наступну форму:
<DoubleAnimationUsingPath Storyboard.TargetProperty="(Canvas.Left)"
Duration="0:0:5" RepeatBehavior="Forever"
PathGeometry="{StaticResource geometryPath}" Source="X" >
В даному випадку анімація застосовується до властивості Canvas.Left об'єкта
Ellipse. Триває 5 секунд і нескінченно повторюється.
PathGeometry встановлює посилання на ресурс, а атрибут Source вказує, що
для нового значення властивості Canvas.Left буде використовуватися параметр
X (координата по осі X) біля точок, які складають PathGeometry.

You might also like