Windows Phone 8 Development

25. November 2012 14:11 by Renaud in Windows Phone  //  Tags:   //   Comments (0)

Voici mes quelques notes prises lors de la session Windows Phone 8 Application Development donnée par Maarten Struys (@mstruys) lors du Windows App Day. On y évoque quelques nouveautés liées au développement sous Windows Phone 8.

Tuiles et templates

Avec Windows Phone 8, de nouvelles tuiles sont apparues. Pour faire simple, on a désormais le choix entre :

  • Flip : Les tuiles que l'on connait déjà depuis Windows Phone 7. Avec une face avant et une face arrière et qui se retourne sur elle-même.
  • Iconic : Une nouvelle tuile qui respecte le design Windows Phone. Elle permet de mettre l'accent sur un compteur.
  • Cycle : Cette dernière tuile permet de boucler parmi 9 images différentes.

Allez lire la doc détaillée pour voir des exemples de bonnes et mauvaises utilisations des différents types de tuiles.

Lock screen

Les applications peuvent maintenant s'enregistrer pour enrichir l'écran de verrouillage. Elles peuvent modifier le background lui-même, comme le fait par exemple l'application Bing qui propose chaque jour un nouveau background, ou afficher des notifications. Il y a désormais deux types de notifications :

  • Les statuts détaillés : affiche le texte de la tuile principale de l'application.
  • Les statuts rapides : affiche une icône plus un compteur si celui-ci est implémenté dans la tuile principale de l'application. Ce deuxième type de notification rappelle les badges disponibles sur Windows 8.

Shared Windows Core

En effet, Windows Phone 8 se rapproche plus de Windows 8 que de Windows Phone 7 dans le sens où les deux OS partagent quelques composants bas niveaux. L'ensemble des librairies Windows Phone 8 (appelées WinPRT dans les slides, pour Windows Phone RunTime) consiste en fait en un subset de WinRT auquel ont été ajoutés quelques composants spécifiques au téléphone. Le tout est donc écrit à la base en C++, avec des projections en C#/VB.NET, aussi à la manière de WinRT. Par contre il n'y a pas pour le moment de projections HTML5/JavaScript. Il y a bien un template d'application HTML/JS disponible avec Visual Studio 2012, mais il s'agit d'une application écrite en code managée et qui embarque un WebBrowser et du contenu HTML/JS. Mais cela ne permet pas d'appeler des librairies natives en JavaScript comme on peut le faire pour Windows 8. Si l'on compte développer une application à la fois sur Windows Phone 8 et Windows 8, il serait donc conseillé, d'un point de vue API, de commencer par l'application phone, et la migrer ensuite vers Windows 8 puisque la quasi-totalité du code pourra être réutilisé. Par contre, d'un point de vue UX & Design, il faut clairement faire la différence entre les deux OS. L'interface devra probablement être entièrement repensée. Parmi les APIs spécifiques à Windows Phone 8, on retrouve par exemple ce qui concerne la synthèse et la reconnaissance vocale. Cela fonctionne de la même manière que la reconnaissance vocale avec le SDK Kinect. Il n'est malheureusement pas possible pour le moment d'utiliser la reconnaissance vocale sans donner des "suggestions", comme par exemple ce que permet de faire le téléphone pour rédiger des SMS.

Les outils : VS 2012 + Blend

L'émulateur Windows Phone a bien été amélioré. Il permet de tester quasiment toutes les fonctionnalités du téléphone.

  • Simuler le type de connexion réseau (4G, 3G, WiFi, ...) et la force du signal (fort, faible, ...)
  • Jouer avec l'accéléromètre
  • Modifier la géolocalisation
  • Tester les différentes résolutions d'écran

