You are on page 1of 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 : Contrle utilisateur Barre de titre avec marge adaptable selon le mode
daffichage 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 ( REMPLAANT DE SEARCHBOX )....................................................................................... 22
9. POPUP ........................................................................................................................................................ 23
10. EXTENDED SPASHSCREEN ........................................................................................................................... 23
11. VARIABLESIZEDWRAPGRID......................................................................................................................... 25
II. ACCENT ET THEME (DARK, LIGHT) .......................................................................................................... 27
DFINIR SON PROPRE THME .................................................................................................................................... 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
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)

Modles dapplication (Visual Studio 2015)

Modle Universel Windows 10 (UWP)

Modles dapplications Windows, Windows Phone et


Universel (avec projet Shared ) Windows 8

Avec Windows 10, le modle dapplication universelle permet de crer partir dun seul projet une
application pour le Windows Store (PC, tablettes et ordinateurs portables) et une application pour le
Windows Phone Store.

Modle Universel Windows 8 : Modle Universel Windows 10


3 projets (un projet Windows Store, (UWP) : 1 seul projet
un Windows Phone et un Shared )
3

I. Contrles
Liste des contrles et exemples

Voir lexemple XamlUIBasics

1. RelativePanel
Permet de positionner les lments les uns par rapport aux autres et de grer le repositionnement
des lments avec des AdaptiveTriggers.

Proprits de placement

Placement par rapport un lment

Above : Au-dessus de llment


Below : En-dessous de llment
LeftOf : A gauche de llment
RightOf : A droite de llment

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)
4

Placement par rapport au RelativePanel

AlignTopWithPanel : En haut ( gauche si pas prcis) du RelativePanel


AlignBottomWithPanel : En bas (et gauche si pas prcis) du RelativePanel
AlignLeftWithPanel : A gauche (et en haut si pas prcis) du RelativePanel
AlignRightWithPanel : A droite (et en haut si pas prcis) du RelativePanel

Plus pour centrer horizontalement et verticalement un lment 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 dfaut les lments sont placs


gauche en haut du RelativePanel

Rectangle vert plac droite


(AlignRightWithPanel) et en bas
(AlignBottomWithPanel)du RelativePanel
5

2. SplitView
a. SplitView de base et Adaptive Triggers
<SplitView>
<SplitView.Pane>
<!-- menu -->
</SplitView.Pane>
<SplitView.Content>
<!-- content-->
</SplitView.Content>
</SplitView>

Exemple

Les Adaptive Triggers


permettent de basculer le mode
daffichage du splitview selon la
taille de la page.

Plus de1024 CompactInline ,


panel ouvert

Le bouton hamburger permet en


plus douvrir, fermer le panel. Il est
plac en dehors du splitview pour ne
pas tre cach quand le panel est
ferm en mode Overlay

En-dessous 720, Mode


daffichage Overlay

De 720 1024,
CompactInline et
panel ferm

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
6

SplitView
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup> Adaptive Triggers, on
<VisualState x:Name="VisualStateMin0"> change le mode
<VisualState.StateTriggers> daffichage du splitview
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
selon la taille de la page
<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" Marge de 48 par rapport au top
IsPaneOpen="True" pour laisser la place au bouton
OpenPaneLength="320">
<SplitView.Pane> hamburger
<ListView Margin="0,48,0,0"
VerticalAlignment="Stretch"
ItemsSource="{x:Bind ViewModel.MenuItems}"
ItemTemplate="{StaticResource MenuItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"/>
</SplitView.Pane> On peut dfinir ce que lon veut en contenu .De
plus on peut omettre SplitView.Content
<SplitView.Content>
<Frame x:Name="mainFrame"></Frame>
</SplitView.Content> Bouton hamburger
</SplitView> plac en dernier

<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>
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 utilise 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("Vidos", Symbol.Video));
MenuItems.Add(new MenuItem("Musiques", Symbol.Audio));
}
}
8

b. Bouton Rechercher et AutoSuggestBox dans SplitView


AutoSuggestBox quand le Bouton quand le panel est
panel est ouvert ferm

