windows 10 uwp app development ebook

62
1 Windows 10 Universal Windows Platform (UWP) I. CONTROLES.............................................................................................................................................. 3 1. RELATIVEPANEL .............................................................................................................................................. 3 2. SPLITVIEW..................................................................................................................................................... 5 a. SplitView de base et Adaptive Triggers ................................................................................................. 5 b. Bouton Rechercher et AutoSuggestBox dans SplitView ......................................................................... 8 c. « Page Header » : Contrôle utilisateur « Barre de titre » avec marge adaptable selon le mode d’affichage du SplitView ............................................................................................................................... 10 3. NAVIGATION MODEL...................................................................................................................................... 13 4. BACKBUTTON............................................................................................................................................... 16 5. COMMANDBAR, SYMBOLICON, .................................................................................................................... 17 6. MEDIA ELEMENT ET CUSTOM MEDIA TRANSPORT CONTROLS ................................................................................. 20 7. CONTENT DIALOG ......................................................................................................................................... 21 8. AUTOSUGGESTBOX REMPLAÇANT DE SEARCHBOX »)....................................................................................... 22 9. POPUP ........................................................................................................................................................ 23 10. EXTENDED SPASHSCREEN ........................................................................................................................... 23 11. VARIABLESIZEDWRAPGRID......................................................................................................................... 25 II. ACCENT ET THEME (DARK, LIGHT) .......................................................................................................... 27 DÉFINIR SON PROPRE THÈME .................................................................................................................................... 27 III. DESIGN TIME.......................................................................................................................................... 28 IV. DATATEMPLATESELECTOR ................................................................................................................. 29 DERNIER ELEMENT « AFFICHER PLUS » POUR LISTVIEW OU GRIDVIEW .................................................................... 31 V. HEADERGROUP ...................................................................................................................................... 34 DATATEMPLATES ........................................................................................................................................... 36 POUR LISTVIEW..................................................................................................................................................... 36 POUR GRIDVIEW ................................................................................................................................................... 38 VI. ADAPTIVE UI ...................................................................................................................................... 40 1. ADAPTIVE TRIGGERS ...................................................................................................................................... 41 2. MASTER DETAILS................................................................................................................................................ 43 3. CUSTOM ADAPTIVE TRIGGERS .......................................................................................................................... 45 4. DEVICEFAMILY ............................................................................................................................................. 48 5. ASTUCE : REACTIVER LES ANIMATIONS, TRANSITIONS WINDOWS ............................................................................ 48 VII. X :BIND « COMPILED BINDING » ........................................................................................................ 49 1. BINDING DE COLLECTION ................................................................................................................................ 49 2. AVEC DATATEMPLATE.................................................................................................................................... 50 3. AVEC DICTIONNAIRE DE RESSOURCES (RESOURCEDICTIONARY) ............................................................................... 50 4. « RELATIVESOURCE » ET « ELEMENTNAME » LIER AU NOM DE LELEMENT ........................................................... 51 5. « SOURCE » ET « DATACONTEXT ».. AJOUTER UNE PROPRIETE DU VIEWMODEL DANS LE CODE-BEHIND ....................... 51 6. BINDING EVENTS .......................................................................................................................................... 52 7. DEFER LOADING............................................................................................................................................ 53

Upload: cheah-eng-soon

Post on 21-Jan-2017

2.689 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Windows 10 UWP App Development ebook

1

Windows 10 Universal Windows Platform (UWP)

I. CONTROLES.............................................................................................................................................. 3

1. RELATIVEPANEL .............................................................................................................................................. 3 2. SPLITVIEW ..................................................................................................................................................... 5

a. SplitView de base et Adaptive Triggers ................................................................................................. 5 b. Bouton Rechercher et AutoSuggestBox dans SplitView ......................................................................... 8 c. « Page Header » : Contrôle utilisateur « Barre de titre » avec marge adaptable selon le mode

d’affichage du SplitView ............................................................................................................................... 10 3. NAVIGATION MODEL ...................................................................................................................................... 13 4. BACKBUTTON ............................................................................................................................................... 16 5. COMMANDBAR, SYMBOLICON, … .................................................................................................................... 17 6. MEDIA ELEMENT ET CUSTOM MEDIA TRANSPORT CONTROLS ................................................................................. 20 7. CONTENT DIALOG ......................................................................................................................................... 21 8. AUTOSUGGESTBOX (« REMPLAÇANT DE SEARCHBOX ») ....................................................................................... 22 9. POPUP ........................................................................................................................................................ 23 10. EXTENDED SPASHSCREEN ........................................................................................................................... 23 11. VARIABLESIZEDWRAPGRID ......................................................................................................................... 25

II. ACCENT ET THEME (DARK, LIGHT) .......................................................................................................... 27

DÉFINIR SON PROPRE THÈME .................................................................................................................................... 27

III. DESIGN TIME.......................................................................................................................................... 28

IV. DATATEMPLATESELECTOR ................................................................................................................. 29

DERNIER ELEMENT « AFFICHER PLUS » POUR LISTVIEW OU GRIDVIEW .................................................................... 31

V. HEADERGROUP ...................................................................................................................................... 34

DATATEMPLATES ........................................................................................................................................... 36

POUR LISTVIEW..................................................................................................................................................... 36 POUR GRIDVIEW ................................................................................................................................................... 38

VI. ADAPTIVE UI ...................................................................................................................................... 40

1. ADAPTIVE TRIGGERS ...................................................................................................................................... 41 2. MASTER DETAILS ................................................................................................................................................ 43 3. CUSTOM ADAPTIVE TRIGGERS .......................................................................................................................... 45 4. DEVICEFAMILY ............................................................................................................................................. 48 5. ASTUCE : REACTIVER LES ANIMATIONS, TRANSITIONS WINDOWS ............................................................................ 48

VII. X :BIND « COMPILED BINDING » ........................................................................................................ 49

1. BINDING DE COLLECTION ................................................................................................................................ 49 2. AVEC DATATEMPLATE.................................................................................................................................... 50 3. AVEC DICTIONNAIRE DE RESSOURCES (RESOURCEDICTIONARY) ............................................................................... 50 4. « RELATIVESOURCE » ET « ELEMENTNAME » … LIER AU NOM DE L’ELEMENT ........................................................... 51 5. « SOURCE » ET « DATACONTEXT ».. AJOUTER UNE PROPRIETE DU VIEWMODEL DANS LE CODE-BEHIND ....................... 51 6. BINDING EVENTS .......................................................................................................................................... 52 7. DEFER LOADING ............................................................................................................................................ 53

Page 2: Windows 10 UWP App Development ebook

2

VIII. APPLICATION LIFECYCLE..................................................................................................................... 53

1. HISTORIQUE DE NAVIGATION (« APP ») ............................................................................................................ 54 2. ETATS DE LA PAGE ET DONNEES ........................................................................................................................ 54

IX. TILES, TOASTS ........................................................................................................................................ 56

TILE .................................................................................................................................................................... 56 Adaptive Tiles ............................................................................................................................................... 59

TOAST ................................................................................................................................................................. 60 Adaptive toast .............................................................................................................................................. 60

Documentation, exemples (page de tous les exemples de codes)

Modèles d’application (Visual Studio 2015)

Avec Windows 10, le modèle d’application universelle permet de créer à partir d’un seul projet une

application pour le Windows Store (PC, tablettes et ordinateurs portables) et une application pour le

Windows Phone Store.

Modèle « Universel » Windows 10 (UWP)

Modèles d’applications Windows, Windows Phone et

« Universel » (avec projet « Shared ») Windows 8

Modèle « Universel Windows 8 » :

3 projets (un projet Windows Store,

un Windows Phone et un « Shared »)

Modèle « Universel Windows 10 »

(UWP) : 1 seul projet

Page 3: Windows 10 UWP App Development ebook

3

I. Contrôles Liste des contrôles et exemples

Voir l’exemple « XamlUIBasics »

1. RelativePanel Permet de positionner les éléments les uns par rapport aux autres et de gérer le repositionnement

des éléments avec des AdaptiveTriggers.

Propriétés de placement

Placement par rapport à un élément

Above : Au-dessus de l’élément

Below : En-dessous de l’élément

LeftOf : A gauche de l’élément

RightOf : A droite de l’élément

Plus

AlignHorizontalCenterWith

AlignVerticalCenterWith

AlignBottomWith

AlignTopWith

AlignLeftWith

AlignRightWith

Exemple

<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Rectangle x:Name="rectangle1" Fill="Red" Width="300" Height="150" /> <Rectangle x:Name="rectangle2" Fill="Blue" RelativePanel.RightOf="rectangle1" Width="300" Height="150" /> <Rectangle x:Name="rectangle3" Fill="Green" RelativePanel.Below="rectangle2" RelativePanel.AlignHorizontalCenterWith="rectangle2" Width="300" Height="150" /> </RelativePanel>

Rectangle bleu placé à droite du

rectangle rouge

Rectangle vert placé en-dessous du

rectangle bleu (Below) et aligné avec

celui-ci (AlignHorizontalCenterWith)

Page 4: Windows 10 UWP App Development ebook

4

Placement par rapport au RelativePanel

AlignTopWithPanel : En haut (à gauche si pas précisé) du RelativePanel

AlignBottomWithPanel : En bas (et à gauche si pas précisé) du RelativePanel

AlignLeftWithPanel : A gauche (et en haut si pas précisé) du RelativePanel

AlignRightWithPanel : A droite (et en haut si pas précisé) du RelativePanel

Plus pour centrer horizontalement et verticalement un élément par rapport au RelativePanel

AlignHorizontalCenterWithPanel

AlignVerticalCenterWithPanel

<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Rectangle x:Name="rectangle1" Fill="Red" Width="300" Height="150" /> <Rectangle x:Name="rectangle2" RelativePanel.AlignRightWithPanel="True" Fill="Blue" Width="300" Height="150" /> <Rectangle x:Name="rectangle3" Fill="Green" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True" Width="300" Height="150" /> </RelativePanel>

Rectangle bleu placé à droite du

RelativePanel (AlignRightWithPanel)

Par défaut les éléments sont placés