Malheureusement, ça ne passera plus auprès de votre chef si vous demandez un téléphone de chaque résolution, juste pour pouvoir tester votre app. Il vous dira simplement d'utiliser l'émulateur. Mais comme Maarten le précisait, il reste nécessaire de tester son application sur un vrai téléphone pour au moins deux raisons :

  • Pouvoir tester avec des performances réelles (l'émulateur ne peut pas reproduire les performances du téléphone)
  • Apprécier la véritable expérience utilisateur. Voir comment vos interfaces réagissent au touch.

Quoi d'autre ?

Voilà en bref le contenu de la session de Maarten Struys. C'était une bonne introduction, même si évidemment ça ne couvre qu'une toute petite partie des nouveautés de Windows Phone 8. J'imagine qu'on peut s'attendre à en voir davantage au TechDays 2013 ! En attendant, on organise des trainings Discovery : Windows Phone 8 au MIC Belgique le 22 janvier 2013 et le 05 février 2013 pour apprendre les bases de la programmation Windows Phone ! :)

Retour sur le Windows App Day 2012

25. November 2012 14:11 by Renaud in   //  Tags:   //   Comments (0)

Petit retour sur le Windows App Day, cette journée organisée par Microsoft et destinées aux développeurs et graphistes initiés ou non. En effet, il s'agissait d'une série de sessions de 1h chacune, réparties sur deux tracks : Developer et UX & Designer. Pour l'ouverture, nous avons pu voir tour à tour Luc Van de Velde (Director Developer & Platform group) et Katrien De Graeve, David Hernie et Nick Trogh (tous trois Technical Evangelist) parler de la direction prise par Microsoft en nous présentant quelques success stories et témoignages de développeurs. Le ton est donné : on va parler Windows 8, Windows Phone 8 et Windows Azure ! :) Mais juste après un petit break...

Pour les sessions suivantes, l'audience se sépare en deux. On a eu droit à quelques sessions intéressantes dont je vais vous faire le résumé. Je n'ai suivi que la partie Developer, donc je ne pourrai malheureusement pas parler du reste. Mais d'après les quelques échos que j'ai eu sur le moment, les sessions UX & Design valaient vraiment la peine d'être vues ! Windows Phone 8 Development by Maarten Struys

> Lire l'article Windows Phone 8 Development

Windows Azure Mobile Services, Connecting Cross Platform Devices by Kristof Rennen

> Lire l'article Windows Azure Mobile Services : intro

From Slider to Gauge: building WinRT custom controls by Diederik Krols

Cette session montrait différentes manières de créer un contrôle custom, soit à partir d'un contrôle existant, soit from scratch.

What it takes to make Mine for Facebook : learn and apply to your next Windows Store app by Kevin Dockx

Cette dernière partie était une série de conseils du développeur de l'application Mine for Facebook (que vous devriez d'ailleurs essayer ;) ). C'était un excellent retour d'expérience pour terminer cette journée. Kevin nous suggérait entre autres de trouver un ami graphiste ("on ne laisse pas les graphistes développer, et on ne devrait sans doute pas laisser les développeurs faire du design"). Il nous a ainsi montré l'évolution de son application, depuis son premier essai jusqu'au rendu final, en expliquant les apports du graphiste au projet.

Il est ensuite rentré dans des conseils plus techniques, comme par exemple :

  • N'utiliser que des librairies tierces qui ont fait leurs preuves. Vous n'avez pas envie de voir votre projet "cassé" à cause d'une librairie qui n'est plus mise à jour.
  • Lorsque l'on travaille en asynchrone, penser à annuler les tâches toujours en cours mais plus nécessaires grâce à des CancellationToken.
  • Consumer/Producer pattern et BlockingCollection pour pré-fetcher des données et apporter une meilleure expérience utilisateur. La perception est plus forte que la réalité.  Et peu importe combien votre application est performante, ce qui compte c'est l'impression finale qu'aura l'utilisateur !
  • Utiliser un outil d'analytics pour loguer les erreurs mais aussi analyser le comportement des utilisateurs. Suggestion : MarkedUp.

En résumé, la journée a été bonne et enrichissante. À refaire sans hésiter :)

La Journée Agile à Namur, le 28/11/2012

22. October 2012 13:10 by Renaud in   //  Tags:   //   Comments (0)

Cet été, nous avons eu la chance, à plusieurs reprises dans le cadre des Afterwork Parties, d'accueillir au MIC quelques membres fondateurs de DotNetHub. La spécialité de ce users group belge, en dehors d'être l'une des plus importantes communautés .NET francophones, est qu'il organise de nombreux évènements mêlant à la fois technologies Microsoft et méthodes agiles. Le 28 novembre prochain, l'association DotNetHub / AgileHub a décidé de mettre en place un grand évènement agile francophone, sobrement intitulé "Journée Agile". Le programme complet est disponible sur le site web de l'évènement ! Sont prévues au total : 18 sessions par une quinzaine de speakers. Les sujets traités sont assez variés. Cela va de l'atelier d'introduction aux principes "lean", à la conférence technique sur l'ALM et Team Foundation Server, en passant par des retours d'expériences. (http://www.journeeagile.be). Si cette journée vous tente, sachez que les inscriptions sont d'ores et déjà ouvertes. Vous avez jusqu'au 26 octobre pour profiter du prix Early Birds! Nous avons également un nombre limité de codes promos à vous offrir ! Pour en profiter lors de votre inscription, il suffit de nous contacter sur Twitter en mentionnant le @micbelgique ou @dumontrenaud. Ex: "Hello @micbelgique, est-ce qu'il vous reste des codes promo pour la #journeeagile de #dotnethub ?" Rendez-vous donc le 28 novembre, à Namur, dans les bâtiments de l'Henallux implantation IESN pour une journée Agile et Microsoft :)

L‘agenda du développeur enthousiaste

17. October 2012 15:10 by Renaud in   //  Tags:   //   Comments (0)

Si vous êtes allé sur le net récemment, vous aurez remarqué que cette fin d'année va être particulièrement chargée en évènements :) et honnêtement ce n'est pas pour me déplaire. On a droit à des hackathons, des grosses annonces Microsoft, des trainings et autres events organisés par la communauté. J'vais donc essayer ici de vous proposer un petit résumé des dates à retenir pour les développeurs du monde Microsoft !

19 Oct.
Startup Weekend Mons
2012

Le Startup Weekend vient s'installer à Mons, et plus exactement à la HELHa (Haute École Louvain en Hainaut, où j'ai d'ailleurs fais mes études, soit dit en passant :) ). Le concept : 54 heures pour créer une startup en équipe, ou du moins un concept qui tienne la route, et que l'on puisse défendre à la fin du weekend devant un jury. J'y participerai avec une bande de développeurs .NET qui ont profité des inscriptions offertes par le MIC !

Inscription

7 Nov.
Training Windows 8 : Découverte du dev en C#/XAML
2012

Vous avez envie de participer à tous les évènements qui suivent mais vous n'avez pas encore d'expérience en développement Windows 8 ? Venez une après-midi au MIC et vous découvrirez les bases du développement d'une application Windows Store. C'est gratuit et c'est moi qui donne la formation. Il vous suffit de venir avec votre laptop équipé de Windows 8 et d'une version de Visual Studio 2012 pour Windows 8. L'idée de ce training, c'est de vous permettre de vous lancer rapidement en apprenant les concepts fondamentaux :) Par la suite, je vous proposerai des sessions plus avancées. D'ailleurs n'hésitez pas à me faire savoir si un sujet vous intéresse particulièrement. Je pourrais organiser une session là-dessus !

