UWP beginner: Заголовок вікна в додатках (VB.NET + C#)

З виходом Windows 10 компанія Microsoft повернула поняття вікна в його первозданному вигляді для додатків Windows Store. Тепер, використовуючи звичні кнопки в правому верхньому куті, можна змінювати розмір, згортати/розгортати і закривати вікно, незалежно від типу програми. Найцікавіше, що Microsoft не відмовилася від свого початкового напрямку – орієнтації на контент. Ця філософія не універсальна, але вона добре підходить для цілого пласта додатків. Погодьтеся, якщо ви робите гру або читалку, то стандартний заголовок з квітами заданими автоматично може злегка зіпсувати дизайн додатка. Тому нові широкі можливості налаштування заголовка в додатках універсальної платформи Windows (UWP) стали безумовним плюсом.

Даний матеріал підготовлений спільно з активним учасником спільноти Microsoft Developer, Олексієм Плотніковим, і менеджером по роботі з технічними аудиторіями, Стасом Павловим. В ньому ми поговоримо про можливі налаштуваннях заголовка всередині UWP-програми.



1. Приховуємо заголовок. Як раз для тих випадків, коли в додатку необхідно повне занурення в контент і підпис не потрібен, існує функція приховування заголовка і переведення програми в повноекранний режим.

Зробити це дуже просто:

VB.NET
'Перехід у повноекранний режим
ApplicationView.GetForCurrentView.TryEnterFullScreenMode()
'Повернення в віконний режим
ApplicationView.GetForCurrentView.ExitFullScreenMode()

C#
//Перехід у повноекранний режим
ApplicationView.GetForCurrentView().TryEnterFullScreenMode();

//Повернення в віконний режим
ApplicationView.GetForCurrentView().ExitFullScreenMode();


Зверніть увагу, що функція TryEnterFullScreenMode повертає значення Boolean, що дозволить переконатися в успіху переходу в повноекранний режим, який не завжди гарантований.

Даний код найкраще використовувати, коли необхідно перевести додаток в повноекранний режим і назад у відповідь на дії користувача. У випадку, якщо потрібно запуск програми в повноекранному режимі, потрібно помістити на початку методу OnLaunched додатки наступний код:

VB.NET
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.FullScreen

C#
ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.FullScreen;


Приємне доповнення такого підходу в тому, що додаток відразу запуститься в повноекранному режимі, включаючи екран заставки, а також запам'ятає це правило для подальших запусків.

На замітку: для уніфікації поведінки UWP-додатків і WinRT, при переході в повноекранний режим можна побачити рядок заголовка якщо підвести курсор миші до верхнього краю вікна. Це буде корисно при проектуванні програми.

2. Тонка настройка. насправді, можливість повністю замінити стандартний заголовок на свій без необхідності піклується про стандартному поведінці начебто перетягування вікна за заголовок з'явилася вперше. По суті це означає, що тепер можна розмістити на місці заголовка все, що прийде в голову. Даний спосіб дозволяє замінити тільки ту частину заголовка, що містить іконку і назву програми. Частина з кнопками керування вікном замінити на власну не вийде.

Якщо зануритися в цей функціонал, слово «заміна» не зовсім підходить. Швидше ми просимо платформу приховати стандартний заголовок і говоримо який елемент в XAML буде виконувати його функції.

Робиться лише двома рядками коду:

VB.NET
'Дозволити використовувати власний заголовок (як наслідок прибрати стандартний)
Core.CoreApplication.GetCurrentView.TitleBar.ExtendViewIntoTitleBar = True
'Встановити зазначений елемент як заголовок вікна.
Window.Current.SetTitleBar(CustomTitleBar)

З#
//Дозволити використовувати власний заголовок (як наслідок прибрати стандартний)
CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
//Встановити зазначений елемент як заголовок вікна.
Window.Current.SetTitleBar(CustomTitleBar);


І ось тут починається найцікавіше. Зазначений елемент може не тільки сильно відрізнятися від звичного заголовка, але і розташовуватися в будь-якому місці вікна. Другий рядок коду не помістить його в потрібне місце і не дасть правильних розмірів, вона всього лише повідомить платформу про те, що на думку розробника є заголовком. Єдине, що вийде у підсумку – це можливість перетягувати вікно натисканням на даний елемент, без необхідності додаткових дій в коді.

Все це вкрай важливо розуміти і пам'ятати, що персоналізація ніколи не повинна іти в розріз із звичками користувача. Пам'ятаючи це потрібно подбати про те, щоб заголовок був розміщений на місці стандартного заголовка і мав відповідну висоту і колір.

Як це виглядає в XAML:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height=".*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Background="LightBlue" x:Name="CustomTitleBur">
<TextBlock VerticalAlignment="Center" Margin="10,0,0,0">Заголовок вікна</TextBlock>
<Image Margin="20,4,0,4" Source="Assets/StoreLogo.png"></Image>
</StackPanel>
</Grid>


В даному прикладі видно, що текст заголовка і іконка помінялися місцями. Все виглядає гранично просто і зрозуміло, але при цьому є цілий ряд важливих аспектів.

По-перше, якщо повідомити платформі про те, що потрібно використовувати власний заголовок, вона віддасть раніше не доступну частину вікна під макет, а значить весь вміст зрушиться вгору. Враховуючи це, потрібно подбати про те, щоб у верхній частині макета був тільки елемент замінює стандартний заголовок, а також переконатися, що ніщо не перекривається кнопками управління вікном. В XAML вище кореневої Grid віддає під заголовок один рядок заввишки 32 одиниці. Тут криється ще один підступ – висота кнопок управління вікном залежить від налаштувань Windows і дорівнює 32 тільки при стандартних налаштуваннях, тому що поважає свого користувача розробник подбає про відстеження зміни налаштувань і відреагує на це. У статті MSDN, присвяченій методом Window.SetTitleBar можна дізнатися докладніше про те, як це зробити.

По-друге, потрібно пам'ятати, що платформа обробляє елемент як звичайний заголовок, а значить помістивши туди кнопку буде неможливо відловлювати події її натискання. Всі події миші будуть перехоплюватися платформою і використовуватися для перетягування вікна.

Вам може здатися, що обійти попереднє обмеження можна просто прибравши рядок коду:

VB.NET
Window.Current.SetTitleBar(CustomTitleBar)

C#
Window.Current.SetTitleBar(CustomTitleBar);


Але, платформа просто приховає стандартний заголовок, а необхідний елемент в якості заголовка не встановить. Тоді можна просто визначити ділянки, за які вікно можна перетягувати і додати потрібні дії в коді? Але, ні, все не так просто. Насправді, якщо не викликати метод SetTitleBar, то все, що знаходиться в макеті вікна потрапить на місце колишнього заголовка, втратить можливість відловлювати enter і буде вести себе як заголовок. Для чого ж тоді потрібна ця рядок коду? Вона потрібна для того, щоб точно визначити місця, які ведуть себе як заголовок. Якщо необхідно помістити туди кнопку, то вона повинна бути за межами елемента CustomTitleBar.

Перепишемо наш XAML наступним чином:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height=".*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Авто"/>
<ColumnDefinition Width=".*"/>
</Grid.ColumnDefinitions>
<Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="FullScreenButton"
Click="FullScreenButton_Click">
<FontIcon FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph=""/>
</Button>
<Grid Background="LightBlue" Grid.Column="1" x:Name="CustomTitleBar">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Margin="10,0,0,0">Заголовок вікна</TextBlock>
<Image Margin="20,4,0,4" Source="Assets/StoreLogo.png"></Image>
</StackPanel>
</Grid>
</Grid>
</Grid>


А в коді вікна буде написано наступне:

VB.NET
Private Sub Page_Loaded(sender As Object, e As RoutedEventArgs)
Core.CoreApplication.GetCurrentView.TitleBar.ExtendViewIntoTitleBar = True
Window.Current.SetTitleBar(CustomTitleBur)
AddHandler Window.Current.SizeChanged, AddressOf CurrentWindow_SizeChanged
End Sub

Private Sub CurrentWindow_SizeChanged(sender As Object, e As WindowSizeChangedEventArgs)
Dim view = ApplicationView.GetForCurrentView
If Not view.IsFullScreenMode Then
view.ExitFullScreenMode()
CustomTitleBur.Visibility = Visibility.Visible
FullScreenButton.Visibility = Visibility.Visible
End If
End Sub

Private Sub FullScreenButton_Click(sender As Object, e As RoutedEventArgs)
Dim view = ApplicationView.GetForCurrentView
If view.TryEnterFullScreenMode() Then
CustomTitleBur.Visibility = Visibility.Collapsed
FullScreenButton.Visibility = Visibility.Collapsed
End If
End Sub

C#
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;

}

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
Window.Current.SetTitleBar(CustomTitleBar);
Window.Current.SizeChanged += Current_SizeChanged;
FullScreenButton.Click += FullScreenButton_Click;

}