à gauche en haut du RelativePanel

Rectangle vert placé à droite

(AlignRightWithPanel) et en bas

(AlignBottomWithPanel)du RelativePanel

Page 5: Windows 10 UWP App Development ebook

5

2. SplitView

a. SplitView de base et Adaptive Triggers

Exemple

DisplayMode

- Overlay : par-dessus le contenu quand ouvert et caché fermé

- CompactOverlay : par-dessus le contenu quand ouvert et avec une barre quand fermé

- Inline : ancré ouvert, caché fermé

- CompactInline : ancré ouvert et avec une barre quand fermé

<SplitView> <SplitView.Pane> <!-- menu --> </SplitView.Pane> <SplitView.Content> <!-- content--> </SplitView.Content> </SplitView>

De 720 à 1024,

« CompactInline » et

panel fermé

Les « Adaptive Triggers »

permettent de basculer le mode

d’affichage du splitview selon la

taille de la page.

Plus de1024 « CompactInline »,

panel ouvert

En-dessous 720, Mode

d’affichage « Overlay »

Le bouton hamburger permet en

plus d’ouvrir, fermer le panel. Il est

placé en dehors du splitview pour ne

pas être caché quand le panel est

fermé en mode « Overlay »

Page 6: Windows 10 UWP App Development ebook

6

SplitView

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="VisualStateMin0"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="0" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="splitView.DisplayMode" Value="Overlay"/> <Setter Target="splitView.IsPaneOpen" Value="False"/> </VisualState.Setters> </VisualState> <VisualState x:Name="VisualStateMin720"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="720" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="splitView.DisplayMode" Value="CompactInline"/> <Setter Target="splitView.IsPaneOpen" Value="False"/> </VisualState.Setters> </VisualState> <VisualState x:Name="VisualStateMin1024"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="1024" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="splitView.DisplayMode" Value="CompactInline"/> <Setter Target="splitView.IsPaneOpen" Value="True"/> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <SplitView x:Name="splitView" DisplayMode="CompactInline" IsPaneOpen="True" OpenPaneLength="320"> <SplitView.Pane> <ListView Margin="0,48,0,0" VerticalAlignment="Stretch" ItemsSource="{x:Bind ViewModel.MenuItems}" ItemTemplate="{StaticResource MenuItemTemplate}" SelectionMode="None" IsItemClickEnabled="True"/> </SplitView.Pane> <SplitView.Content> <Frame x:Name="mainFrame"></Frame> </SplitView.Content> </SplitView> <Button Name="splitViewButton" Style="{StaticResource Square48x48ButtonStyle}" VerticalAlignment="Top" Click="splitViewButton_Click"> <FontIcon FontFamily="{ThemeResource ContentControlThemeFontFamily}" Glyph="&#x2261;" FontSize="32" Margin="0,-8,0,0"/> </Button> </Grid>

On peut définir ce que l’on veut en contenu .De

plus on peut omettre « SplitView.Content »

Bouton hamburger

placé en dernier

Marge de 48 par rapport au top

pour laisser la place au bouton

hamburger

Adaptive Triggers, on

change le mode

d’affichage du splitview

selon la taille de la page

Page 7: Windows 10 UWP App Development ebook

7

Template

<DataTemplate x:Key="MenuItemTemplate" x:DataType="local:MenuItem"> <StackPanel Orientation="Horizontal" Margin="2,0,0,0"> <SymbolIcon Symbol="{x:Bind Symbol}"/> <TextBlock Text="{x:Bind Title}" Margin="24,0,0,0" VerticalAlignment="Center"/> </StackPanel> </DataTemplate>

Code-behind

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); ViewModel = new MainPageViewModel(); } public MainPageViewModel ViewModel { get; set; } private void splitViewButton_Click(object sender, RoutedEventArgs e) { splitView.IsPaneOpen = !splitView.IsPaneOpen; } }

Classe utilisée pour le menu

public class MenuItem { public Symbol Symbol { get; set; } public string Title { get; set; } public MenuItem(string title, Symbol symbol) { Title = title; Symbol = symbol; } }

On remplit la collection

public class MainPageViewModel { public ObservableCollection<MenuItem> MenuItems { get; set; } public MainPageViewModel() { MenuItems = new ObservableCollection<MenuItem>(); MenuItems.Add(new MenuItem("Accueil", Symbol.Home)); MenuItems.Add(new MenuItem("Vidéos", Symbol.Video)); MenuItems.Add(new MenuItem("Musiques", Symbol.Audio)); } }

Page 8: Windows 10 UWP App Development ebook

8

b. Bouton Rechercher et AutoSuggestBox dans SplitView

<SplitView x:Name="splitView" DisplayMode="CompactInline" IsPaneOpen="True" OpenPaneLength="320"> <SplitView.Pane> <StackPanel Margin="0,48,0,0"> <Grid Height="48"> <AutoSuggestBox x:Name="autoSuggestBox" Margin="12,0" PlaceholderText="Rechercher" VerticalAlignment="Center" QueryIcon="Find" Visibility="{Binding IsPaneOpen, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=splitView}" /> <Button x:Name="searchButton" Style="{StaticResource Square48x48ButtonStyle}" Visibility="{Binding IsPaneOpen, Converter={StaticResource BooleanToCollapsedConverter}, ElementName=splitView}" Click="searchButton_Click"> <SymbolIcon Symbol="Find" /> </Button> </Grid> <ListView ItemsSource="{x:Bind ViewModel.MenuItems}" ItemTemplate="{StaticResource MenuItemTemplate}" SelectionMode="None" IsItemClickEnabled="True"/> </StackPanel> </SplitView.Pane> <SplitView.Content> <Frame x:Name="mainFrame"></Frame> </SplitView.Content> </SplitView>

Il suffit en plus de permettre au clic sur le bouton rechercher d’ouvrir le panel

private void searchButton_Click(object sender, RoutedEventArgs e) { splitView.IsPaneOpen = true; }

Style du bouton

On lie la visibilité de

l’AutoSuggestBox et du bouton

rechercher à SplitView

IsPaneOpen et on utilise des

converters

AutoSuggestBox quand le

panel est ouvert

Bouton quand le panel est

fermé

On fait en sorte que chaque

élément fasse 48px de haut

Page 9: Windows 10 UWP App Development ebook

9

<Style x:Key="Square48x48ButtonStyle" TargetType="Button"> <Setter Property="Background" Value="Transparent" /> <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" /> <Setter Property="FontFamily" Value="{ThemeResource SymbolThemeFontFamily}" /> <Setter Property="Height" Value="48" /> <Setter Property="Width" Value="48" /> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalAlignment" Value="Center"/> <Setter Property="UseSystemFocusVisuals" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListMediumBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltBaseHighBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Content" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ContentPresenter x:Name="Content" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>

Bouton 48x48 avec

contenu centré

Page 10: Windows 10 UWP App Development ebook

10

c. « Page Header » : Contrôle utilisateur « Barre de titre » avec marge adaptable selon le

mode d’affichage du SplitView Création d’un UserControl « PageHeader » qui pourra être glissé sur chaque page de contenu

(affichée dans la zone de contenu du SplitView) . On pourra personnaliser le contenu de cette barre

de titre pour chaque page, mais surtout permettra de gérer la marge entre le titre et le bouton

hamburger du splitview. En effet, en mode d’affichage Overlay, le titre (s’il est aligné à gauche) et le

bouton hamburger risqueraient de se chevaucher, il faut donc gérer la marge.

<UserControl x:Class="UWPNavigationDemo.Controls.PageHeader" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPNavigationDemo.Controls" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Height="48" d:DesignHeight="300" d:DesignWidth="400"> <Grid> <Grid x:Name="titleBar"> <ContentPresenter x:Name="content" VerticalAlignment="{x:Bind VerticalContentAlignment}" HorizontalAlignment="{x:Bind HorizontalContentAlignment}" Margin="{x:Bind Padding}" Content="{x:Bind HeaderContent}"/> </Grid> </Grid> </UserControl>

Code-behind du contrôle

public sealed partial class PageHeader : UserControl { public PageHeader() { this.InitializeComponent(); EasyMessenger.Default.Subscribe<bool>("SplitView-DisplayMode-Overlay", (isOverlay)=> { if (isOverlay) { this.titleBar.Margin = new Thickness(overlayMargin, 0, 0, 0); } else { this.titleBar.Margin = new Thickness(defaultMargin, 0, 0, 0); } }); } private const int defaultMargin = 12; private const int overlayMargin = 48; public UIElement HeaderContent { get { return (UIElement)GetValue(HeaderContentProperty); } set { SetValue(HeaderContentProperty, value); } } public static readonly DependencyProperty HeaderContentProperty = DependencyProperty.Register("HeaderContent", typeof(UIElement), typeof(PageHeader), new PropertyMetadata(DependencyProperty.UnsetValue)); }

Hauteur de 48 pour être aligné avec

le bouton hamburger

J’utilise un Messenger pour m’abonner au changement

de « DisplayMode » du SplitView. SI le DisplayMode est

« Overlay » . Je mets une grosse marge (48px) pour que

le bouton hamburger et le titre ne se chevauchent pas

Dependency Property

permettant de personnaliser le

contenu du contrôle selon

chaque page

Page 11: Windows 10 UWP App Development ebook

11

Voir l’exemple XamlNavigation, qui n’utilise pas tout à fait la même méthode, mais il m’a

semblé observer quelques soucis

Dans le code-behind de MainPage

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); ViewModel = new MainPageViewModel(); SizeChanged += (s, e) => { CheckDisplayMode(); }; mainFrame.Navigated += (s, e) => { CheckDisplayMode(); }; // navigation mainFrame.Navigate(typeof(PageOne)); } private void CheckDisplayMode() { var displayMode = splitView.DisplayMode; if (displayMode == SplitViewDisplayMode.Overlay) { // messenger EasyMessenger.Default.Publish("SplitView-DisplayMode-Overlay", true); } else { EasyMessenger.Default.Publish("SplitView-DisplayMode-Overlay", false); } } // etc.

}