Inscription

9 Nov.
Startup Weekend Liège
2012

Même principe que le Startup Weekend Mons, mais à la Cité Ardente cette fois ! Il reste encore quelques semaines pour vous inscrire. Si vous êtes développeurs .NET, et que vous êtes intéressés par une invitation au Startup Weekend offerte par le MIC, n'hésitez pas à me contacter (sur twitter par exemple : @DumontRenaud ;) )

Inscription

10 Nov.
WOWZAPP 2012 In Belgium
2012

Le WOWZAPP 2012, c'est un hackathon international organisé par Microsoft. Bien que ce soit publié sur la partie student du site de Microsoft, c'est évènement est évidemment ouvert à tous les développeurs intéressés ! :) Malheureusement, cela se passe au même moment que le Startup Weekend Mons ! Il faudra donc faire un choix... Petit rappel pour les étudiants : les comptes DreamSpark donnent droit à tous les outils de développements gratuitement, et en participant à cet événement vous pouvez également gagner un abonnement de 6 mois à Windows Azure ! Double bonne raison pour y aller :)

Inscription

17 Nov.
When AZUG meets MADN (Coding BBQ)
2012

Ok, sérieusement : Qui ne rêve pas de faire un barbecue à cette période de l'année ? Et si en plus, on s'en sert d'excuse pour organiser une petite matinée de code ? Ce ce qu'ont décidé de faire les user groups AZUG et MADN, en organisant un évènement mélangeant Cloud, développement Mobile, et saucisses grillées ! Le planning de la journée suggère que la matinée sera dédiée au code, avec une démo des projets aux environs de 13h. Le reste de la journée étant réservée au barbecue ! :)

Inscription

23 Nov.
Windows App Day
2012

Cook Your App !Le Windows App Day s'adresse aussi bien aux développeurs qu'aux graphistes. Il s'agit d'une journée organisée par Microsoft et pour laquelle on nous promet des speakers internationaux :) A noter que l'une des sessions est consacrée à Windows Phone 8 ! D'ici là évidemment, le SDK aura été lâché dans la nature... :)

Inscription

28 Nov.
Journée Agile 2012 - Namur
2012

LA journée dédiée à l'agilité en Belgique et en français, c'est celle-là ! Organisée par l'association DotNetHub / AgileHub, la Journée Agile 2012 propose un programme de 18 sessions sur les méthodes agiles, scrum, la gestion de projet, l'ALM et TFS 2012. Le MIC Belgique a quelques codes promos à offrir pour l'inscription à cet événement. Plus d'infos dans ce billet : http://blog.mic-belgique.be/articles/la-journee-agile-a-namur-le-28-11-2012/

Inscription

MSDN Events

Ensuite, à côté de tout ça, il y a encore plein de formations organisées par Microsoft et les membres des communautés belges !

Plus d'infos

Encore plus d'events :)

Non non, ce n'est pas fini ! Mais je ne peux pas encore tout vous dire... D'ici la fin de l'année, il y aura d'autres nouvelles dates à ne pas manquer, et je vous en reparlerai ici dès que tout sera fixé ;) Et enfin, si vous participez à un évènement dans les semaines à venir, et qu'il ne se trouve pas dans cette liste, n'hésitez pas à nous en faire part dans les commentaires ! :) Ca intéressera sûrement quelqu'un.

[Windows 8] C# / XAML : Drag & Drop (fr)

1. October 2012 15:12 by Renaud in Windows 8  //  Tags: , ,   //   Comments (6)
Cet article présente une manière d'utiliser le Drag and drop entre deux listes différentes. Si vous voulez simplement permettre de réarranger les items au sein d'une même liste, il vous suffit de mettre les propriétés CanReorderItems et AllowDrop à True sur votre GridViewSample : http://sdrv.ms/U8tPem. Lisez ce commentaire.
À la recherche d'une idée d'application Windows 8 à développer, je voulais quelque chose qui me permette de tester le Drag & Drop (en partie parce que j'avais été intrigué en voyant les propriétés CanDragItems et DragItemsStarting sur les listes en WinRT). Et comme j'en avais assez de faire des applications classées 16+, pour être sûr de passer la certif, je voulais également faire une application sans équivoque qui soit notée 3+ ! Une app pour les tout-petits :) Du coup j'ai développé "Les animaux de la ferme", une sorte de puzzle en bois dédiée à l'apprentissage: disponible sur le Windows Store.