private void FullScreenButton_Click(object sender, RoutedEventArgs e)
{
var view = ApplicationView.GetForCurrentView();

if (!view.TryEnterFullScreenMode())
{
CustomTitleBar.Visibility = Visibility.Visible;
FullScreenButton.Visibility = Visibility.Collapsed;
}

}

private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
var view = ApplicationView.GetForCurrentView();

if (!view.IsFullScreenMode)
{
view.ExitFullScreenMode();
CustomTitleBar.Visibility = Visibility.Visible;
FullScreenButton.Visibility = Visibility.Visible;
} 
}


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

Отже, розглянемо приклад більш докладно. Для початку, щоб отримати можливість виклику події натискання на кнопку, потрібно внести її за межі елемента CustomTitleBar. Сам же CustomTitleBar – обернути в зафарбований Grid, так як без заливки він не зможе відловлювати введення миші, і буде неможливо перетягувати вікно за увесь заголовок. Крім описаних раніше рядків, що приховують стандартний заголовок і встановлюють необхідний, події завантаження вікна додається підписка на подію зміни розмірів вікна.

Тепер, в той момент, коли переводимо вікно в повноекранний режим, заголовок нікуди не зникає. CustomTitleBar залишається на своєму місці, але при цьому втрачає функції заголовка. При наведенні курсору миші на верхню частину екрану, зверху з'являються кнопки управління вікном, які дозволяють повернутися в звичайний режим. Якщо для переходячи в повноекранний режим і приховування свого заголовка, досить відреагувати на подію кнопки, то для того, щоб дізнатися, що вікно повернулося в звичайний режим, доведеться підписатися на подію зміни розмірів вікна.