PageOne

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Controls:PageHeader HorizontalAlignment="Left"> <Controls:PageHeader.HeaderContent> <TextBlock Text="Titre de la page" Style="{StaticResource TitleTextBlockStyle}" /> </Controls:PageHeader.HeaderContent> </Controls:PageHeader> <Grid Background="#ccc" Grid.Row="1"> </Grid> </Grid>

Abonnement au changement de taille de la page

et en fin de navigation de la frame

« mainFrame ».

On vérifie le mode d’affichage du SPlitView et

notifie par Messenger

Utilisation du contrôle, ajout

d’un simple TextBlock avec un

titre aligné à gauche

Page 12: Windows 10 UWP App Development ebook

12

Marge de 12 en « CompactInline »

(panel ouvert et fermé)

Marge de 48 en mode « Overlay » pour éviter que

le titre et le bouton hamburger se chevauchent

Page 13: Windows 10 UWP App Development ebook

13

3. Navigation model Documentation

Voir l’exemple XamlNavigation

La navigation doit se faire dans deux sens. La barre de navigation doit être « synchronisée »

(navigation retour) avec les pages affichées.

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); var MenuItems = new ObservableCollection<MenuItem>(); MenuItems.Add(new MenuItem("HomePage", "Accueil", Symbol.Home)); MenuItems.Add(new MenuItem("VideosPage", "Vidéos", Symbol.Video)) ; MenuItems.Add(new MenuItem("MusicsPage", "Musiques", Symbol.Audio)); menusListView.ItemsSource = MenuItems; mainFrame.Navigated += (s, e) => { // affiche le bouton if (mainFrame.CanGoBack) { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; } else { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed; } // sélectionne le menu correspondant à la page if (e.NavigationMode == NavigationMode.Back) { string pageName = e.SourcePageType.Name; foreach (var item in menusListView.Items) { var menu = item as MenuItem; if (menu.Id == pageName) { menusListView.SelectedItem = item; return; } } } }; // Gère la navigation retour SystemNavigationManager.GetForCurrentView().BackRequested += (s, a) => { if (mainFrame.CanGoBack) { mainFrame.GoBack(); a.Handled = true; } }; }

Navigation « Retour »

Page 14: Windows 10 UWP App Development ebook

14

private void ListView_ItemClick(object sender, ItemClickEventArgs e) { var menu = e.ClickedItem as MenuItem; if (menu.Id == "HomePage") { mainFrame.Navigate(typeof(HomePage)); } if (menu.Id == "VideosPage") { mainFrame.Navigate(typeof(VideosPage)); } if (menu.Id == "MusicsPage") { mainFrame.Navigate(typeof(MusicsPage)); } } protected override void OnNavigatedTo(NavigationEventArgs e) { // navigation mainFrame.Navigate(typeof(HomePage)); menusListView.SelectedIndex = 0; } }

public class MenuItem { public string Id { get; set; } public Symbol Symbol { get; set; } public string Title { get; set; } public MenuItem(string id,string title, Symbol symbol) { Id = id; Title = title; Symbol = symbol; } }

La ListView modifiée en sélection « Single »

<ListView x:Name="menusListView" ItemTemplate="{StaticResource MenuItemTemplate}" SelectionMode="Single" IsItemClickEnabled="True" ItemClick="ListView_ItemClick"/>

Navigation « Aller »

Ajout d’un paramètre « Id »

permettant de retrouver la page

correspondante au menu

Page 15: Windows 10 UWP App Development ebook

15

Navigation « Aller »

Navigation « Retour », après avoir cliqué sur le bouton retour de la barre de titre, le menu est

sélectionné et synchronisé par rapport à la page affichée.

Il faut garder en tête ici que c’est un scénario simple. On pourrait par exemple imaginer créer un

paramètre spécifique à la navigation avec des propriétés permettant de mieux gérer celle-ci

(exemple la page doit elle être prise en compte dans la navigation par la barre de menus?)

On peut également observer Template10, qui crée un contrôle « HamburgerMenu ».

Page 16: Windows 10 UWP App Development ebook

16

4. BackButton

Voir l’exemple BackButton

Affichage d’un bouton dans la barre de titre (Desktop)

Dans « App » pour « rootFrame » (ou dans le code de la page pour une Frame particulière)

protected override void OnLaunched(LaunchActivatedEventArgs e) { // etc. Window.Current.Activate(); // Affiche ou masque le bouton retour de la barre de titre rootFrame.Navigated += (s, a) => { if (rootFrame.CanGoBack) { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible; } else { SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed; } }; // Gère la navigation retour SystemNavigationManager.GetForCurrentView().BackRequested += (s, a) => { if (rootFrame.CanGoBack) { rootFrame.GoBack(); a.Handled = true; } }; }

Page d’accueil

Navigation vers une autre page, le bouton retour apparait

dans la barre de titre. La couleur correspond à l’accent

sélectionné des paramètres de personnalisation de

Windows 10

Page 17: Windows 10 UWP App Development ebook

17

5. CommandBar, SymbolIcon, …

Voir l’exemple XamlCommanding et XamlUIBasics

CommandBar

<CommandBar> <CommandBar.Content> <TextBlock Text="Titre" /> </CommandBar.Content> <AppBarButton Icon="Like" Label="Like" /> <!--etc.--> <!-- Separator --> <AppBarSeparator/> <!-- MenuFlyout --> <AppBarButton Icon="OpenWith" Label="Show Flyout"> <AppBarButton.Flyout> <MenuFlyout> <MenuFlyoutItem Text="Option 1"/> <MenuFlyoutItem Text="Option 2"/> </MenuFlyout> </AppBarButton.Flyout> </AppBarButton> <!-- AppBarToggleButton --> <AppBarToggleButton Icon="Contact" Label="Contact" IsChecked="True"/> <!-- Secondary --> <CommandBar.SecondaryCommands> <AppBarButton Icon="Setting" Label="Settings"/> </CommandBar.SecondaryCommands> </CommandBar>

Menu Flyout (apparait au-dessus ou en dessous la barre selon l’espace disponible)

On peut définir « IsOpen » pour

afficher ou non les labels

Les commandes secondaires et labels apparaissent

quand on clique sur le bouton « … »

« Content » à gauche

de la barre

Commandes « primaires »

placées à droite de la barre

Commandes « secondaires »

placées dans menu ouvert

avec le bouton « … »

Page 18: Windows 10 UWP App Development ebook

18

« IconElement » (SymbolIcon, FontIcon, ou PathIcon)

<AppBarButton Icon="Like" Label="Like" />

SymbolIcon Liste des symboles disponibles

<AppBarButton Label="Dislike"> <AppBarButton.Icon> <SymbolIcon Symbol="Dislike" Foreground="Red"/> </AppBarButton.Icon> </AppBarButton>

FontIcon permet de définir un symbole qui n’est pas inclus dans SymbolIcon (on peut s’aider avec la

« table des caractères »

<AppBarButton Label="FontIcon"> <AppBarButton.Icon> <FontIcon FontFamily="Candara" Glyph="&#x03A3;"/> </AppBarButton.Icon> </AppBarButton>

PathIcon

<AppBarButton Label="PathIcon"> <AppBarButton.Icon> <PathIcon Data="F1 M 16,12 20,2L 20,16 1,16" HorizontalAlignment="Center"/> </AppBarButton.Icon> </AppBarButton>

BitmapIcon

<AppBarButton Label="BitmapIcon"> <AppBarButton.Icon> <BitmapIcon UriSource="ms-appx:///Assets/YouTube.png" /> </AppBarButton.Icon> </AppBarButton>

Custom

<AppBarButton Label="Custom" HorizontalContentAlignment="Center"> <Grid Width="48" Height="48" Margin="0,-8,0,-4"> <SymbolIcon Symbol="Memo"/> <TextBlock Text="2" Margin="0,2,0,0" Style="{StaticResource CaptionTextBlockStyle}" HorizontalAlignment="Center"/> </Grid> </AppBarButton>

Page 19: Windows 10 UWP App Development ebook

19

Top et bottom AppBar

(Peuvent être ajoutées rapidement depuis le panneau « Structure du document »)

<Page.TopAppBar> <CommandBar x:Name="topBar" ClosedDisplayMode="Compact"> <CommandBar.Content> <StackPanel Orientation="Horizontal"> <AppBarButton Icon="Home" /> <!--etc.--> </StackPanel> </CommandBar.Content> <AppBarButton Icon="Accept" Label="Valider"/> <!--etc.--> </CommandBar> </Page.TopAppBar> <Page.BottomAppBar> <CommandBar> <AppBarButton Icon="Accept" Label="Valider"/> <!--etc.--> </CommandBar> </Page.BottomAppBar>

On peut changer le mode d’affichage :

- Compact (par défaut)

- Minimal (n’affiche plus que le bouton « … » permettant d’afficher les éléments de la barre)

- Hidden la barre est complètement cachée.

TopAppBar

BottomAppBar

Page 20: Windows 10 UWP App Development ebook

20

6. Media Element et Custom media transport controls Documentation

Source

<MediaElement x:Name="mediaElement" Source="/Assets/dhany.mp4" AreTransportControlsEnabled="True" />

SetSource

<MediaElement x:Name="mediaElement" AreTransportControlsEnabled="True" />

Ouverture d’une boite de dialogue

private async void button_Click(object sender, RoutedEventArgs e) { var picker = new FileOpenPicker(); picker.FileTypeFilter.Add(".wmv"); picker.FileTypeFilter.Add(".mp4"); picker.FileTypeFilter.Add(".mp3"); picker.FileTypeFilter.Add(".wma"); picker.SuggestedStartLocation = PickerLocationId.VideosLibrary; var file = await picker.PickSingleFileAsync(); if (file != null) { IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read); mediaElement.SetSource(stream, file.ContentType); } }

Il est possible de customiser les contrôles, en ajouter (un bouton like en plus par exemple)

Voir l’exemple XamlCustomMediaTransportControls

Page 21: Windows 10 UWP App Development ebook

21

7. Content Dialog Menu « Ajouter » … « Nouvel élément » … « Boite de dialogue de contenu »

Desktop Mobile

Exemple de « ContentDialog »

<ContentDialog x:Class="UWPContentDialogDemo.MyContentDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPContentDialogDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Title="Ecrire une note" PrimaryButtonText="Envoyer" SecondaryButtonText="Annuler" PrimaryButtonClick="ContentDialog_PrimaryButtonClick" SecondaryButtonClick="ContentDialog_SecondaryButtonClick"> <StackPanel> <TextBox Header="Titre"></TextBox> <TextBox TextWrapping="Wrap" AcceptsReturn="True" Header="Contenu" Height="100"></TextBox> </StackPanel> </ContentDialog>

Afficher la boite de dialogue et gérer le résultat

private async void Button_Click(object sender, RoutedEventArgs e) { var dialog = new MyContentDialog(); var dialogResult = await dialog.ShowAsync(); if(dialogResult == ContentDialogResult.Primary) { } else if (dialogResult == ContentDialogResult.Secondary) { } }

La boite de dialogue s’adapte

selon la taille de la page.

Par défaut la boite occupe toute la

page mais on peut la

redimensionner depuis le designer

Contenu

Titre et boutons de la

boite de dialogue

Page 22: Windows 10 UWP App Development ebook

22

8. AutoSuggestBox (« remplaçant de SearchBox »)

Voir les exemples XamlUIBasics et XamlAutoSuggestBox

<AutoSuggestBox x:Name="autoSuggestBox" Margin="0,8,12,0" Width="270" PlaceholderText="Entrer le nom d'une ville Française" QueryIcon="Find" TextChanged="autoSuggestBox_TextChanged" SuggestionChosen="autoSuggestBox_SuggestionChosen" QuerySubmitted="autoSuggestBox_QuerySubmitted" RelativePanel.AlignRightWithPanel="True" />

private void autoSuggestBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) { if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) { var suggestions = GetSuggestions(sender.Text); sender.ItemsSource = suggestions; } } private void autoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args) { var selectedItem = args.SelectedItem.ToString(); suggestionChosenTextBlock.Text = "Suggestion choisie : " + selectedItem; } private void autoSuggestBox_QuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args) { if (args.ChosenSuggestion != null) { } else if (!string.IsNullOrEmpty(args.QueryText)){ } } private List<string> GetSuggestions(string query) { var suggestions = cities.FindAll(c => c.ToLower().StartsWith(query.ToLower())); return suggestions; }