Le Drag & Drop sur WinRT

Indiquer si un event doit être déclenché ou pas

Il est très simple de déplacer des items provenant d'une liste. On va voir avec quelques lignes de code comment démarrer le drag, garder une trace des éléments manipulés, et finalement faire quelque chose de ces informations au moment du drop, si nécessaire. Si vous n'avez pas remarqué, il y'a généralement dans WinRT la possibilité de dire si un event doit être utilisé ou pas. On retrouve par exemple les propriétés suivantes : IsItemClickEnabled, IsRightTapEnabled, ... Ce qui va réellement nous faciliter la vie, c'est la propriété CanDragItems couplée à l'event DragItemsStarting. Tout cela étant hérité de la classe ListViewBase.

This post explains a way to use Drag & drop across two different lists. If you're looking for rearranging items within the same list, you just have to set the properties CanReorderItems and AllowDrop to True on your GridViewSample : http://sdrv.ms/U8tPem. Read this comment.
While looking for a new Windows 8 app idea, I wanted to make something using drag & drop, just for fun. I also wanted something that could be rated 3+ on the Store. An app for kids. And I suddenly remembered my childhood and that kind of puzzles with big pieces of wood. That's how I built "Les animaux de la ferme" (Farm's animals), which is available on the Windows Store for free.

Ce qu'on va déplacer

Pour faire simple, on va utiliser deux GridView. Cela marcherait tout aussi bien avec des ListView, mais peu importe. On va simplement afficher deux collections, et faire passer les items de l'une à l'autre grâce au drag and drop. Dans une page basique, je vais donc ajouter ces deux GridViews, plutôt similaires :

<GridView   ItemTemplate="{StaticResource ItemTemplate1}"
            ItemsSource="{Binding FirstCollection}"
            AllowDrop="True" CanDragItems="True" 
            DragItemsStarting="GridViewDragItemsStarting"
            Drop="GridViewDrop" Margin="10">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

<GridView   ItemTemplate="{StaticResource ItemTemplate2}"
            ItemsSource="{Binding SecondCollection}"
            AllowDrop="True" CanDragItems="True" 
            DragItemsStarting="GridViewDragItemsStarting"
            Drop="GridViewDrop" Margin="10">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

Les seules différences notables entre ces deux grilles sont les templates utilisés (ItemTemplate1 et ItemTemplate2), et les collections bindées (FirstCollection et SecondCollection). Notez ici les propriétés utilisées:

  • CanDragItems / DragItemStarting
  • AllowDrop / Drop
On va concrètement activer la possibilité de déplacer des items tout en écoutant l'événement indiquant le commencement d'un déplacement. Et on va également activer le drop, donc le fait de pouvoir lâcher un item sur ce contrôle, et écouter l'événement correspondant.

Première collection visible, deuxième collection encore vide.

Gestion du drag et du drop !

On va maintenant implémenter les eventhandlers pour DragItemsStarted et Drop. Dans ce cas-ci, on va faire simple et faire ça de manière assez générique pour pouvoir utiliser les mêmes eventhandlers sur chaque liste en permettant de déplacer les items de l'une à l'autre.

Lors du début du déplacement d'un élément, on se retrouve avec un DragItemsStartingEventArgs avec quelques propriétés intéressantes:

  • Items, une collection contenant les éléments déplacés.
  • Data, qui n'est autre qu'un DataPackage, le même que celui utilisé par le charm Share.
        private void GridViewDragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            var item = e.Items.FirstOrDefault();
            if (item == null)
                return;

            e.Data.Properties.Add("item", item);
            e.Data.Properties.Add("gridSource", sender);
        }

On récupère ici le premier élément déplacé, et on va stocker quelques infos dans notre DataPackage, qui va nous service de contexte durant toute l'opération. On va ainsi garder une trace de l'item déplacé, ainsi que du grid duquel il provient !

Ensuite vient le moment de lâcher l'élément. Et si l'utilisateur le lâche par-dessus l'un des grids, l'eventhandler suivant sera appelé :

private void GridViewDrop(object sender, DragEventArgs e)
{
    object gridSource;
    e.Data.Properties.TryGetValue("gridSource", out gridSource);

    if (gridSource == sender)
        return;

    object sourceItem;
    e.Data.Properties.TryGetValue("item", out sourceItem);
    if (sourceItem == null)
        return;

    _mainViewModel.SwitchItem((DemoItem)sourceItem);
}

Dans ce code, on va comparer le grid de source, et le grid cible. Si les deux sont les mêmes, on ne fait rien, et l'élément reste dans sa collection. Dans le cas contraire, on va récupérer l'élément qui a été déplacé depuis notre DataPackage, et on va le changer de collection. Ici, je fais appel à une méthode de mon viewmodel qui fait passer les éléments d'une liste à l'autre. Et c'est tout ! Rien que ça. Il n'en faut pas plus pour faire du drag&drop entre deux listes. Les animations sont présentes automatiquement, et le tout forme un ensemble assez sympathique. 

Conclusion