Експериментуючи з даним кодом, можна досягти багатьох цікавих результатів, але не варто забувати про стандартизацію і зручність. Наприклад, ви можете помістити CustomTitleBar внизу вікна і тоді з'явиться можливість перетягувати вікно не за верхню, а за нижню частину, але користувач навряд чи скаже за це «спасибі». Добре обміркуйте необхідності вирішення, перш ніж його застосовувати. До речі дуже гарним прикладом реалізації власного заголовка можна назвати браузер Microsoft Edge, в якому частиною заголовка є вкладки.
3. Зміна кольору заголовка. Описаний вище метод вкрай цікавий і досить гнучкий, але в більшості сценаріїв буде надмірно створювати свій елемент і ускладнювати життя його правильним налаштуванням. Набагато простіше просто перефарбувати елементи системного заголовка кольору програми. Набір параметрів, що відповідають за кольори заголовка, досить широкий, щоб досягти гармонії з іншим додатком.

Для скорочення коду можна отримати посилання на поточний TitleBar і далі працювати з нею:

VB.NET
Dim tb As ApplicationViewTitleBar = ApplicationView.GetForCurrentView.TitleBar

C#
ApplicationViewTitleBar tb = ApplicationView.GetForCurrentView().TitleBar;


Розглянемо всі властивості, що відповідають за колір елементів заголовка:

VB.NET
'Встановлює фону заголовка, але не зачіпає частину з кнопками керування вікном.
tb.BackgroundColor = Windows.UI.Colors.LightBlue
'Встановлює фон під кнопками керування вікном
tb.ButtonBackgroundColor = Windows.UI.Colors.LightBlue
'Встановлює колір символів всередині кнопок керування вікном (риска, хрестик, квадратик).
tb.ButtonForegroundColor = Windows.UI.Colors.Black
'Встановлює колір фону кнопок управління вікном в момент наведення на них вказівника миші. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonHoverBackgroundColor = Windows.UI.Colors.Blue
'Встановлює колір символів всередині кнопок управління вікном в момент наведення на них вказівника миші. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonHoverForegroundColor = Windows.UI.Colors.White
'Встановлює колір фону кнопок управління вікном в момент, коли додаток не активно
tb.ButtonInactiveBackgroundColor = Windows.UI.Colors.Gray
'Встановлює колір символів всередині кнопок управління вікном в момент, коли додаток не активно
tb.ButtonInactiveForegroundColor = Windows.UI.Colors.White
'Встановлює колір фону кнопок управління вікном у момент натискання на них. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonPressedBackgroundColor = Windows.UI.Colors.DarkBlue
'Встановлює колір символів всередині кнопок управління вікном у момент натискання на них. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonPressedForegroundColor = Windows.UI.Colors.White
'Встановлює колір символів заголовка вікна
tb.ForegroundColor = Windows.UI.Colors.Black
'Встановлює фону заголовка в момент, коли додаток не активно
tb.InactiveBackgroundColor = Windows.UI.Colors.Gray
'Встановлює колір символів заголовка вікна в момент, коли додаток не активно
tb.InactiveForegroundColor = Windows.UI.Colors.White

C#
//Встановлює фону заголовка, але не зачіпає частину з кнопками керування вікном.
tb.BackgroundColor = Windows.UI.Colors.LightBlue;
//Встановлює фон під кнопками керування вікном
tb.ButtonBackgroundColor = Windows.UI.Colors.LightBlue;
//Встановлює колір символів всередині кнопок керування вікном (риска, хрестик, квадратик).
tb.ButtonForegroundColor = Windows.UI.Colors.Black;
//Встановлює колір фону кнопок управління вікном в момент наведення на них вказівника миші. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonHoverBackgroundColor = Windows.UI.Colors.Blue;
//Встановлює колір символів всередині кнопок управління вікном в момент наведення на них вказівника миші. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonHoverForegroundColor = Windows.UI.Colors.White;
//Встановлює колір фону кнопок управління вікном в момент, коли додаток не активно
tb.ButtonInactiveBackgroundColor = Windows.UI.Colors.Gray;
//Встановлює колір символів всередині кнопок управління вікном в момент, коли додаток не активно
tb.ButtonInactiveForegroundColor = Windows.UI.Colors.White;
//Встановлює колір фону кнопок управління вікном у момент натискання на них. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonPressedBackgroundColor = Windows.UI.Colors.DarkBlue;
//Встановлює колір символів всередині кнопок управління вікном у момент натискання на них. УВАГА! Не впливає на кнопку закриття вікна.
tb.ButtonPressedForegroundColor = Windows.UI.Colors.White;
//Встановлює колір символів заголовка вікна
tb.ForegroundColor = Windows.UI.Colors.Black;
//Встановлює фону заголовка в момент, коли додаток не активно
tb.InactiveBackgroundColor = Windows.UI.Colors.Gray;
//Встановлює колір символів заголовка вікна в момент, коли додаток не активно
tb.InactiveForegroundColor = Windows.UI.Colors.White;


Поекспериментувавши з кожним з цих властивостей, ви можете домогтися гармонійного дизайну і ваш додаток буде успішно відповідати філософії орієнтації на контент.

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

Варто зауважити, що параметри, що відповідають за колір кнопок керування вікном, також відповідають за кнопку «Назад», яка з'явилася в UWP-додатках і розташована в заголовку вікна (про неї плануємо написати окремий матеріал).

На цьому опис налаштування заголовка в додатках UWP можна завершити. Варто зауважити, що все вище сказане актуальне для додатків, що запускаються на робочому столі. Якщо програма виконується в режимі планшета або на мобільному пристрої, заголовок в ньому відсутня.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.