On change la liste des

suggestions selon le texte

saisi

Déclenché lorsque l’utilisateur sélectionne une suggestion de la liste proposée

Page 23: Windows 10 UWP App Development ebook

23

private List<string> cities = new List<string> { "Lyon", "Marseille", "Nantes", "Nice", "Strasbourg", "Toulouse", "Paris" };

9. Popup Exemple popup « chargement » affichée pendant le chargement des données

<Popup IsOpen="{Binding IsBusy}" VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid Background="{ThemeResource ContentDialogBorderThemeBrush}" Height="100" Width="200"> <Grid.RenderTransform> <TranslateTransform X="-100" Y="-50" /> </Grid.RenderTransform> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> <ProgressRing VerticalAlignment="Center" IsActive="True" Foreground="{ThemeResource ContentDialogDimmingThemeBrush}" /> <TextBlock x:Uid="loadingTextBlock" Foreground="{ThemeResource ContentDialogDimmingThemeBrush}" Text="Loading" FontSize="22" FontWeight="Light" Margin="12,0,0,0" /> </StackPanel> </Grid> </Popup>

10. Extended SpashScreen Ajout dans la méthode « OnLaunched » de « App »

if (e.PreviousExecutionState != ApplicationExecutionState.Running) { bool loadState = (e.PreviousExecutionState == ApplicationExecutionState.Terminated); var splash = new ExtendedSplash(e.SplashScreen, loadState); rootFrame.Content = splash; Window.Current.Content = rootFrame; }

Création d’une page avec image et progress ring.

<Grid Background="#D03133" > <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="180"/> </Grid.RowDefinitions> <Canvas Grid.RowSpan="2"> <Image x:Name="extendedSplashImage" Source="Assets/SplashScreen.png"/> </Canvas> <ProgressRing IsActive="True" Grid.Row="1" Width="80" Height="80" Foreground="White" HorizontalAlignment="Center" /> </Grid>

Place correctement au centre de la page

Page 24: Windows 10 UWP App Development ebook

24

La taille de l’image et les éléments sont repositionnés selon la taille de la page

public sealed partial class ExtendedSplash { internal Rect splashImageRect; private SplashScreen splash; private double ScaleFactor; public ExtendedSplash(SplashScreen splashscreen, bool loadState) { InitializeComponent(); Window.Current.SizeChanged += new WindowSizeChangedEventHandler(OnResize); ScaleFactor = (double)DisplayInformation.GetForCurrentView().ResolutionScale / 100; splash = splashscreen; if (splash != null) { splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(OnDismissed); splashImageRect = splash.ImageLocation; PositionImage(); } } private void PositionImage() { extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.Left); extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Top); extendedSplashImage.Height = splashImageRect.Height / ScaleFactor; extendedSplashImage.Width = splashImageRect.Width / ScaleFactor; } private void OnResize(Object sender, WindowSizeChangedEventArgs e) { if (splash != null) { splashImageRect = splash.ImageLocation; PositionImage(); } } private async void OnDismissed(SplashScreen sender, object e) { // on peut effectuer un chargement, essayer de connecter l’utilisateur, etc. par exemple puis naviguer vers la page principale await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { WNavigationService.Default.Navigate(typeof(MainPage)); }); } }

Page 25: Windows 10 UWP App Development ebook

25

11. VariableSizedWrapGrid <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="4" ItemHeight="100" ItemWidth="100"> <Rectangle Fill="Green" Width="200" Height="200" VariableSizedWrapGrid.RowSpan="2" VariableSizedWrapGrid.ColumnSpan="2" Margin="4"/> <Rectangle Fill="Gray" Width="200" VariableSizedWrapGrid.ColumnSpan="2" Margin="4"/> <Rectangle Fill="Red" Margin="4"/> <Rectangle Fill="Blue" Margin="4"/> </VariableSizedWrapGrid>

La même chose pour un GridView

public class VariableGridView : GridView { protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { var variableItem = item as VariableSizedItem; if (variableItem != null) { var gridViewItem = element as GridViewItem; if (gridViewItem != null) { VariableSizedWrapGrid.SetColumnSpan(gridViewItem, variableItem.ColumnSpan); VariableSizedWrapGrid.SetRowSpan(gridViewItem, variableItem.RowSpan); } } base.PrepareContainerForItemOverride(element, item); } }

Le modèle

public class VariableItem { public string Title { get; set; } public SolidColorBrush BackgroundColor { get; set; } public int Height { get; set; } public int Width { get; set; } public int ColumnSpan { get; set; } public int RowSpan { get; set; } // etc. }

On peut changer la largeur,

hauteur et ainsi définir

combien de colonnes, lignes

sont occupées

Propriétés liées pour définir l’élément

dans le GridView, il pourrait avoir

d’autres propriétés avec des données

récupérées

On dérive le GridView et redéfinit

« PrepareContainerForItemOverride »

On change le nombre de colonnes

et lignes en rapport à l’élément

« VariableItem » (modèle défini)

Chaque élément de base a une taille de

100x100. Ils s’empilent horizontalement

(orientation) dans la limite de 4

Page 26: Windows 10 UWP App Development ebook

26

Ajout à la page

<local:VariableGridView x:Name="variableGridView"> <local:VariableGridView.ItemTemplate> <DataTemplate> <Grid Background="{Binding BackgroundColor}" Height="{Binding Height}" Width="{Binding Width}" Margin="4"> <TextBlock Text="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </DataTemplate> </local:VariableGridView.ItemTemplate> <local:VariableGridView.ItemsPanel> <ItemsPanelTemplate> <VariableSizedWrapGrid Orientation="Horizontal" MaximumRowsOrColumns="4" ItemHeight="100" ItemWidth="100"/> </ItemsPanelTemplate> </local:VariableGridView.ItemsPanel> </local:VariableGridView>

Dans le code-behind de la page

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); Items = new List<VariableItem>(); Items.Add(new VariableItem { Title = "First", BackgroundColor = new SolidColorBrush(Colors.Green), Height = 200, Width = 200, ColumnSpan = 2, RowSpan = 2 }); Items.Add(new VariableItem { Title = "Second", BackgroundColor = new SolidColorBrush(Colors.Gray), Width = 200, Height = 100, ColumnSpan = 2 }); Items.Add(new VariableItem { Title = "Three", BackgroundColor = new SolidColorBrush(Colors.Red), Height = 100, Width = 100, }); Items.Add(new VariableItem { Title = "Four", BackgroundColor = new SolidColorBrush(Colors.Blue), Height = 100, Width = 100, }); variableGridView.ItemsSource = Items; } public List<VariableItem> Items { get; set; } }

Page 27: Windows 10 UWP App Development ebook

27

II. Accent et Thème (Dark, Light) <Rectangle Fill="{ThemeResource SystemAccentColor}" Grid.Row="1"></Rectangle>

On peut changer le thème (« Light » ou « Dark ») pour toute l’application dans « app »

<Application x:Class="UWPAutoSuggestBoxDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPAutoSuggestBoxDemo" RequestedTheme="Light"> </Application>

Ou pour seulement des éléments ou contrôles avec l’attribut « RequestedTheme », exemple

<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" RequestedTheme="Dark"> <!--etc--> </RelativePanel>

Définir son propre thème <Application.Resources> <ResourceDictionary> <ResourceDictionary.ThemeDictionaries> <ResourceDictionary x:Key="Default"> <SolidColorBrush x:Key="BackgroundBrush" Color="Red" /> </ResourceDictionary> <ResourceDictionary x:Key="Light"> <SolidColorBrush x:Key="BackgroundBrush" Color="Gray" /> </ResourceDictionary> <ResourceDictionary x:Key="HighContrast"> <SolidColorBrush x:Key="BackgroundBrush" Color="{ThemeResource SystemColorWindowColor}" /> </ResourceDictionary> </ResourceDictionary.ThemeDictionaries> </ResourceDictionary> </Application.Resources>