Cela n'a jamais été aussi simple ! N'hésitez pas à télécharger les sources si quelque chose ne vous semble pas clair :

 

 

[Windows 8] C# / XAML : Drag & Drop (English)

1. October 2012 11:10 by Renaud in Windows 8  //  Tags: , , ,   //   Comments (19)

 It's really easy to move items from a list in a Windows 8 app. We'll see in this blog how we can start dragging items in a few lines of code, keep track of the item being dragged, and finally how to handle the drop of that item. You probably noticed that in the XAML now (something that didn't exist in Silverlight for Windows Phone 7), you can say, for some events, whether you want them enabled or not. For example, on a GridView, you'll find properties such as IsItemClickEnabled, IsRightTapEnabled, ... But there is also one property that will be really useful for now. It's called CanDragItems, and we will use it in addition to the DragItemsStarting event. Those properties are  inherited from the ListViewBase class.

 

What are we going to drag ?

To make it as simple as possible, we'll use two GridView. We could make it also with ListView as it also inherits from ListViewBase. We will simply display two collections, and make it possible for the user to move items from a list to the other using drag and drop. In a blank Page, I add those two GirdViews, that are quite similar :

<GridView   ItemTemplate="{StaticResource ItemTemplate1}"
            ItemsSource="{Binding FirstCollection}"
            AllowDrop="True" CanDragItems="True" 
            DragItemsStarting="GridViewDragItemsStarting"
            Drop="GridViewDrop" Margin="10">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

<GridView   ItemTemplate="{StaticResource ItemTemplate2}"
            ItemsSource="{Binding SecondCollection}"
            AllowDrop="True" CanDragItems="True" 
            DragItemsStarting="GridViewDragItemsStarting"
            Drop="GridViewDrop" Margin="10">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
</GridView>

The only differences are the templates used (ItemTemplate1 and ItemTemplate2), and the bound collections (FirstCollection and SecondCollection). Notice alose those properties :

  • CanDragItems / DragItemStarting
  • AllowDrop / Drop
We explicitly enable the possibility to move items, while listening to the event fired the user actually starts moving an object. And then, we also activate the ability to "drop", and we listen to the corresponding event to know when an item is dropped on one of the GridViews.
 

Handle the drag and the drop !

Now that the UI can display our collections, we will implement the eventhandlers for DragItemsStarted and Drop. In this case, we will make it simple and we will use the same handlers for both grid so that the user can move items from one grid to the other and vice versa.

When you start moving an item, you end up with a DragItemsStartingEventArgs, which has some interesting properties :

  • Items, a collection containing the dragged items.
  • Data, which is nothing less than a DataPackage object. The same as the one used by the Share charm for data transfer between apps.
        private void GridViewDragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            var item = e.Items.FirstOrDefault();
            if (item == null)
                return;

            e.Data.Properties.Add("item", item);
            e.Data.Properties.Add("gridSource", sender);
        }

Here we retrieve the first dragged item, if any, and we store it in the DataPackage, which will act as a context during the whole operation. We also keep track of the "sender" grid, to know where that item comes from.

Then comes the moment you drop the item. And if the user drop it on one of the grid, the following event handler will be executed :

private void GridViewDrop(object sender, DragEventArgs e)
{
    object gridSource;
    e.Data.Properties.TryGetValue("gridSource", out gridSource);

    if (gridSource == sender)
        return;

    object sourceItem;
    e.Data.Properties.TryGetValue("item", out sourceItem);
    if (sourceItem == null)
        return;

    _mainViewModel.SwitchItem((DemoItem)sourceItem);
}

In that piece of code, we compare the source grid with the target grid. If they are the same, then we don't have nothing to do, the item will simply stays where it is. Otherwise, we will get back the item that was dragged, thanks to the DataPackage, and we will put it in the other collection (that's what does the SwitchItem method). And that's all. You don't need nothing more to use drag & drop between two collections. Animations are automatically added, and the result is quite nice ! 

Conclusion

It has never been that easy to use drag and drop ! Don't hesitate to download the sample project if something seems fluzzy :

 

 

[Windows 8 / XAML] Modifier le style d'un FlipView

22. September 2012 19:09 by Renaud in Windows 8  //  Tags: , , ,   //   Comments (7)

Lors d'un Excellence Lab passé récemment, on m'a conseillé de modifier légèrement mon FlipView de sorte que les flèches de navigation vers les items suivants ou précédents ne se superposent pas au contenu. Il suffisait donc de légèrement ré-hausser les flèches pour régler ce problème. Un collègue m'a également posé une question pour savoir comment modifier la couleur de ces flèches, pour répondre à la demande d'un client. J'imagine que la personne a cherché après une propriété "NavigationTemplate", ou quelque chose du genre, un peu comme on retrouve un ItemTemplate En fait, les boutons de navigation font directement partie du template du FlipView. Pour s'en rendre compte, il suffit d'utiliser Blend !

En créant un projet simple, contenant un FlipView et en l'ouvrant dans Blend, il est possible d'éditer une "copie" du template actuel:

Éditer une copie du template