<SplitView x:Name="splitView"
DisplayMode="CompactInline" On fait en sorte que chaque
IsPaneOpen="True"
OpenPaneLength="320"> lment fasse 48px de haut
<SplitView.Pane>
<StackPanel Margin="0,48,0,0"> On lie la visibilit de
<Grid Height="48">
lAutoSuggestBox et du bouton
<AutoSuggestBox x:Name="autoSuggestBox"
Margin="12,0" rechercher SplitView
PlaceholderText="Rechercher" IsPaneOpen et on utilise des
VerticalAlignment="Center" converters
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 douvrir le panel
private void searchButton_Click(object sender, RoutedEventArgs e)
{
splitView.IsPaneOpen = true;
}
Style du bouton
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" /> Bouton 48x48 avec
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalAlignment" Value="Center"/>
contenu centr
<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>
10

c. Page Header : Contrle utilisateur Barre de titre avec marge adaptable selon le
mode daffichage du SplitView
Cration dun UserControl PageHeader qui pourra tre gliss sur chaque page de contenu
(affiche dans la zone de contenu du SplitView) . On pourra personnaliser le contenu de cette barre
de titre pour chaque page, mais surtout permettra de grer la marge entre le titre et le bouton
hamburger du splitview. En effet, en mode daffichage Overlay, le titre (sil est align gauche) et le
bouton hamburger risqueraient de se chevaucher, il faut donc grer 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"
Hauteur de 48 pour tre align avec
Height="48"
d:DesignHeight="300" le bouton hamburger
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 contrle Jutilise un Messenger pour mabonner au changement
de DisplayMode du SplitView. SI le DisplayMode est
public sealed partial class PageHeader : UserControl
{
Overlay . Je mets une grosse marge (48px) pour que
public PageHeader() le bouton hamburger et le titre ne se chevauchent pas
{
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; Dependency Property
private const int overlayMargin = 48;
public UIElement HeaderContent permettant de personnaliser le
{ contenu du contrle selon
get { return (UIElement)GetValue(HeaderContentProperty); } chaque page
set { SetValue(HeaderContentProperty, value); }
}
public static readonly DependencyProperty HeaderContentProperty =
DependencyProperty.Register("HeaderContent", typeof(UIElement), typeof(PageHeader), new
PropertyMetadata(DependencyProperty.UnsetValue));
}
11

Voir lexemple XamlNavigation, qui nutilise pas tout fait la mme mthode, mais il ma
sembl observer quelques soucis

Dans le code-behind de MainPage


public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
ViewModel = new MainPageViewModel(); Abonnement au changement de taille de la page
SizeChanged += (s, e) =>
{ et en fin de navigation de la frame
CheckDisplayMode(); mainFrame .
};
mainFrame.Navigated += (s, e) => On vrifie le mode daffichage du SPlitView et
{ notifie par Messenger
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"/>
Utilisation du contrle, ajout
<RowDefinition/> dun simple TextBlock avec un
</Grid.RowDefinitions> titre align gauche
<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>
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
13

3. Navigation model
Documentation

Voir lexemple XamlNavigation

La navigation doit se faire dans deux sens. La barre de navigation doit tre synchronise
(navigation retour) avec les pages affiches.
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", "Vidos", Symbol.Video)) ;
MenuItems.Add(new MenuItem("MusicsPage", "Musiques", Symbol.Audio));

menusListView.ItemsSource = MenuItems;

mainFrame.Navigated += (s, e) =>


{ Navigation Retour
// affiche le bouton
if (mainFrame.CanGoBack)
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Visible;
}
else
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
AppViewBackButtonVisibility.Collapsed;
}
// slectionne 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;
}
}
}
};
// Gre la navigation retour
SystemNavigationManager.GetForCurrentView().BackRequested += (s, a) =>
{
if (mainFrame.CanGoBack)
{
mainFrame.GoBack();
a.Handled = true;
}
};
}
14

private void ListView_ItemClick(object sender, ItemClickEventArgs e)


{ Navigation Aller
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;
}
}

Ajout dun paramtre Id