Thème Dark, la couleur

sera rouge

Thème Light, la couleur

sera gris

Page 28: Windows 10 UWP App Development ebook

28

On peut également définir les thèmes dans des dictionnaires de ressources et les rendre accessibles à

l’application

<Application x:Class="UWPThemesDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPThemesDemo" RequestedTheme="Dark"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.ThemeDictionaries> <ResourceDictionary Source="Resources/Dark.xaml" x:Key="Default" /> <ResourceDictionary Source="Resources/Light.xaml" x:Key="Light" /> </ResourceDictionary.ThemeDictionaries> </ResourceDictionary> </Application.Resources> </Application>

Utilisation

<Grid Background="{ThemeResource BackgroundBrush}"> </Grid>

III. Design Time public class MainPageViewModel : ViewModelBase { public MainPageViewModel() { if (Windows.ApplicationModel.DesignMode.DesignModeEnabled) { } } }

Page 29: Windows 10 UWP App Development ebook

29

IV. DataTemplateSelector Permet d’afficher différents Templates dans une ListView ou un GridView pour une même source de

données.

public class SearchResultTemplateSelector : DataTemplateSelector { public DataTemplate VideoTemplate { get; set; } public DataTemplate ChannelTemplate { get; set; } public DataTemplate PlayListTemplate { get; set; } protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if(item is Video) { return VideoTemplate; } if (item is Channel) { return ChannelTemplate; } if (item is PlayList) { return PlayListTemplate; } return base.SelectTemplateCore(item, container); } }

Exemple de Templates

<DataTemplate x:Key="YouTube320VideoItemTemplate" x:DataType="models:Video"> <!--etc--> </DataTemplate> <DataTemplate x:Key="YouTubeChannelItemTemplate" x:DataType="models:Channel"> <!--etc--> </DataTemplate> <DataTemplate x:Key="YouTubePlaylistItemTemplate" x:DataType="models:PlayList"> <!--etc--> </DataTemplate>

Models