Si on regarde ensuite le XAML, on peut voir que Blend a généré un Style représentant le FlipView, avec tous les Visual States nécessaires pour faire le FlipView tel qu'on le connait. Voici le code complet :

      <Style x:Key="FlipViewStyle1" TargetType="FlipView">
        	<Setter Property="Background" Value="Transparent"/>
        	<Setter Property="BorderThickness" Value="0"/>
        	<Setter Property="TabNavigation" Value="Once"/>
        	<Setter Property="IsTabStop" Value="False"/>
        	<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
        	<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
        	<Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.IsHorizontalScrollChainingEnabled" Value="True"/>
        	<Setter Property="ScrollViewer.IsVerticalScrollChainingEnabled" Value="True"/>
        	<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True"/>
        	<Setter Property="ItemsPanel">
        		<Setter.Value>
        			<ItemsPanelTemplate>
        				<VirtualizingStackPanel AreScrollSnapPointsRegular="True" Orientation="Horizontal"/>
        			</ItemsPanelTemplate>
        		</Setter.Value>
        	</Setter>
        	<Setter Property="Template">
        		<Setter.Value>
        			<ControlTemplate TargetType="FlipView">
        				<Grid>
        					<VisualStateManager.VisualStateGroups>
        						<VisualStateGroup x:Name="FocusStates">
        							<VisualState x:Name="Focused">
        								<Storyboard>
        									<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
        									<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
        								</Storyboard>
        							</VisualState>
        							<VisualState x:Name="Unfocused"/>
        							<VisualState x:Name="PointerFocused"/>
        						</VisualStateGroup>
        					</VisualStateManager.VisualStateGroups>
        					<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="3">
        						<Border.Resources>
        							<ControlTemplate x:Key="HorizontalNextTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M4.12,0 L9.67,5.47 L4.12,10.94 L0,10.88 L5.56,5.47 L0,0.06 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="10.94" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="9.67"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="HorizontalPreviousTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M5.55,0 L9.67,0.06 L4.12,5.47 L9.67,10.88 L5.55,10.94 L0,5.48 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="10.94" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="9.67"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="VerticalNextTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M0.06,0 L5.47,5.56 L10.88,0 L10.94,4.12 L5.48,9.67 L0,4.12 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="9.67" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="10.94"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="VerticalPreviousTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M5.63,0 L11.11,5.55 L11.05,9.67 L5.64,4.12 L0.23,9.67 L0.17,5.55 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="9.67" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="10.94"/>
        								</Border>
        							</ControlTemplate>
        						</Border.Resources>
        						<Grid>
        							<ScrollViewer x:Name="ScrollingHost" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalSnapPointsType="MandatorySingle" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled">
        								<ItemsPresenter/>
        							</ScrollViewer>
        							<Button x:Name="PreviousButtonHorizontal" HorizontalAlignment="Left" Height="40" IsTabStop="False" Template="{StaticResource HorizontalPreviousTemplate}" VerticalAlignment="Center" Width="70"/>
        							<Button x:Name="NextButtonHorizontal" HorizontalAlignment="Right" Height="40" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" VerticalAlignment="Center" Width="70"/>
        							<Button x:Name="PreviousButtonVertical" HorizontalAlignment="Center" Height="40" IsTabStop="False" Template="{StaticResource VerticalPreviousTemplate}" VerticalAlignment="Top" Width="70"/>
        							<Button x:Name="NextButtonVertical" HorizontalAlignment="Center" Height="40" IsTabStop="False" Template="{StaticResource VerticalNextTemplate}" VerticalAlignment="Bottom" Width="70"/>
        						</Grid>
        					</Border>
        					<Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
        					<Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
        				</Grid>
        			</ControlTemplate>
        		</Setter.Value>
        	</Setter>
        </Style>

Dans ce style, on retrouve:

  •  4 boutons : deux pour le flip horizontal, et deux pour le flip vertical.
    • PreviousButtonHorizontal
    • NextButtonHorizontal
    • PreviousButtonVertical
    • NextButtonVertical
  • 4 ControlTemplate : un pour chaque bouton
    • HorizontalNextTemplate
    • HorizontalPreviousTemplate
    • VerticalNextTemplate
    • VerticalPreviousTemplate

Vous n'avez plus qu'à jouer sur ce XAML pour arriver à ce que vous voulez :) Encore une fois, vous allez pouvoir apprécier mes talents et mon bon goût digne des graphistes les plus skillés !

Navigation ré-haussée avec du texte

 

Vous pouvez télécharger ce sample ici:

 

[Windows 8 / XAML] Customize the FlipView style

22. September 2012 15:20 by Renaud in Windows 8  //  Tags: , , ,   //   Comments (0)

During an Excellence Lab that I recently passed for a Windows 8 app, the Microsoft Expert told me it would be better to modify my FlipView to make sur the previous/next arrows don't override the content. The only thing I had to do for solving the problem, was to move the arrows upper. Then, a colleague ask me how to modify the color of those arrows... so I decided to write a post :) I can imagine that my colleague looked for a property such as "NavigationTemplate" or whatever, because that's how it works usually when you want to modify how some part of a control look like. For example, for the ItemTemplate property... But in this case, the buttons are directly part of the FlipView template itself ! To realize it, we will simply use Blend !

Create a simple project, using a FlipView and open it in Blend. Then, edit a "copy" of the template of your FlipView :