public class MenuItem
{
permettant de retrouver la page
public string Id { get; set; } correspondante au menu
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 modifie en slection Single
<ListView x:Name="menusListView"
ItemTemplate="{StaticResource MenuItemTemplate}"
SelectionMode="Single"
IsItemClickEnabled="True"
ItemClick="ListView_ItemClick"/>
15

Navigation Aller

Navigation Retour , aprs avoir cliqu sur le bouton retour de la barre de titre, le menu est
slectionn et synchronis par rapport la page affiche.

Il faut garder en tte ici que cest un scnario simple. On pourrait par exemple imaginer crer un
paramtre spcifique la navigation avec des proprits permettant de mieux grer 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 cre un contrle HamburgerMenu .


16

4. BackButton

Voir lexemple BackButton

Affichage dun bouton dans la barre de titre (Desktop)

Dans App pour rootFrame (ou dans le code de la page pour une Frame particulire)
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;
}
};

// Gre la navigation retour


SystemNavigationManager.GetForCurrentView().BackRequested += (s, a) =>
{
if (rootFrame.CanGoBack)
{
rootFrame.GoBack();
a.Handled = true;
}
};
Navigation vers une autre page, le bouton retour apparait
} dans la barre de titre. La couleur correspond laccent
slectionn des paramtres de personnalisation de
Windows 10
Page daccueil
17

5. CommandBar, SymbolIcon,

Voir lexemple XamlCommanding et XamlUIBasics


On peut dfinir IsOpen pour
CommandBar afficher ou non les labels
<CommandBar>
<CommandBar.Content>
<TextBlock Text="Titre" /> Content gauche
</CommandBar.Content> de la barre
<AppBarButton Icon="Like" Label="Like" />
<!--etc.-->

<!-- Separator --> Commandes primaires


<AppBarSeparator/>
places droite de la barre
<!-- 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 --> Commandes secondaires


<CommandBar.SecondaryCommands>
places dans menu ouvert
<AppBarButton Icon="Setting" Label="Settings"/>
</CommandBar.SecondaryCommands> avec le bouton
</CommandBar>

Les commandes secondaires et labels apparaissent


quand on clique sur le bouton

Menu Flyout (apparait au-dessus ou en dessous la barre selon lespace disponible)


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 dfinir un symbole qui nest pas inclus dans SymbolIcon (on peut saider avec la
table des caractres
<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>
19

Top et bottom AppBar

(Peuvent tre ajoutes 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>

TopAppBar

BottomAppBar

On peut changer le mode daffichage :

- Compact (par dfaut)


- Minimal (naffiche plus que le bouton permettant dafficher les lments de la barre)

- Hidden la barre est compltement cache.


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 dune 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 contrles, en ajouter (un bouton like en plus par exemple)

Voir lexemple XamlCustomMediaTransportControls


21

7. Content Dialog
Menu Ajouter Nouvel lment Boite de dialogue de contenu

Par dfaut la boite occupe toute la


La boite de dialogue sadapte page mais on peut la
Desktop selon la taille de la page. Mobile redimensionner depuis le designer

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" Titre et boutons de la
PrimaryButtonText="Envoyer" boite de dialogue
SecondaryButtonText="Annuler"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick"> Contenu

<StackPanel>
<TextBox Header="Titre"></TextBox>
<TextBox TextWrapping="Wrap" AcceptsReturn="True" Header="Contenu" Height="100"></TextBox>
</StackPanel>
</ContentDialog>
Afficher la boite de dialogue et grer le rsultat
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)
{ }
}
22

8. AutoSuggestBox ( remplaant 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 Franaise"
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)
{ On change la liste des
var suggestions = GetSuggestions(sender.Text); suggestions selon le texte
sender.ItemsSource = suggestions; saisi
}
}
private void autoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs
args)
{ Dclench lorsque lutilisateur slectionne une suggestion de la liste propose
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;
}
23

private List<string> cities = new List<string>


{
"Lyon",
"Marseille",
"Nantes",
"Nice",
"Strasbourg",
"Toulouse",
"Paris"
};

9. Popup
Exemple popup chargement affiche pendant le chargement des donnes
<Popup IsOpen="{Binding IsBusy}" VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid Background="{ThemeResource ContentDialogBorderThemeBrush}" Height="100" Width="200">
<Grid.RenderTransform>
<TranslateTransform X="-100" Y="-50" /> Place correctement au centre de la page
</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 mthode 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;
}
Cration dune 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>
24