public class ModelBase { // properties }

public class Video :ModelBase { // } public class Channel :ModelBase { // } public class PlayList :ModelBase { // }

3 propriétés permettant de

définir un Template à retourner

selon le type de l’élément reçu

Les 3 classes peuvent hériter d’une

classe de base. Ainsi la source de

données sera une collection de

« ModelBase »

Page 30: Windows 10 UWP App Development ebook

30

ViewModel

public class SearchPageViewModel : ViewModelBase { private ObservableCollection<ModelBase> _results; public ObservableCollection<ModelBase> Results { get { return _results; } set { SetProperty(ref _results, value); } } // etc. }

Utilisation

En ressources (de la page par exemple)

<local:SearchResultTemplateSelector x:Key="TemplateSelector" VideoTemplate="{StaticResource YouTubeVideoItemTemplate}" ChannelTemplate="{StaticResource YouTubeChannelItemTemplate}" PlayListTemplate="{StaticResource YouTubeSearchPlayListItemTemplate}"> </local:SearchResultTemplateSelector>

Puis définition de l’ « ItemTemplateSelector »

<GridView x:Name="itemsGridView" ItemsSource="{x:Bind ViewModel.Results,Mode=OneWay}" ItemTemplateSelector="{StaticResource TemplateSelector}"> </GridView>

Le GridView affiche un Template

différent selon que c’est une

vidéo, une playlist ou une chaine

par exemple

Page 31: Windows 10 UWP App Development ebook

31

Dernier élément « Afficher plus » pour ListView ou GridView Sur ce même principe on peut imaginer un « last item » template qui afficherait un bouton afficher

plus par exemple.

public class LastTemplateSelector : DataTemplateSelector { public DataTemplate NormalTemplate { get; set; } public DataTemplate LastTemplate { get; set; } protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if (item is DataItem) { return NormalTemplate; } if (item is LastItem) { return LastTemplate; } return base.SelectTemplateCore(item, container); } }

Pour les modèles on a deux classes héritant de « ModelBase

public class ModelBase { public string Title { get; set; } } public class LastItem : ModelBase { public LastItem(string title) { Title = title; } } public class DataItem : ModelBase { public int Id { get; set; } public string Subtitle { get; set; } // etc. }

Page 32: Windows 10 UWP App Development ebook

32

ViewModel

public class MainPageViewModel { public ObservableCollection<ModelBase> Items { get; set; } private ICommand _goDetailsPageCommand; public ICommand GoDetailsPageCommand { get { return _goDetailsPageCommand ?? (_goDetailsPageCommand = new RelayCommand<ItemClickEventArgs>((item) => { var selectedItem = item.ClickedItem; if(selectedItem is DataItem) { // navigate to data } if(selectedItem is LastItem) { // load more data } })); } } public MainPageViewModel() { Items = new ObservableCollection<ModelBase>(); Items.Add(new DataItem(1, "Titre 1", "Subtile", "Lorem ipsum dolor sit …", "Images/group.jpg")); Items.Add(new DataItem(2, "Titre 2", "Subtile", "Lorem ipsum dolor sit …", "Images/group_2.jpg")); // etc. // Last Items.Add(new LastItem("Afficher plus")); } }

On ajoute dans le code behind de la page une propriété pour le binding (avec x :Bind)

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); ViewModel = new MainPageViewModel(); } public MainPageViewModel ViewModel { get; set; } }

Quand l’utilisateur clique sur

un élément du GridView soit

on le diriga vers la page détails

soit on charge plus d’éléments.

(Il faudra les insérer avant le

bouton)

Page 33: Windows 10 UWP App Development ebook

33

En ressources de la page

<local:LastTemplateSelector x:Key="LastTemplateSelector" NormalTemplate="{StaticResource ImageOverlayTemplate}" LastTemplate="{StaticResource LastTemplate}"/>

On définit un template simple pour le type « LastItem »

<DataTemplate x:Key="LastTemplate" x:DataType="models:LastItem"> <Grid Width="200" Height="200" Background="{ThemeResource SystemAccentColor}" Margin="4"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </DataTemplate>

Le GridView avec ItemTemplateSelector et behavior

<GridView x:Name="itemsListView" ItemsSource="{x:Bind ViewModel.Items}" ItemTemplateSelector="{StaticResource LastTemplateSelector}" SelectionMode="None" IsItemClickEnabled="True"> <Interactivity:Interaction.Behaviors> <Core:EventTriggerBehavior EventName="ItemClick"> <Core:InvokeCommandAction Command="{x:Bind ViewModel.GoDetailsPageCommand}" CommandParameter="{x:Bind itemsListView.SelectedItem}"/> </Core:EventTriggerBehavior> </Interactivity:Interaction.Behaviors> </GridView>

Page 34: Windows 10 UWP App Development ebook

34

V. HeaderGroup

Models

public sealed class DataSource { public static IEnumerable<DataGroup> GetGroups() { var groups = new List<DataGroup>(); var groupA = new DataGroup("A"); groupA.Items.Add(new DataItem("Aanor")); groupA.Items.Add(new DataItem("Aaricia")); groupA.Items.Add(new DataItem("Aaron")); // etc. groups.Add(groupA); var groupB = new DataGroup("B"); groupB.Items.Add(new DataItem("Babet")); groupB.Items.Add(new DataItem("Babeth")); // etc. groups.Add(groupB); // etc. return groups; } } public class DataGroup { public string TitleGroup { get; private set; } public ObservableCollection<DataItem> Items { get; set; } public DataGroup(string titleGroup) { TitleGroup = titleGroup; Items = new ObservableCollection<DataItem>(); } } public class DataItem { public string TitleItem { get; set; } public DataItem(string titleItem) { TitleItem = titleItem; } }

Switch du nom de groupe au

défilement

Page 35: Windows 10 UWP App Development ebook

35

ViewModel

public class MyDataViewModel { public ObservableCollection<DataGroup> Groups { get; set; } public void LoadData() { var groups = DataSource.GetGroups(); if (groups != null) { Groups = new ObservableCollection<DataGroup>(groups); } } }

Utilisation

Code behind de la page

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); ViewModel = new MyDataViewModel(); } public MyDataViewModel ViewModel { get; set; } protected override void OnNavigatedTo(NavigationEventArgs e) { ViewModel.LoadData(); } }

<ListView ItemsSource="{x:Bind cvs.View}" ItemTemplate="{StaticResource DataItemTemplate}"> <ListView.GroupStyle> <GroupStyle HeaderTemplate="{StaticResource HeaderTemplate}" /> </ListView.GroupStyle> </ListView>

Templates et source de données groupée

<Page.Resources> <CollectionViewSource x:Name="cvs" Source="{x:Bind ViewModel.Groups}" IsSourceGrouped="True" ItemsPath="Items" /> <DataTemplate x:Key="HeaderTemplate" x:DataType="models:DataGroup"> <TextBlock Text="{x:Bind TitleGroup}" Foreground="{ThemeResource ApplicationForegroundThemeBrush}" Style="{StaticResource SubtitleTextBlockStyle}"/> </DataTemplate> <DataTemplate x:Key="DataItemTemplate" x:DataType="models:DataItem"> <TextBlock Text="{x:Bind TitleItem}" Style="{StaticResource BaseTextBlockStyle}"/> </DataTemplate> </Page.Resources>

Utilisation ici d’une ListView

mais on peut faire la même

chose avec un GridView

Page 36: Windows 10 UWP App Development ebook

36

DataTemplates

Pour ListView Texte seul

<DataTemplate x:Key="TextListTemplate" x:DataType="models:DataItem"> <Grid Width="280"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" Margin="8,0,0,0" HorizontalAlignment="Left" TextWrapping="Wrap"/> </Grid> </DataTemplate>

Icone et texte

<DataTemplate x:Key="IconTextTemplate" x:DataType="models:DataItem"> <StackPanel Orientation="Horizontal" Width="500"> <Image Height="45" Width="45" Margin="0,8,0,8" Source="{x:Bind Image}" Stretch="UniformToFill"/> <StackPanel Orientation="Vertical" VerticalAlignment="Top" Margin="8,8,0,0"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" /> <TextBlock Text="{x:Bind Subtitle}" Margin="0,4,8,0" Style="{StaticResource BodyTextBlockStyle}" /> </StackPanel> </StackPanel> </DataTemplate>

Page 37: Windows 10 UWP App Development ebook

37

Image et texte

<DataTemplate x:Key="ImageTextListTemplate" x:DataType="models:DataItem"> <StackPanel Orientation="Horizontal" Width="500" Height="130"> <Image Height="110" Width="110" Margin="0,8,0,8" Source="{x:Bind Image}" Stretch="UniformToFill"/> <StackPanel VerticalAlignment="Center" Width="380" Margin="8,8,0,0"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" /> <TextBlock Text="{x:Bind Subtitle}" TextWrapping="WrapWholeWords" Style="{StaticResource CaptionTextBlockStyle}" /> <TextBlock Text="{x:Bind Description}" TextWrapping="WrapWholeWords" Margin="0,8,0,0" Style="{StaticResource BodyTextBlockStyle}"/> </StackPanel> </StackPanel> </DataTemplate>

Overlay

<DataTemplate x:Key="ImageOverlayTemplate" x:DataType="models:DataItem"> <Grid Height="110"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Image Source="{x:Bind Image}" Stretch="Uniform" Grid.Column="1" Grid.RowSpan="2" Margin="0,8,0,8"/> <Border Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" Margin="0,8,0,8"> <TextBlock Text="{x:Bind Title}" Margin="8,8,0,0" TextWrapping="Wrap" HorizontalAlignment="Left" Style="{StaticResource BaseTextBlockStyle}"/> </Border> <TextBlock Text="{x:Bind Subtitle}" Grid.Row="1" Style="{StaticResource BodyTextBlockStyle}" TextWrapping="Wrap" Margin="8,0,0,0"/> </Grid> </DataTemplate> </Page.Resources>

Page 38: Windows 10 UWP App Development ebook

38

Pour GridView Texte seul

<DataTemplate x:Key="TextTemplate" x:DataType="models:DataItem"> <StackPanel Orientation="Horizontal" Width="300"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" Margin="8,0,0,0"/> </StackPanel> </DataTemplate>

Icone et texte

<DataTemplate x:Key="IconTextTemplate" x:DataType="models:DataItem"> <StackPanel Orientation="Horizontal" Width="280"> <Image Source="{x:Bind Image}" Width="45" Height="45" Margin="8" Stretch="UniformToFill"/> <StackPanel VerticalAlignment="Center" Margin="8,0"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" /> <TextBlock Text="{x:Bind Subtitle}" /> </StackPanel> </StackPanel> </DataTemplate>

Image et texte

<DataTemplate x:Key="ImageTextTemplate" x:DataType="models:DataItem"> <StackPanel Orientation="Horizontal" Width="500" Height="130"> <Image Source="{x:Bind Image}" Stretch="Fill" Height="110" Width="110" Margin="8,8,0,8"/> <StackPanel Width="350" Margin="8,8,0,0" VerticalAlignment="Center"> <TextBlock Text="{x:Bind Title}" Style="{StaticResource BaseTextBlockStyle}" /> <TextBlock Text="{x:Bind Subtitle}" Style="{StaticResource CaptionTextBlockStyle}"/> <TextBlock Text="{x:Bind Description}" TextWrapping="Wrap" Margin="0,8,0,0"/> </StackPanel> </StackPanel> </DataTemplate>

Page 39: Windows 10 UWP App Development ebook

39

Overlay

<DataTemplate x:Key="ImageOverlayTemplate" x:DataType="models:DataItem"> <StackPanel Height="130" Width="190" Margin="4,4,4,8"> <TextBlock Text="{x:Bind Title}" Margin="8,4" Width="186" Style="{StaticResource BaseTextBlockStyle}" HorizontalAlignment="Left"/> <Image Source="{x:Bind Image}" Margin="8,0,8,8" Stretch="UniformToFill"/> </StackPanel> </DataTemplate>

Page 40: Windows 10 UWP App Development ebook

40

VI. Adaptive UI Une application UWP doit pouvoir s’exécuter sur différents appareils. Il va falloir adapter la page

pour les différentes résolutions et orientations (Portrait, paysage).

Penser en Pixel effectif (et non en pixel réel)

« Four is the magic number » (tailles, marges multiples de 4)

« 6R »

Reposition

Resize

Reflow (basculer de 2 à 3 colonnes par exemple)

Reveal

Replace

Re-architect

Utilisation de RelativePanel pour pouvoir repositionner les éléments

Utilisation Visual States et AdaptiveTrigger pour déplacer des blocs ou éléments, redimensionner,

cacher, etc.

Snap points :

- 320

- 548 Phone

- 720 Tablet

- 1024 Desktop

Astuce : afficher la taille courante de la page

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); this.SizeChanged += (s, e) => { textBlock.Text = e.NewSize.Width.ToString(); }; }

Page 41: Windows 10 UWP App Development ebook

41

1. Adaptive Triggers

Voir exemple Responsive Techniques

1. Ouvrir le projet avec Blend

2. Ajouter des Etats Visuels

Panneau Etats : Ajouter un groupe d’états puis des états visuels

3. Changer les propriétés des éléments selon les états

Sélectionner l’état dans le panneau « Etats » et l’élément dans le panneau « Objets et chronologie »,

puis modifier les propriétés de cet élément dans le panneau « Propriétés »

AdaptiveTrigger ou Custom Trigger

Ajout de groupe d’états Ajout d’états viusels

Ajouter un AdaptiveTrigger Réglage des propriétés (MinWindowHeight et

MinWindowWidth pour un AdaptiveTrigger)

Page 42: Windows 10 UWP App Development ebook

42

Repositionnement avec RelativePanel

<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="VisualStateMin0"> <VisualState.Setters> <Setter Target="textBlock.(RelativePanel.Below)" Value="image"/> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="1"/> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="VisualStateMin548"> <VisualState.Setters> <Setter Target="textBlock.(RelativePanel.RightOf)" Value="image"/> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="548"/> </VisualState.StateTriggers> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Image x:Name="image" Source="Images/breakfast.jpg" Width="300" Margin="8"/> <TextBlock x:Name="textBlock" Text="Une petite faim?" TextWrapping="NoWrap" Style="{StaticResource SubheaderTextBlockStyle}" Margin="8" /> </RelativePanel>

De 0 à 548

> 548

Setters

StateTriggers

De 0 à 548 on place le texte

en-dessous l’image

> 548 on place le texte à

droite de l’image

Page 43: Windows 10 UWP App Development ebook

43

2. Master details > 548

Page divisée avec à gauche la liste, à droite le détail

De 0 à 548

La liste occupe toute la largeur de la page (ColumnSpan=2), la partie détail est cachée (Collapsed) et

lorsque l’on clique sur un élément de la liste on navigue vers une page détails

Une variante consiste donner un nom à chaque colonne de la grille (exemple « masterColumn »

et « detailsColumn ») et changer la taille pour de 0 à 548 (ou 720) passer masterColumn à « * » et

detailsColumn à 0. Exemple XamlMasterDetail

Page 44: Windows 10 UWP App Development ebook

44

<Page …> <Page.Transitions> <TransitionCollection> <NavigationThemeTransition /> </TransitionCollection> </Page.Transitions> <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="VisualStateMin0"> <VisualState.Setters> <Setter Target="personDetailsControl.(UIElement.Visibility)" Value="Collapsed"/> <Setter Target="peopleList.(Grid.ColumnSpan)" Value="2"/> </VisualState.Setters> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="1"/> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="VisualStateMin548"> <VisualState.StateTriggers> <AdaptiveTrigger MinWindowWidth="548"/> </VisualState.StateTriggers> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <ListView x:Name="peopleList" ItemsSource="{x:Bind People}" IsItemClickEnabled="True" ItemClick="peopleList_ItemClick" /> <Controls:PersonDetailsControl x:Name="personDetailsControl" Background="#ccc" DataContext="{Binding SelectedItem, ElementName=peopleList}" Grid.Column="1"/> </Grid>

Navigation vers une page Détails si la partie détails est cachée (>548)

private void ListView_ItemClick(object sender, ItemClickEventArgs e) { if (personDetailsControl.Visibility == Visibility.Collapsed) { Frame.Navigate(typeof(PersonDetailsPage), e.ClickedItem); } }

La liste à gauche de la grille

Un contrôle utilisateur affichant le détail à droite

Visual States

On peut ajouter une transition à

page pour effet de retour

Page 45: Windows 10 UWP App Development ebook

45

La page Détails avec un bouton retour un titre et le contrôle utilisateur

<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Button x:Name="backButton" Style="{StaticResource NavigationBackButtonSmallStyle}" TabIndex="1" Margin="8" Click="backButton_Click" AutomationProperties.Name="Back" ToolTipService.ToolTip="Back" /> <TextBlock Style="{ThemeResource TitleTextBlockStyle}" Text="{Binding Name, Mode=OneWay}" RelativePanel.RightOf="backButton" RelativePanel.AlignVerticalCenterWith="backButton" Margin="8"/> <Controls:PersonDetailsControl RelativePanel.Below="backButton" /> </RelativePanel>

private void backButton_Click(object sender, RoutedEventArgs e) { Frame.GoBack(new DrillInNavigationTransitionInfo()); }

3. Custom adaptive triggers

voir l’exemple XamlStateTriggers

using Windows.System.Profile; using Windows.UI.Xaml; namespace UWPAdaptiveTriggerDemo.CustomTriggers { public class DeviceFamilyTrigger : StateTriggerBase { private string _deviceFamily; public string DeviceFamily { get { return _deviceFamily; } set { var qualifiers = ResourceContext.GetForCurrentView().QualifierValues; _deviceFamily = value; SetActive(_deviceFamily == qualifiers["DeviceFamily"]); // ou //var currentDeviceFamily = AnalyticsInfo.VersionInfo.DeviceFamily; //_deviceFamily = value; //SetActive(_deviceFamily == currentDeviceFamily); } } } }

Avec Blend, pour un état visuel

Hérite de « StateTriggerBase »

On appelle la méthode « SetActive »

Propriété(s) accessible(s) servant pour

déterminer quand l’état est activé

Sélectionner « Autre type » …

Page 46: Windows 10 UWP App Development ebook

46

On change ensuite les propriétés des éléments de la page selon les états visuels.

Et le « Custom State Trigger »

On définit ensuite les valeurs qui

rendront actif l’état visuel

Page 47: Windows 10 UWP App Development ebook

47

Dans cet exemple, on affiche une image quand on est sur desktop, et une autre quand on est sur

mobile

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="DeviceFamilyStates"> <VisualState x:Name="Desktop"> <VisualState.StateTriggers> <triggers:DeviceFamilyTrigger DeviceFamily="Windows.Desktop" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="desktopImage.Visibility" Value="Visible" /> <Setter Target="mobileImage.Visibility" Value="Collapsed" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Mobile"> <VisualState.StateTriggers> <triggers:DeviceFamilyTrigger DeviceFamily="Windows.Desktop" /> </VisualState.StateTriggers> <VisualState.Setters> <Setter Target="desktopImage.Visibility" Value="Collapsed" /> <Setter Target="mobileImage.Visibility" Value="Visible" /> </VisualState.Setters> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Image x:Name="desktopImage" Source="../Assets/desktop-family.png"></Image> <Image x:Name="mobileImage" Source="../Assets/mobile-family.png"></Image> </Grid>

Page 48: Windows 10 UWP App Development ebook

48

4. DeviceFamily On peut créer une version de page selon les devices

Si on navigue vers la page « Scenario4 », automatiquement la vue pour Mobile sera affichée si on est

sur ce device.

On peut obtenir le device également en code

var qualifiers = ResourceContext.GetForCurrentView().QualifierValues; if (qualifiers["DeviceFamily"] == "DeviceFamily-Xbox") { Frame.Navigate(typeof(MainPage_Xbox)); } else { Frame.Navigate(typeof(MainPage)); }

5. Astuce : réactiver les animations, transitions Windows Régler les effets visuels de Windows. Permet de réactiver les animations, transitions au cas où elles

auraient été désactivées pour améliorer les performances par exemple.

Vue correspondante

pour Mobile

Vue par « défaut »

Page 49: Windows 10 UWP App Development ebook

49

VII. x :Bind « Compiled Binding »

Voir exemple XamlBind

Les +

- Meilleures performances que le binding « classique ». Très performant pour afficher des

listes.

- Va chercher automatiquement les propriétés dans le code-behind de la page sans définir de

DataContext. Pour l’utilisation de ViewModels on définit donc directement une propriété

dans le code-behind.

- Le mode par défaut de binding est « OneTime ». Il faut donc définir un mode OneWay ou

TwoWay si ce n’est pas suffisant.

- On peut utiliser « x :Bind » pour binder des événements, permet d’éviter l’utilisation de

RelayCommand ou de behavior pour des scénarios simples.

Les -

- Problème avec les commandes dans les DataTemplates de fichier de ressources (Besoin

d’aller chercher le DataContext du parent)

- Problème avec SelectedItem (renvoyant un objet) avec ListView / GridView .., besoin de faire

des convertisseurs ?

- Problème avec les styles

- Les attributs ElementName, RelativeSource, Source, UpdateSourceTrigger ne sont pas pris

en charge par « x :Bind »

- Solution : il faudra parfois mélanger le binding classique et binding avec « x :Bind ». On règle

alors le DataContext sur le même ViewModel défini en propriété dans le code-behind de la

page.

1. Binding de collection On définit une propriété dans le code-behind de la page sans définir de DataContext

public sealed partial class Scenario1 : Page { public Scenario1() { this.InitializeComponent(); People = new ObservableCollection<Person> { new Person { Name ="Marie Bellin"}, new Person { Name ="Jérôme Romagny"} }; } public ObservableCollection<Person> People { get; set; } }

(Le modèle utilisé)

public class Person { public string Name { get; set; } public override string ToString() { return Name; } }

Page 50: Windows 10 UWP App Development ebook

50

2. Binding dans la page

<ListView ItemsSource="{x:Bind People}" />

2. Avec DataTemplate On définit le DataTemplate en ressources de la page

<DataTemplate x:Key="personItemTemplate" x:DataType="models:Person"> <StackPanel Orientation="Horizontal"> <SymbolIcon Symbol="People" Margin="8,0,0,0"/> <TextBlock Text="{x:Bind Name}" Margin="8,0,0,0"/> </StackPanel> </DataTemplate>

<ListView ItemsSource="{x:Bind People}" ItemTemplate="{StaticResource personItemTemplate}" />

3. Avec dictionnaire de ressources (ResourceDictionary) 1. Ajouter un dictionnaire de ressources

<ResourceDictionary x:Class="UWPDataBindingDemo.Resources.Templates" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:UWPDataBindingDemo.Resources" xmlns:models="using:UWPDataBindingDemo.Models"> <DataTemplate x:Key="personItemTemplateFromResourceDictionary" x:DataType="models:Person"> <StackPanel Orientation="Horizontal"> <SymbolIcon Symbol="People" Margin="8,0,0,0"/> <TextBlock Text="{x:Bind Name}" Margin="8,0,0,0"/> </StackPanel> </DataTemplate> </ResourceDictionary>

2. Ajout d’une classe (partielle) du même nom que le dictionnaire de ressources

namespace UWPDataBindingDemo.Resources { public partial class Templates { public Templates() { InitializeComponent(); } } }

Utilisation du DataTemplate du dictionnaire de resources

<Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <resources:Templates /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources>

Si aucun DataTemplate n’est défini c’est la méthode

ToString des éléments qui est appelée

Ajouter un namespace et

définir le DataType

Exemple de template

Ajout d’un nom de classe

Attention au namespace

Référencer le dictionnaire en

ressources de la page ou pour

toute l’application dans « App »

Page 51: Windows 10 UWP App Development ebook

51

<ListView ItemsSource="{x:Bind People}" ItemTemplate="{StaticResource personItemTemplateFromResourceDictionary}" />

4. « RelativeSource » et « ElementName » … lier au nom de l’élément <Slider x:Name="slider" Header="Slider" Maximum="10" Margin="8"/> <TextBlock Text="{x:Bind slider.Value,Mode=OneWay}" Margin="8"/>

5. « Source » et « DataContext ».. Ajouter une propriété du ViewModel dans le

code-behind public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); ViewModel = new MyViewModel(); DataContext = ViewModel; } public MyViewModel ViewModel { get; set; } }

Variantes

public sealed partial class MainPage : Page { private MainViewModel viewModel; public MainPage() { this.InitializeComponent(); this.Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { viewModel = new MyViewModel(); this.DataContext = viewModel; } } }

public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); this.DataContextChanged += (s, e) => { ViewModel = DataContext as MyViewModel; }; } public MainPageViewModel ViewModel { get; set; } }

Parfois il faudra définir le

DataContext pour mélanger les deux

formes de binding

Page 52: Windows 10 UWP App Development ebook

52

<TextBlock Text="{x:Bind ViewModel.Message}"/>

public class MyViewModel { public string Message { get; set; } public MyViewModel() { Message = "Bonjour!"; } }

6. Binding Events Permet d’éviter l’utilisation de « RelayCommand » (ICommand) ou de behavior

« EventToCommand » pour des scénarios simples, de « déplacer » les événements du code-

behind de la page vers le ViewModel par exemple.

N’accepte pas les paramètres « personnels », pas de support de CanExecute

Exemple

public class MyViewModel { public void DoWork1() { } public void DoWork2(object sender, RoutedEventArgs e) { } public void DoWork3(object sender, object e) { } }

Dans le code-behind de la page

public sealed partial class Scenario4 : Page { public Scenario4() { this.InitializeComponent(); ViewModel = new MyViewModel(); } public MyViewModel ViewModel { get; set; } }

<Button Content="Sans paramètre ... void DoWork1()" Click="{x:Bind ViewModel.DoWork1}"/> <Button Content="void DoWork2(object sender, RoutedEventArgs e)" Click="{x:Bind ViewModel.DoWork2}"/> <Button Content="void DoWork3(object sender, object e)" Click="{x:Bind ViewModel.DoWork3}"/>

Les 3 signatures

acceptées

Page 53: Windows 10 UWP App Development ebook

53

7. Defer loading Dans la page

<Grid x:Name="myGrid" x:DeferLoadStrategy="Lazy" Background="Red" />

Dans le code-behind

private void Button_Click(object sender, RoutedEventArgs e) { FindName("myGrid"); }

VIII. Application Lifecycle Documentation

Il faut donner l’illusion que l’application n’a pas été suspendue quand celle-ci est résumée.

Launch (« OnLaunched » de « App »).

- « PreviousExecutionState » : NotRunning, Running,Suspended, Terminated, ClosedByUser. Si

l’application est fermée par l’utilisateur (« ClosedByUser ») ne pas restaurer.

- « ActivationKind » : Launch, File, Protocol, Cortana, Secondary tile, toast, search contract,etc.

Suspend : Les applications Desktop sont suspendues quand elles sont minimisées dans la barre

de tâches.

- Sauvegarder les états de la page et les données (Local, Roaming,…)

- « App » : Sauvegarder l’historique de navigation

Resume :

- « App » : Restaurer l’historique de navigation, retourner sur la page avant la suspension

- Restaurer les états de la page (champs) et les données (Local, Roaming …)

Note : Les applications UWP n’incluent pas « SuspensionManager » et « NavigationHelper ».

La grille n’est affichée qu’à

l’appel de FindName

Page 54: Windows 10 UWP App Development ebook

54

1. Historique de navigation (« App ») Sauvegarder la navigation

private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); Frame rootFrame = Window.Current.Content as Frame; ApplicationData.Current.LocalSettings.Values["NavigationState"] = rootFrame.GetNavigationState(); deferral.Complete(); }