Edit a copy of the template

Looking at the XAML, you can see that Blend generated a Style element for the FlipView. It contains everything the the FlipView needs to look how it uses to, including the Visual States. Here is the complete default flipview style:

      <Style x:Key="FlipViewStyle1" TargetType="FlipView">
        	<Setter Property="Background" Value="Transparent"/>
        	<Setter Property="BorderThickness" Value="0"/>
        	<Setter Property="TabNavigation" Value="Once"/>
        	<Setter Property="IsTabStop" Value="False"/>
        	<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden"/>
        	<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/>
        	<Setter Property="ScrollViewer.IsHorizontalRailEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.IsVerticalRailEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.IsHorizontalScrollChainingEnabled" Value="True"/>
        	<Setter Property="ScrollViewer.IsVerticalScrollChainingEnabled" Value="True"/>
        	<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False"/>
        	<Setter Property="ScrollViewer.BringIntoViewOnFocusChange" Value="True"/>
        	<Setter Property="ItemsPanel">
        		<Setter.Value>
        			<ItemsPanelTemplate>
        				<VirtualizingStackPanel AreScrollSnapPointsRegular="True" Orientation="Horizontal"/>
        			</ItemsPanelTemplate>
        		</Setter.Value>
        	</Setter>
        	<Setter Property="Template">
        		<Setter.Value>
        			<ControlTemplate TargetType="FlipView">
        				<Grid>
        					<VisualStateManager.VisualStateGroups>
        						<VisualStateGroup x:Name="FocusStates">
        							<VisualState x:Name="Focused">
        								<Storyboard>
        									<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualWhite"/>
        									<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualBlack"/>
        								</Storyboard>
        							</VisualState>
        							<VisualState x:Name="Unfocused"/>
        							<VisualState x:Name="PointerFocused"/>
        						</VisualStateGroup>
        					</VisualStateManager.VisualStateGroups>
        					<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Margin="3">
        						<Border.Resources>
        							<ControlTemplate x:Key="HorizontalNextTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M4.12,0 L9.67,5.47 L4.12,10.94 L0,10.88 L5.56,5.47 L0,0.06 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="10.94" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="9.67"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="HorizontalPreviousTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M5.55,0 L9.67,0.06 L4.12,5.47 L9.67,10.88 L5.55,10.94 L0,5.48 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="10.94" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="9.67"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="VerticalNextTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M0.06,0 L5.47,5.56 L10.88,0 L10.94,4.12 L5.48,9.67 L0,4.12 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="9.67" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="10.94"/>
        								</Border>
        							</ControlTemplate>
        							<ControlTemplate x:Key="VerticalPreviousTemplate" TargetType="Button">
        								<Border x:Name="Root" BorderBrush="{StaticResource FlipViewButtonBorderThemeBrush}" BorderThickness="{StaticResource FlipViewButtonBorderThemeThickness}" Background="{StaticResource FlipViewButtonBackgroundThemeBrush}">
        									<VisualStateManager.VisualStateGroups>
        										<VisualStateGroup x:Name="CommonStates">
        											<VisualState x:Name="Normal"/>
        											<VisualState x:Name="PointerOver">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPointerOverForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        											<VisualState x:Name="Pressed">
        												<Storyboard>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBackgroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="Root">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedBorderThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        													<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="Arrow">
        														<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource FlipViewButtonPressedForegroundThemeBrush}"/>
        													</ObjectAnimationUsingKeyFrames>
        												</Storyboard>
        											</VisualState>
        										</VisualStateGroup>
        									</VisualStateManager.VisualStateGroups>
        									<Path x:Name="Arrow" Data="M5.63,0 L11.11,5.55 L11.05,9.67 L5.64,4.12 L0.23,9.67 L0.17,5.55 z" Fill="{StaticResource FlipViewButtonForegroundThemeBrush}" HorizontalAlignment="Center" Height="9.67" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Center" Width="10.94"/>
        								</Border>
        							</ControlTemplate>
        						</Border.Resources>
        						<Grid>
        							<ScrollViewer x:Name="ScrollingHost" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalSnapPointsType="MandatorySingle" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled">
        								<ItemsPresenter/>
        							</ScrollViewer>
        							<Button x:Name="PreviousButtonHorizontal" HorizontalAlignment="Left" Height="40" IsTabStop="False" Template="{StaticResource HorizontalPreviousTemplate}" VerticalAlignment="Center" Width="70"/>
        							<Button x:Name="NextButtonHorizontal" HorizontalAlignment="Right" Height="40" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" VerticalAlignment="Center" Width="70"/>
        							<Button x:Name="PreviousButtonVertical" HorizontalAlignment="Center" Height="40" IsTabStop="False" Template="{StaticResource VerticalPreviousTemplate}" VerticalAlignment="Top" Width="70"/>
        							<Button x:Name="NextButtonVertical" HorizontalAlignment="Center" Height="40" IsTabStop="False" Template="{StaticResource VerticalNextTemplate}" VerticalAlignment="Bottom" Width="70"/>
        						</Grid>
        					</Border>
        					<Rectangle x:Name="FocusVisualWhite" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="1.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}" StrokeDashArray="1,1"/>
        					<Rectangle x:Name="FocusVisualBlack" IsHitTestVisible="False" Opacity="0" StrokeDashOffset="0.5" StrokeEndLineCap="Square" Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}" StrokeDashArray="1,1"/>
        				</Grid>
        			</ControlTemplate>
        		</Setter.Value>
        	</Setter>
        </Style>