La taille de limage et les lments sont repositionns 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 lutilisateur, etc. par exemple
puis naviguer vers la page principale
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
WNavigationService.Default.Navigate(typeof(MainPage));
});
}
}
Chaque lment de base a une taille de
25
100x100. Ils sempilent horizontalement
(orientation) dans la limite de 4
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>
On peut changer la largeur,
hauteur et ainsi dfinir
combien de colonnes, lignes
sont occupes

On drive le GridView et redfinit


La mme chose pour un GridView PrepareContainerForItemOverride
public class VariableGridView : GridView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var variableItem = item as VariableSizedItem;
if (variableItem != null) On change le nombre de colonnes
{ et lignes en rapport llment
var gridViewItem = element as GridViewItem; VariableItem (modle dfini)
if (gridViewItem != null)
{
VariableSizedWrapGrid.SetColumnSpan(gridViewItem, variableItem.ColumnSpan);
VariableSizedWrapGrid.SetRowSpan(gridViewItem, variableItem.RowSpan);
}
}

base.PrepareContainerForItemOverride(element, item);
}

Le modle
public class VariableItem
{
public string Title { get; set; }
public SolidColorBrush BackgroundColor { get; set; }
public int Height { get; set; }
public int Width { get; set; } Proprits lies pour dfinir llment
public int ColumnSpan { get; set; } dans le GridView, il pourrait avoir
public int RowSpan { get; set; }
// etc. dautres proprits avec des donnes
} rcupres
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; }
}
27

II. Accent et Thme (Dark, Light)


<Rectangle Fill="{ThemeResource SystemAccentColor}" Grid.Row="1"></Rectangle>
On peut changer le thme ( Light ou Dark ) pour toute lapplication 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 lments ou contrles avec lattribut RequestedTheme , exemple
<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" RequestedTheme="Dark">
<!--etc-->
</RelativePanel>

Dfinir son propre thme


<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
Thme Dark, la couleur
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="BackgroundBrush" Color="Red" /> sera rouge
</ResourceDictionary>

<ResourceDictionary x:Key="Light"> Thme Light, la couleur


<SolidColorBrush x:Key="BackgroundBrush" Color="Gray" /> sera gris
</ResourceDictionary>

<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="BackgroundBrush" Color="{ThemeResource SystemColorWindowColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
</ResourceDictionary>
</Application.Resources>
28

On peut galement dfinir les thmes dans des dictionnaires de ressources et les rendre accessibles
lapplication
<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)
{
}
}
}
29

IV. DataTemplateSelector
Permet dafficher diffrents Templates dans une ListView ou un GridView pour une mme source de
donnes.
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) 3 proprits permettant de
{
return ChannelTemplate;
dfinir un Template retourner
} selon le type de llment reu
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
} Les 3 classes peuvent hriter dune
classe de base. Ainsi la source de
public class Video :ModelBase donnes sera une collection de
{ ModelBase
//
}
public class Channel :ModelBase
{
//
}
public class PlayList :ModelBase
{
//
}
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 dfinition de l ItemTemplateSelector
<GridView x:Name="itemsGridView"
ItemsSource="{x:Bind ViewModel.Results,Mode=OneWay}"
ItemTemplateSelector="{StaticResource TemplateSelector}">
</GridView>

Le GridView affiche un Template


diffrent selon que cest une
vido, une playlist ou une chaine
par exemple
31

Dernier lment Afficher plus pour ListView ou GridView


Sur ce mme 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 modles on a deux classes hritant 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.
}
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) =>
{ Quand lutilisateur clique sur
var selectedItem = item.ClickedItem; un lment du GridView soit
if(selectedItem is DataItem)
{ on le diriga vers la page dtails
// navigate to data soit on charge plus dlments.
} (Il faudra les insrer avant le
if(selectedItem is LastItem)
{ bouton)
// 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 proprit pour le binding (avec x :Bind)
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
ViewModel = new MainPageViewModel();
}
public MainPageViewModel ViewModel { get; set; }
}
33

En ressources de la page
<local:LastTemplateSelector x:Key="LastTemplateSelector"
NormalTemplate="{StaticResource ImageOverlayTemplate}"
LastTemplate="{StaticResource LastTemplate}"/>
On dfinit 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>
34

V. HeaderGroup Switch du nom de groupe au