Restaurer la navigation

protected override void OnLaunched(LaunchActivatedEventArgs e) { // etc. if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { if (ApplicationData.Current.LocalSettings.Values.ContainsKey("NavigationState")) { rootFrame.SetNavigationState((string)ApplicationData.Current.LocalSettings.Values["NavigationState"]); } } }

2. Etats de la page et données Sauver les états de la page courante à la suspension (« code-behind de la page » )

protected override void OnNavigatedFrom(NavigationEventArgs e) { vm.SaveData(); }

ViewModel

public void SaveData() { ApplicationData.Current.RoamingSettings.Values["ValueOne"] = ValueOne; ApplicationData.Current.RoamingSettings.Values["ValueTwo"] = ValueTwo; }

Restaurer les états

protected override void OnNavigatedTo(NavigationEventArgs e) { if(e.NavigationMode == NavigationMode.New) { // clear vm.ClearData(); } else { vm.LoadData(); } }

Exemple sauvegarde de deux

valeurs de champs

Page 55: Windows 10 UWP App Development ebook

55

ViewModel

public void LoadData() { if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("ValueOne")) { ValueOne = ApplicationData.Current.RoamingSettings.Values["ValueOne"].ToString(); } if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("ValueTwo")) { ValueTwo = ApplicationData.Current.RoamingSettings.Values["ValueTwo"].ToString(); } } public void ClearData() { if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("ValueOne")) { ApplicationData.Current.RoamingSettings.Values.Remove("ValueOne"); } if (ApplicationData.Current.RoamingSettings.Values.ContainsKey("ValueTwo")) { ApplicationData.Current.RoamingSettings.Values.Remove("ValueTwo"); } }

