Professional Documents
Culture Documents
6, 7 лекція. WPF
6, 7 лекція. 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. Так, створюваний за замовчуванням в проекті файл
<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"
<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"
<Grid x:Name="grid1">
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"
<Grid x:Name="grid1">
</Grid> </Window>
Взаємодія XAML та С#
using System.Windows;
namespace XamlApp {
public MainWindow() {
InitializeComponent();
if (text != "") {
MessageBox.Show(text);
} } } }
Взаємодія XAML та С#. Динамічне додавання
<Grid x:Name="layoutGrid"> – MainWindow.xaml
using System.Windows;
namespace XamlApp {
public MainWindow() {
InitializeComponent();
} } }
Складні типи. Конвертери типів
У попередніх темах було розглянуто створення елементів в 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; }
стовпці і рядки, кількість яких визначає розробник. Для визначення рядків використовується властивість
<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>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
Компоновка. Grid
Встановлення розмірів
Але якщо в попередньому випадку у нас рядки і стовпці були рівні один одному, то тепер спробуємо
їх налаштувати стовпчики по ширині, а рядки - по висоті. Є кілька варіантів настройки розмірів.
Автоматичні розміри
Тут стовпець або рядок займає те місце, яке їм потрібно
<ColumnDefinition Width="Auto" />
<RowDefinition Height="Auto" />
Абсолютні розміри
В даному випадку висота і ширина зазначаються в одиницях, незалежних від пристрою:
<ColumnDefinition Width="150" />
<RowDefinition Height="150" />
Компоновка. Grid
значення має властивість Orientation - Horizontal або Vertical. Головна відмінність від StackPanel - якщо елементи
не поміщаються в рядку або стовпці, створюються нові стовпець або рядок для не помістилися елементів.
<WrapPanel>
</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">
</Canvas>
Компоновка. Canvas
Властивості компоновки елементів
Ширина і висота
З допомогою спеціальних властивостей ми можемо вирівняти елемент відносно визначеної сторони контейнера по
Свойство HorizontalAlignment вирівнює елемент по горизонталі щодо правої або лівої сторони контейнера і відповідно
може приймати значення Left, Right, Center (положення по центру), Stretch (розтягнення по всій ширині). Наприклад:
<Grid>
</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-коді у нас визначена наступна кнопка:
Тут у нас заданий атрибут Click з назвою методу обробника button1_Click, який буде визначений у
файлі коду C# і буде викликатися по натисненню кнопки. Тоді у зв'язаному файлі C# код ми можемо
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
public MainWindow() {
InitializeComponent();
Button1.Click += Button1_Click;
} }
Події у WPF
Маршрутизація подій
Модель подій WPF відрізняється від подій WinForms не тільки декларативним підключенням. Події,
виникнувши на одному елементі, можуть оброблятися на іншому. Події можуть підніматися і опускатися по
дереву елементів.
Прямі (direct events) - вони виникають і отрабытывают на одному елементі і нікуди далі не передаються. Діють
як звичайні події.
Піднімаються (киплячому events) - виникають на одному елементі, а потім передаються далі до батьківського
елементу-контейнера і далі, поки не досягне найвищого батька в дереві елементів. Опускаються, тунельні
(tunneling events) - починає відпрацьовувати в кореневому елементі вікна програми і йде далі по вкладених
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Button>
</StackPanel>
</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. Прикріплюючі події.
Для анімації властивості необхідний клас анімації, який би підтримував тип цього властивості.
Наприклад, для зміни таких властивостей, як довжина, ширина, які представляють тип 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, який і запускає анімацію.
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>
Анімація
</RadialGradientBrush>
</Ellipse.Fill>
<Ellipse.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimationUsingPath Storyboard.TargetProperty="(Canvas.Top)"
Duration="0:0:5" RepeatBehavior="Forever"
При запуску ми
побачимо, як невеликий
кулька бігає по
прямокутному контуру:
Анімація. Анімація шляху.
Тут одна із застосовуваних анімацій має наступну форму:
<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.