dfilement

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;
}
}
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();
}
} Utilisation ici dune ListView
mais on peut faire la mme
chose avec un GridView
<ListView ItemsSource="{x:Bind cvs.View}"
ItemTemplate="{StaticResource DataItemTemplate}">
<ListView.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource HeaderTemplate}" />
</ListView.GroupStyle>
</ListView>
Templates et source de donnes groupe
<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>
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>
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>
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>
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>
40

VI. Adaptive UI
Une application UWP doit pouvoir sexcuter sur diffrents appareils. Il va falloir adapter la page
pour les diffrentes rsolutions et orientations (Portrait, paysage).

Penser en Pixel effectif (et non en pixel rel)

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 lments

Utilisation Visual States et AdaptiveTrigger pour dplacer des blocs ou lments, 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();
};
}
41

1. Adaptive Triggers

Voir exemple Responsive Techniques

1. Ouvrir le projet avec Blend


2. Ajouter des Etats Visuels

Panneau Etats : Ajouter un groupe dtats puis des tats visuels


Ajout de groupe dtats Ajout dtats viusels

Rglage des proprits (MinWindowHeight et


Ajouter un AdaptiveTrigger
MinWindowWidth pour un AdaptiveTrigger)

3. Changer les proprits des lments selon les tats AdaptiveTrigger ou Custom Trigger

Slectionner ltat dans le panneau Etats et llment dans le panneau Objets et chronologie ,
puis modifier les proprits de cet lment dans le panneau Proprits
42

Repositionnement avec RelativePanel


<RelativePanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<VisualStateManager.VisualStateGroups>
<VisualStateGroup>

<VisualState x:Name="VisualStateMin0"> Setters


<VisualState.Setters>
<Setter Target="textBlock.(RelativePanel.Below)" Value="image"/>
De 0 548 </VisualState.Setters>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="1"/> StateTriggers
</VisualState.StateTriggers>
</VisualState>

<VisualState x:Name="VisualStateMin548">
<VisualState.Setters>
<Setter Target="textBlock.(RelativePanel.RightOf)" Value="image"/>
</VisualState.Setters>
> 548 <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>

> 548 on place le texte


droite de limage

De 0 548 on place le texte


en-dessous limage
43

2. Master details
> 548

Page divise avec gauche la liste, droite le dtail

De 0 548

La liste occupe toute la largeur de la page (ColumnSpan=2), la partie dtail est cache (Collapsed) et
lorsque lon clique sur un lment de la liste on navigue vers une page dtails

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
44

<Page >
<Page.Transitions> On peut ajouter une transition
<TransitionCollection>
<NavigationThemeTransition /> page pour effet de retour
</TransitionCollection>
</Page.Transitions>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">


<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
Visual States
<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" La liste gauche de la grille


ItemsSource="{x:Bind People}"
IsItemClickEnabled="True"
ItemClick="peopleList_ItemClick" /> Un contrle utilisateur affichant le dtail droite

<Controls:PersonDetailsControl x:Name="personDetailsControl" Background="#ccc"


DataContext="{Binding SelectedItem, ElementName=peopleList}"
Grid.Column="1"/>
</Grid>
Navigation vers une page Dtails si la partie dtails est cache (>548)
private void ListView_ItemClick(object sender, ItemClickEventArgs e)
{
if (personDetailsControl.Visibility == Visibility.Collapsed)
{
Frame.Navigate(typeof(PersonDetailsPage), e.ClickedItem);
}
}
45

La page Dtails avec un bouton retour un titre et le contrle 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 lexemple XamlStateTriggers


using Windows.System.Profile;
using Windows.UI.Xaml;

namespace UWPAdaptiveTriggerDemo.CustomTriggers Hrite de StateTriggerBase