Page 56: Windows 10 UWP App Development ebook

56

IX. Tiles, toasts Documentation

Voir exemple Notifications

Tile On définit les Assets toujours dans le manifeste de l’application, onglet « Ressources visuelles »

- Petit : 71x71 (« généré automatiquement » si l’Asset n’est pas présent)

- Moyen : 150x150 (Square150x150Logo.png)

- Large : 310x150 (Wide310x150Logo.png)

- Grand : 310x310 (Wide310x310Logo.png)

Vignette de l’application : Chercher l’application depuis le champ recherche de Windows 10 puis

« Epingler à l’écran de démarrage »

71x71 150x150 310x150

310x310

Seulement pour desktop

Page 57: Windows 10 UWP App Development ebook

57

Note : si on définit la couleur d’arrière-plan des vignettes sur « transparent », c’est alors la couleur

d’accent de Windows qui est appliqué

Vignette secondaire : ajoutée par code. La vignette est désormais ajoutée directement sans boite de

dialogue (comme c’était le cas avec Windows 8.1)

private async void OnPinSecondaryTile(object sender, RoutedEventArgs e) { var isPinned = SecondaryTile.Exists(tileId); if (!isPinned) { await PinSecondaryTile(tileId); } } const string tileId = "DetailsTile "; private async Task<bool> PinSecondaryTile(string tileId) { string tileActivationArguments = " mon argument"; var tile = new SecondaryTile(tileId, "Vignette secondaire", tileActivationArguments, new Uri("ms-appx:///Assets/Square150x150Logo.png", UriKind.Absolute), TileSize.Square150x150); tile.VisualElements.Wide310x150Logo = new Uri("ms-appx:///Assets/Wide310x150Logo.png", UriKind.Absolute); tile.VisualElements.Square310x310Logo = new Uri("ms-appx:///Assets/Square310x310Logo.png", UriKind.Absolute); // détails tile.VisualElements.ShowNameOnSquare150x150Logo = true; tile.VisualElements.ShowNameOnWide310x150Logo = true; tile.VisualElements.ShowNameOnSquare310x310Logo = true; //tile.VisualElements.BackgroundColor = Colors.DarkOrange; tile.VisualElements.ForegroundText = ForegroundText.Light; tile.RoamingEnabled = false; bool isPinned = await tile.RequestCreateAsync(); return isPinned; }

Nom affiché, arguments, uri de la

tile 150x150 et taille désirée de la

vignette

Page 58: Windows 10 UWP App Development ebook

58

Notification de vignette

private void OnUpdateTile(object sender, RoutedEventArgs e) { string image = "ms-appx:///Assets/image_1.jpg"; string title = "Titre!"; string message = "Nouveau message!"; string xml = string.Format(@"<tile> <visual version=""2""> <binding template=""TileSquare150x150PeekImageAndText02"" fallback=""TileSquarePeekImageAndText02""> <image id=""1"" src=""{0}"" alt=""alt text""/> <text id=""1"">{1}</text> <text id=""2"">{2}</text> </binding> <binding template=""TileWide310x150PeekImage01"" fallback=""TileWidePeekImage01""> <image id=""1"" src=""{0}""/> <text id=""1"">{1}</text> <text id=""2"">{2}</text> </binding> </visual> </tile>", image, title, message); var document = new XmlDocument(); document.LoadXml(xml); var notification = new TileNotification(document); TileUpdateManager.CreateTileUpdaterForApplication().Update(notification); }

« Scheduled » (différé)

// etc. var notification = new ScheduledTileNotification(document, DateTimeOffset.Now.AddSeconds(10)); TileUpdateManager. CreateTileUpdaterForSecondaryTile(tileId). AddToSchedule(notification);

« Periodic » (Web Service appelé toutes les 30 minutes, 60 minutes, 6 heures, 12 heures, 24 heures)

// etc. var updater = TileUpdateManager.CreateTileUpdaterForSecondaryTile(tileId); var uri = new Uri("http://localhost:3660/api/Notification/"); updater.StartPeriodicUpdate(uri, PeriodicUpdateRecurrence.Hour);

« Push » (Push Services)

Documentation

Animation « cube 3D »

Défilement

Notification de la vignette principale. On peut également

notifier les vignettes secondaires en passant le « tile id »

Page 59: Windows 10 UWP App Development ebook

59

Adaptive Tiles On peut toujours utiliser les templates de Windows 8.1 ou on peut utiliser les « Adaptive Templates »

qui permettent plus de souplesse et de personnalisation

Adaptive Tile Schema

Exemple

private void OnAdaptiveTile(object sender, RoutedEventArgs e) { string image = "ms-appx:///Assets/image_1.jpg"; string title = "Titre!"; string message = "Nouveau message!"; string xml = string.Format(@"<tile> <visual> <binding template=""TileSmall""> <image src=""{0}"" placement=""background""></image> </binding> <binding template=""TileMedium""> <image src=""{0}"" placement=""background""></image> <text hint-style=""caption"" hint-wrap=""true"">{1}</text> <text hint-style=""captionSubtle"" hint-wrap=""true"">{2}</text> </binding> <binding template=""TileWide""> <image src=""{0}"" placement=""background""></image> <text hint-style=""title"" hint-wrap=""true"">{1}</text> <text hint-style=""subSubtle"" hint-wrap=""true"">{2}</text> </binding> <binding template=""TileLarge"" branding=""nameAndLogo""> <group> <subgroup> <text hint-style=""title"">{1}</text> <text hint-style=""subSubtle"">{2}</text> </subgroup> </group> <image src=""{0}"" placement=""inline""></image> </binding> </visual> </tile>", image, title, message); var document = new XmlDocument(); document.LoadXml(xml); var notification = new TileNotification(document); TileUpdateManager.CreateTileUpdaterForApplication().Update(notification); }

Image en arrière-plan,

texte par-dessus avec styles

Vignette 71x71

Vignette 150x150

Vignette 310x150

Vignette 310x310

Placement de l’image en arrière-plan

(background) , on pourrait la placer en

ligne avec un alignement

On définit le style du texte

(caption, etc.) .« hint-

wrap » place devant

l’image d’arrière-plan

« branding » :

nom et logo

(44x44)

Affichage du nom

et logo

Image « inline »

Groupe et image

en ligne

Page 60: Windows 10 UWP App Development ebook

60

Toast Les toasts servent soit à afficher un message, soit propose une action.

On peut utiliser les templates de toast de Windows 8.1 ou on peut utiliser les adaptives templates.

private void OnSendToast(object sender, RoutedEventArgs e) { string title = "Mon application"; string message = "Nouveau message!"; string xml = string.Format(@"<toast> <visual> <binding template=""ToastText02""> <text id=""1"">{0}</text> <text id=""2"">{1}</text> </binding> </visual> </toast>", title, message); var document = new XmlDocument(); document.LoadXml(xml); var notification = new ToastNotification(document); ToastNotificationManager.CreateToastNotifier().Show(notification); }

Adaptive toast

Toast

Image remplaçant le

logo

Image « inline »

Centre de

notifications

Page 61: Windows 10 UWP App Development ebook

61

private void OnSendAdaptiveToast(object sender, RoutedEventArgs e) { string image = "ms-appx:///Assets/image_1.jpg"; string newLogo = "ms-appx:///Assets/image_2.png"; string title = "Mon application"; string message = "Nouveau message!"; string xml = string.Format(@"<toast> <visual> <binding template=""ToastGeneric""> <image src=""{0}"" placement=""appLogoOverride""/> <text>{1}</text> <text>{2}</text> <image src=""{3}"" placement=""inline""/> </binding> </visual> </toast>",newLogo, title, message,image); var document = new XmlDocument(); document.LoadXml(xml); var notification = new ToastNotification(document); ToastNotificationManager.CreateToastNotifier().Show(notification); }

Scénarios

<toast scenario=""reminder"">

private void OnSendAlarmToast(object sender, RoutedEventArgs e) { string title = "Alarme!"; string message = "Message!"; string xml= string.Format(@"<toast launch='args' scenario='alarm'> <visual> <binding template='ToastGeneric'> <text>{0}</text> <text>{1}</text> </binding> </visual> <actions> <action arguments = 'snooze' content = 'snooze' /> <action arguments = 'dismiss' content = 'dismiss' /> </actions> </toast>",title,message); var document = new XmlDocument(); document.LoadXml(xml); var notification = new ToastNotification(document); ToastNotificationManager.CreateToastNotifier().Show(notification); }

Reminder, alarm ou

incomingCall

Page 62: Windows 10 UWP App Development ebook

62

Historique de notification

ToastNotificationManager.History.Clear();

Il est possible de définir les applications pouvant envoyer des notifications dans les options de

Windows 10 (« Système » … « Notifications et actions » ou depuis le centre de notifications de la

barre de tâches)