In this style, you can find :

  •  4 buttons: two for the horizontal flip, and two for the vertical flip.
    • PreviousButtonHorizontal
    • NextButtonHorizontal
    • PreviousButtonVertical
    • NextButtonVertical
  • 4 ControlTemplate : one for each button
    • HorizontalNextTemplate
    • HorizontalPreviousTemplate
    • VerticalNextTemplate
    • VerticalPreviousTemplate

Then, you just have to play with the XAML to achieve what you want to :) Once again, you can appreciate my incredible talent and good taste, that would make the most skilled designer jealous !

Upper navigation with colors and text"

You can download the sample here :

28th September 2012 :the next Windows 8 appathon in Zaventem

19. September 2012 15:26 by Renaud in   //  Tags:   //   Comments (0)

October 26 is getting closer and closer … is your Windows 8 app ready? You’re invited to the last app-a-thon before Windows 8 hits the market. Join us at our offices in Zaventem on September 28!

Team up with your best UX or developer friend to build a killer team, come alone, sign up with a group, whatever you want! Hands on. Code. Build. Shine. Totally Metro. Totally Windows 8.

When? 28 September 2012 Where? Microsoft Belgium Leonardo Da Vincilaan 3 1935 Zaventem

There will be 2 coding sessions, 1 for Day Birds from 10am – 4pm and one for Night Owls from 6pm – 12am. You can join us for one or both sessions. Build an app, have fun and go home with a fantastic prize!

Xbox 360 + Kinect

 

Deluxe App’ero Bongo Box

Professional Sharp Knife Set

Seats are limited so don’t lose a sec and SIGN UP NOW! All technical pre-requisites and resources are available on the registration page.

No app idea yet? No problem! We have a bucket full of ideas and scenarios you can use right away to kick start your project!

Questions about UX & design? Don’t worry, we’ve got that covered. You’ll be able to talk to a Windows 8 UX Expert (will be there for 4 hours) and a designer (will be there the entire day!) to help out with logo’s, graphic design, etc.

Looking forward to enjoy this day and/or night with you!

Le prochain App-a-thon Windows 8 c'est le 28 Septembre à Zaventem !

19. September 2012 11:09 by Renaud in   //  Tags:   //   Comments (0)

Deux jours après l'App'ero Windows 8 se tiendra un app-a-thon aux bureaux de Microsoft à Zaventem. Si vous n'en pouvez plus d'attendre la sortie de Windows 8, ou que vous souhaitez terminer votre app pour la sortie officielle, inscrivez-vous à cet événement !

On s'approche petit à petit du 26 Octobre, date de sortie officielle de Windows 8. Votre app est-elle prête ? Dans tous les cas, vous êtes invités au dernier app-a-thon (avant la sortie de Windows 8 du moins ;)). Rejoignez Microsoft dans leurs bureaux de Zaventem le 28 Septembre.

Faites équipe avec un ami designer ou développeur pour former une équipe de killer, ou venez seul et rencontrez des gens sur place. Faites comme bon vous semble ! Mais venez plonger les mains dans le code, pour développer votre propre application !

Quand? 28 Septembre 2012 Où? Microsoft Belgium Leonardo Da Vincilaan 3 1935 Zaventem

Il y aura 2 sessions de code, une pour les développeurs diurnes de 10h à 16h, et l'autre pour les noctambules de 18h à minuit!  Vous pouvez nous rejoindre pour l'un ou l'autre, ou les deux ! Développez, amusez-vous et rentrez chez vous avec un prix :)

Xbox 360 + Kinect

 

Deluxe App’ero Bongo Box

Professional Sharp Knife Set

Les places sont limitées donc ne perdez pas une secondes et SIGN UP NOW! Toutes les infos techniques, ressources nécessaires, sont dispos sur la page d'inscription.

Pas encore d'idée d'app? Pas de problème, des personnes sur place auront des tonnes d'idée et de scénarios que vous pourrez utiliser pour démarrer immédiatement !

Des questions UX ou design? Ne vous inquiétez pas, vous aurez la possibilité de parler à un expert Windows 8 UX (présents durant 4h) et un designer (présent toute la journée !) qui pourra vous aideravec vos logos, votre interface graphique, etc...

En espérant vous y voir ;)

TextBox

About the author

I'm a developer, blog writer, and author, mainly focused on Microsoft technologies (but not only Smile). I'm Microsoft MVP Client Development since July 2013.

Microsoft Certified Professional

I'm currently working as an IT Evangelist with an awesome team at the Microsoft Innovation Center Belgique, where I spend time and energy helping people to develop their projects. I also give training to enthusiastic developers and organize afterworks with the help of the Belgian community.

MIC Belgique

Take a look at my first book (french only): Développez en HTML 5 pour Windows 8

Développez en HTML5 pour Windows 8

Membre de l'association Fier d'être développeur

TextBox

Month List