{
public class DeviceFamilyTrigger : StateTriggerBase
{
private string _deviceFamily; Proprit(s) accessible(s) servant pour
public string DeviceFamily dterminer quand ltat est activ
{
get { return _deviceFamily; }
set
{
var qualifiers = ResourceContext.GetForCurrentView().QualifierValues;
_deviceFamily = value;
SetActive(_deviceFamily == qualifiers["DeviceFamily"]); On appelle la mthode SetActive
// ou
//var currentDeviceFamily = AnalyticsInfo.VersionInfo.DeviceFamily;
//_deviceFamily = value;
//SetActive(_deviceFamily == currentDeviceFamily); }
}
}
}

Avec Blend, pour un tat visuel

Slectionner Autre type


46

Et le Custom State Trigger

On dfinit ensuite les valeurs qui


rendront actif ltat visuel

On change ensuite les proprits des lments de la page selon les tats visuels.
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>
48

4. DeviceFamily
On peut crer une version de page selon les devices

Vue correspondante
pour Mobile

Vue par dfaut

Si on navigue vers la page Scenario4 , automatiquement la vue pour Mobile sera affiche 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 : ractiver les animations, transitions Windows


Rgler les effets visuels de Windows. Permet de ractiver les animations, transitions au cas o elles
auraient t dsactives pour amliorer les performances par exemple.
49

VII. x :Bind Compiled Binding


Voir exemple XamlBind

Les +

- Meilleures performances que le binding classique . Trs performant pour afficher des
listes.
- Va chercher automatiquement les proprits dans le code-behind de la page sans dfinir de
DataContext. Pour lutilisation de ViewModels on dfinit donc directement une proprit
dans le code-behind.
- Le mode par dfaut de binding est OneTime . Il faut donc dfinir un mode OneWay ou
TwoWay si ce nest pas suffisant.
- On peut utiliser x :Bind pour binder des vnements, permet dviter lutilisation de
RelayCommand ou de behavior pour des scnarios simples.

Les -

- Problme avec les commandes dans les DataTemplates de fichier de ressources (Besoin
daller chercher le DataContext du parent)
- Problme avec SelectedItem (renvoyant un objet) avec ListView / GridView .., besoin de faire
des convertisseurs ?
- Problme avec les styles
- Les attributs ElementName, RelativeSource, Source, UpdateSourceTrigger ne sont pas pris
en charge par x :Bind
- Solution : il faudra parfois mlanger le binding classique et binding avec x :Bind . On rgle
alors le DataContext sur le mme ViewModel dfini en proprit dans le code-behind de la
page.

1. Binding de collection
On dfinit une proprit dans le code-behind de la page sans dfinir de DataContext
public sealed partial class Scenario1 : Page
{
public Scenario1()
{
this.InitializeComponent();
People = new ObservableCollection<Person>
{
new Person { Name ="Marie Bellin"},
new Person { Name ="Jrme Romagny"}
};
}
public ObservableCollection<Person> People { get; set; }
}
(Le modle utilis)
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
50
Si aucun DataTemplate nest dfini cest la mthode
2. Binding dans la page ToString des lments qui est appele

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

2. Avec DataTemplate Ajouter un namespace et


On dfinit le DataTemplate en ressources de la page dfinir le DataType
<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 Ajout dun nom de classe
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> Exemple de template
</DataTemplate>
</ResourceDictionary>

2. Ajout dune classe (partielle) du mme nom que le dictionnaire de ressources


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

Utilisation du DataTemplate du dictionnaire de resources


<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<resources:Templates /> Rfrencer le dictionnaire en
</ResourceDictionary.MergedDictionaries> ressources de la page ou pour
</ResourceDictionary>
</Application.Resources>
toute lapplication dans App
51

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


ItemTemplate="{StaticResource personItemTemplateFromResourceDictionary}" />

4. RelativeSource et ElementName lier au nom de llment


<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 proprit du ViewModel dans le


code-behind
public sealed partial class MainPage : Page
{
public MainPage()
{
Parfois il faudra dfinir le
this.InitializeComponent();
ViewModel = new MyViewModel(); DataContext pour mlanger les deux
DataContext = ViewModel; formes de binding
}
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; }
}
52

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

public class MyViewModel


{
public string Message { get; set; }
public MyViewModel()
{
Message = "Bonjour!";
}
}
6. Binding Events
Permet dviter lutilisation de RelayCommand (ICommand) ou de behavior
EventToCommand pour des scnarios simples, de dplacer les vnements du code-
behind de la page vers le ViewModel par exemple.
Naccepte pas les paramtres personnels , pas de support de CanExecute

Exemple
public class MyViewModel
{ Les 3 signatures
public void DoWork1()
{ acceptes

}
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 paramtre ... 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}"/>
53

7. Defer loading La grille nest affiche qu


Dans la page lappel de FindName

<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 lillusion que lapplication na pas t suspendue quand celle-ci est rsume.

Launch ( OnLaunched de App ).


- PreviousExecutionState : NotRunning, Running,Suspended, Terminated, ClosedByUser. Si
lapplication est ferme par lutilisateur ( ClosedByUser ) ne pas restaurer.
- ActivationKind : Launch, File, Protocol, Cortana, Secondary tile, toast, search contract,etc.
Suspend : Les applications Desktop sont suspendues quand elles sont minimises dans la barre
de tches.
- Sauvegarder les tats de la page et les donnes (Local, Roaming,)
- App : Sauvegarder lhistorique de navigation
Resume :
- App : Restaurer lhistorique de navigation, retourner sur la page avant la suspension
- Restaurer les tats de la page (champs) et les donnes (Local, Roaming )

Note : Les applications UWP nincluent pas SuspensionManager et NavigationHelper .


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 donnes
Sauver les tats de la page courante la suspension ( code-behind de la page )
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
vm.SaveData();
}

ViewModel Exemple sauvegarde de deux


valeurs de champs
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();
}
}
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");
}
}
56

IX. Tiles, toasts


Documentation

Voir exemple Notifications

Tile
On dfinit les Assets toujours dans le manifeste de lapplication, onglet Ressources visuelles

- Petit : 71x71 ( gnr automatiquement si lAsset nest pas prsent)


- Moyen : 150x150 (Square150x150Logo.png)
- Large : 310x150 (Wide310x150Logo.png)
- Grand : 310x310 (Wide310x310Logo.png)

Vignette de lapplication : Chercher lapplication depuis le champ recherche de Windows 10 puis


Epingler lcran de dmarrage

71x71 150x150 310x150

Seulement pour desktop

310x310
57

Note : si on dfinit la couleur darrire-plan des vignettes sur transparent , cest alors la couleur
daccent de Windows qui est appliqu

Vignette secondaire : ajoute par code. La vignette est dsormais ajoute directement sans boite de
dialogue (comme ctait 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 "; Nom affich, arguments, uri de la
private async Task<bool> PinSecondaryTile(string tileId) tile 150x150 et taille dsire de la
{ vignette
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);

// dtails
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;
}
58 Animation cube 3D

Notification de vignette Dfilement

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 (diffr) Notification de la vignette principale. On peut galement
notifier les vignettes secondaires en passant le tile id
// 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
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

Image en arrire-plan,
texte par-dessus avec styles Image inline

branding :
nom et logo
(44x44)

private void OnAdaptiveTile(object sender, RoutedEventArgs e)


{
string image = "ms-appx:///Assets/image_1.jpg";
string title = "Titre!";
string message = "Nouveau message!"; Placement de limage en arrire-plan
string xml = string.Format(@"<tile> (background) , on pourrait la placer en
<visual>
Vignette 71x71 <binding template=""TileSmall"">
ligne avec un alignement
<image src=""{0}"" placement=""background""></image>
</binding>
Vignette 150x150 <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>
On dfinit le style du texte
</binding>
Vignette 310x150 <binding template=""TileWide""> (caption, etc.) . hint-
<image src=""{0}"" placement=""background""></image> wrap place devant
<text hint-style=""title"" hint-wrap=""true"">{1}</text> limage darrire-plan
<text hint-style=""subSubtle"" hint-wrap=""true"">{2}</text>
</binding>
Vignette 310x310 <binding template=""TileLarge"" branding=""nameAndLogo""> Affichage du nom
<group> et logo
<subgroup>
<text hint-style=""title"">{1}</text>
<text hint-style=""subSubtle"">{2}</text>
</subgroup> Groupe et image
</group> en ligne
<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);

}
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);
}

Toast

Centre de
Adaptive toast notifications

Image remplaant le Image inline


logo
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);
}

Reminder, alarm ou
Scnarios
incomingCall
<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);
}
62

Historique de notification
ToastNotificationManager.History.Clear();

Il est possible de dfinir les applications pouvant envoyer des notifications dans les options de
Windows 10 ( Systme Notifications et actions ou depuis le centre de notifications de la
barre de tches)

You might also like