Comment “cuisiner” une application Windows 8 avec HTML 5, CSS3 et JavaScript en une semaine–Jour 0 - Eternal Coding - HTML5 / JavaScript / 3D development - Site Home - MSDN Blogs

Comment “cuisiner” une application Windows 8 avec HTML 5, CSS3 et JavaScript en une semaine–Jour 0


 

Comment “cuisiner” une application Windows 8 avec HTML 5, CSS3 et JavaScript en une semaine–Jour 0

  • Comments 17

(La version finale est accessible ici: http://blogs.msdn.com/b/eternalcoding/archive/2012/06/08/comment-cuisiner-une-application-windows-8-avec-html-5-css3-et-javascript-en-une-semaine-jour-5.aspx)

Le but de cette série d’articles est de fournir une recette pragmatique pour écrire une application Windows 8 à partir de zéro.

L’application que j’utiliserai comme exemple est nommée UrzaGatherer et est utilisée pour aider les collectionneurs de cartes Magic The Gathering à gérer leur collection. 

image_thumb4

UrzaGatherer fut développé à l’origine avec WPF 4.0 (http://urzagatherer.codeplex.com/) mais j’ai préféré utiliser HTML 5, CSS3 et JavaScript pour développer la version Windows 8 car je voulais me pencher sur ce nouveau mode de développement.

Pour développer l’application, vous allez donc avoir besoin de :

La solution peut être téléchargée ici: http://www.catuhe.com/msdn/urza/day0.zip 

L’intégralité de la série est disponible ici:

Créer le projet

La première chose à faire est de créer un projet vide (nous aurions bien sur pu utiliser un modèle plus complet de Visual Studio comme le ‘Grid Application"’ mais l’objectif ici est de comprendre comme tout fonctionne) en utilisant le menu Fichier/Nouveau projet : 

image_thumb8

Le projet est ainsi créé avec uniquement les fichiers nécessaires :

image_thumb11

Créer les ressources graphiques

Le fichier package.appxmanifest permet de décrire votre application auprès de Windows 8. Il contient particulièrement la description de l’application ainsi que tous les logos et ressources graphiques nécessaires :

  • image_thumb14

J’aime beaucoup ajouter ces ressources à mes applications car cela donne tout de suite un air de “vraie application”.

Le “splash screen” par exemple est très important car c’est la première chose que vos utilisateurs vont voir et comme chacun sait la première impression est toujours la plus importante : 

image_thumb17

Cette partie est souvent la plus dure au final car les développeurs ne sont que très rarement de bons designers Sourire

Structurer le projet

La structuration va dépendre de votre manière de travailler. Personnellement j’aime travailler ainsi : 

image_thumb20

  • Un répertoire pour mes ressources graphiques (/images)
  • Un répertoire pour mon code JavaScript qui n’est pas en relation avec les pages (/js)
  • Un répertoire pour les pages
  • Un répertoire pour chaque page (/pages/xxx) ou seront positionnés les fichiers .js, .html, .css
  • Une page racine default.html (avec son .css et son .js)
       

Connexion aux données

La connexion aux données sera faite dans le fichier /js/data.js.

Pour UrzaGatherer, les données sont composées de : 

  • Un fichier all.json qui décrit toutes les cartes supportées
  • Les images de chaque carte (plus de 4Go!!)
  • Un logo pour chaque extension (sachant qu’une carte appartient à une extension qui appartient à un bloc)
  • Un logo pour chaque bloc

En partant de notre fichier data.js vide, nous allons ajouter une fonction anonyme automatique :

(function () { })();

A l’intérieur de cette fonction, nous allons récupérer les données. Pour UrzaGatherer, ce fichier est présent en ligne (all.json) mais fait une taille trop importante pour être téléchargé à chaque fois. Il faut donc gérer un cache local :

(function () {

    var blocks = new WinJS.Binding.List();
    var expansions = new WinJS.Binding.List();
    var root = "http://urzagatherer.blob.core.windows.net";

    var expansionSorter = function (i0, i1) {
        if (i0.orderInBlock > i1.orderInBlock)
            return 1;
        else if (i0.orderInBlock < i1.orderInBlock)
            return -1;
        return 0;
    };

    var processBlocks = function (data) {
        var result = JSON.parse(data);

        for (var blockIndex = 0; blockIndex < result.length; blockIndex++) {
            var block = result[blockIndex];

            block.logo = root + "/blocks/" + block.name.replace(":", "_") + ".png";
            blocks.push(block);

            var sortedExpansions = block.expansions.sort(expansionSorter);

            for (var expansionIndex = 0; expansionIndex < sortedExpansions.length; expansionIndex++) {
                var expansion = sortedExpansions[expansionIndex];
                expansion.block = block;
                expansion.logo = root + "/logos/" + expansion.name.replace(":", "_") + ".png";
                expansions.push(expansion);
            }
        }
    }

    var getBlocksDistant = function (onload) {
        var localFolder = Windows.Storage.ApplicationData.current.localFolder;
        var requestStr = root + "/cards/all.json";

        WinJS.xhr({ url: requestStr }).then(function (request) {
            processBlocks(request.responseText);

            localFolder.createFileAsync("all.json", 
Windows.Storage.CreationCollisionOption.replaceExisting).then(
function (file) { Windows.Storage.FileIO.writeTextAsync(file, request.responseText); }); if (onload) onload(); }); } var getBlocks = function (onload) { var localFolder = Windows.Storage.ApplicationData.current.localFolder; localFolder.getFileAsync("all.json").done(function (file) { return Windows.Storage.FileIO.readTextAsync(file).then(function (data) { processBlocks(data); if (onload) onload(); }); }, function () { getBlocksDistant(onload); }); } WinJS.Namespace.define("UrzaGatherer", { Blocks: blocks, Expansions: expansions, Init: getBlocks }); })();

En utilisantWinJS.Namespace.define, vous allez pouvoir déclarer un objet global (nommé UrzaGatherer) qui sera disponible partout dans votre code.

L’initialisation (via la fonctionInit ) commence donc par chercher les informations en local puis tente de le télécharger via WinJS.xhr (http://msdn.microsoft.com/en-us/library/windows/apps/br229787.aspx) en cas d’échec. 

La fonction Init prend en paramètre une fonction que j’utilise pour savoir que le chargement est terminé et que je peux cacher mon anneau d’attente (une progress bar en mode “ring”).

Préparation de la page d’arrivée

Système de navigation

La page default.html est la page d’arrivée c’est à dire la page qui sera chargée après le lancement de l’application. Dans notre cas elle sera chargé de gérer le système de navigation :

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>UrzaGatherer</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-light.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>

    <!-- UrzaGatherer references -->
    <link href="/default.css" rel="stylesheet">
    <script src="/js/data.js"></script>
    <script src="/js/tools.js"></script>
    <script src="/js/navigator.js"></script>
    <script src="/default.js"></script>
</head>
<body>
    <div id="contenthost" data-win-control="UrzaGatherer.PageControlNavigator" 
data-win-options="{home: '/pages/home/home.html'}"></div> </body> </html>

Cette page est simple: Elle commence par référencer les fichiers de WinJS puis elle charge le code JavaScript global et la feuille de style par défaut.

Au niveau DOM, elle contient un seul div qui va servir de hôte pour les pages filles. C’est un point extrêmement important à comprendre. En effet les pages ne sont pas chargées les unes sur les autres comme dans un navigateur mais sont chargées dans une page hôte (default.html).

Pour mettre en place ce principe il faut faire appel au fichier navigator.js qui va créer le contrôle de navigation (Le code de ce fichier est présent dans les templates Visual Studio 11 tel que ‘Grid Application’) :

(function () {
    "use strict";

    var appView = Windows.UI.ViewManagement.ApplicationView;
    var displayProps = Windows.Graphics.Display.DisplayProperties;
    var nav = WinJS.Navigation;
    var ui = WinJS.UI;
    var utils = WinJS.Utilities;

    WinJS.Namespace.define("UrzaGatherer", {
        PageControlNavigator: WinJS.Class.define(
        // Define the constructor function for the PageControlNavigator.
            function (element, options) {
                this.element = element || document.createElement("div");
                this.element.appendChild(this._createPageElement());

                this.home = options.home;

                nav.onnavigated = this._navigated.bind(this);
                appView.getForCurrentView().onviewstatechanged = this._viewstatechanged.bind(this);

                document.body.onkeyup = this._keyupHandler.bind(this);
                document.body.onkeypress = this._keypressHandler.bind(this);
                nav.navigate(this.home);
            }, {
                // This function creates a new container for each page.
                _createPageElement: function () {
                    var element = document.createElement("div");
                    element.style.width = "100%";
                    element.style.height = "100%";
                    return element;
                },

                // This function responds to keypresses to only navigate when
                // the backspace key is not used elsewhere.
                _keypressHandler: function (eventObject) {
                    if (eventObject.key === "Backspace")
                        nav.back();
                },

                // This function responds to keyup to enable keyboard navigation.
                _keyupHandler: function (eventObject) {
                    if ((eventObject.key === "Left" && eventObject.altKey) 
|| (eventObject.key ===
"BrowserBack")) { nav.back(); } else if ((eventObject.key === "Right" && eventObject.altKey)
|| (eventObject.key ===
"BrowserForward")) { nav.forward(); } }, // This function responds to navigation by adding new pages // to the DOM. _navigated: function (eventObject) { var newElement = this._createPageElement(); var parentedComplete; var parented = new WinJS.Promise(function (c) { parentedComplete = c; }); var that = this; WinJS.UI.Pages.render(eventObject.detail.location,
newElement, eventObject.detail.state, parented). then(
function (control) { that.element.appendChild(newElement); that.element.removeChild(that.pageElement); parentedComplete(); document.body.focus(); that.navigated(); }); }, // This function is called by _viewstatechanged in order to // pass events to the page. _updateLayout: { get: function () { return (this.pageControl && this.pageControl.updateLayout)
||
function () { }; } }, _viewstatechanged: function (eventObject) { (this._updateLayout.bind(this.pageControl))(this.pageElement, eventObject.viewState); }, // This function updates application controls once a navigation // has completed. navigated: function () { // Do application specific on-navigated work here var backButton = this.pageElement.querySelector("header[role=banner] .win-backbutton"); if (backButton) { backButton.onclick = function () { nav.back(); }; if (nav.canGoBack) { backButton.removeAttribute("disabled"); } else { backButton.setAttribute("disabled", "disabled"); } } }, // This is the PageControlNavigator object. pageControl: { get: function () { return this.pageElement && this.pageElement.winControl; } }, // This is the root element of the current page. pageElement: { get: function () { return this.element.firstElementChild; } } } ), // This function navigates to the home page which is defined when the // control is created. navigateHome: function () { var home = document.querySelector("#contenthost").winControl.home; var loc = nav.location; if (loc !== "" && loc !== home) { nav.navigate(home); } }, }); })();

Comme vous pouvez le voir, le controle PageControlNavigator ajoute la page cible en tant qu’élément enfant après avoir supprimé le précédent. Comprendre ce point est essentiel car cela implique par exemple que tous les css et les scripts restent présents même lorsque l’on navigue vers une autre page (http://msdn.microsoft.com/en-us/library/windows/apps/hh452768.aspx).

Appliquer les styles à la page

La feuille de style default.css constitue la feuille de style racine et donc comme vu précédemment sera présente dans toutes les pages filles. Elle est responsable de mettre en place la structure globale.

Elle me sert également a stocker les styles globaux que j’utiliser comme la classe .hidden (que j’utilise pour cacher des éléments) :

html {
    cursor: default;
}

body {
    background-image: url('images/background.jpg');
    background-size: 100% 100%
}

#contenthost {
    height: 100%;
    width: 100%;
}

.fragment {
    /* Define a grid with rows for a banner and a body */
    -ms-grid-columns: 1fr;
    -ms-grid-rows: 133px 1fr 0px;
    display: -ms-grid;
    height: 100%;
    width: 100%;
}

.fragment header[role=banner] {
    /* Define a grid with columns for the back button and page title. */
    -ms-grid-columns: 120px 1fr;
    -ms-grid-rows: 1fr;
    display: -ms-grid;
}

.fragment header[role=banner] .win-backbutton {
    margin-left: 39px;
    margin-top: 59px;
}

.fragment header[role=banner] .titlearea {
    -ms-grid-column: 2;
    margin-top: 37px;
}

.fragment header[role=banner] .titlearea .pagetitle {
    width: calc(100% - 20px);
}

.fragment section[role=main] {
    -ms-grid-row: 2;
    height: 100%;
    width: 100%;
}

.hidden {
    display: none;
}

Vous pouvez noter l’utilisation de display:-ms-grid connu sous le nom de CSS3 Grid Layout (http://msdn.microsoft.com/en-us/library/windows/apps/hh465327.aspx). Ce type de display est très pratique car il permet de définir la structure en utilisant des grilles.

De plus pour le fond d’écran si vous n’avez pas de graphistes sous la main, vous pouvez simplement utiliser un léger dégradé (facile à créer avec Paint.net par exemple) :

image_thumb[3] 

Création de la page principale

Le premier écran visible est fournit par la page “home”. Elle va servir à afficher les extensions triées par blocs.

De base, elle est constituée ainsi :

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>UrzaGatherer</title>
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-light.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
    <!-- UrzaGatherer references -->
    <link href="home.css" rel="stylesheet">
    <script src="home.js"></script>
</head>
<body>
    <!--Content-->
    <div class="home fragment">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled></button>
            <h1 class="titlearea win-type-ellipsis"><span class="pagetitle">UrzaGatherer</span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">

        </section>
    </div>
</body>
</html>
On peut noter la présence de notre bannière (header) et une section pour mettre notre contenu.

Pour ce faire, j’utilise un contrôle de type WinJS.UI.ListView. Ce dernier permet d’afficher des valeurs regroupées par des clefs :

<div class="blocksList" aria-label="List of blocks" data-win-control="WinJS.UI.ListView"
    data-win-options="{itemTemplate:select('.itemTemplate'), groupHeaderTemplate:select('.headerTemplate')
, selectionMode:'none', swipeBehavior:'none', tapBehavior:'invoke', layout:{type:WinJS.UI.GridLayout}}"> </
div>

Le contrôle référence deux templates (itemTemplate et headerTemplate) qui définissent la structure visuelle des éléments et des entêtes :

    <div class="headerTemplate" data-win-control="WinJS.Binding.Template">
        <div class="header-title" data-win-bind="innerText: name">
        </div>
        <img class="item-image" data-win-bind="src: logo" src="#" />
    </div>
    <div class="itemTemplate" data-win-control="WinJS.Binding.Template">
        <img class="item-image" data-win-bind="src: logo" src="#" />
        <div class="item-overlay">
            <h4 class="item-title" data-win-bind="textContent: name"></h4>
        </div>
    </div> 

Ici encore, j’utilise CSS3 Grid pour créer ma structure comme on peut le voir dans home.css :

.home .blocksList .win-item {
    -ms-grid-columns: 1fr;
    -ms-grid-rows: 1fr 30px;
    display: -ms-grid;
    height: 130px;
    width: 260px;
    background: white;
    outline: rgba(0, 0, 0, 0.8) solid 2px;
}

    .home .blocksList .win-item:hover {
        outline: #5F38FF solid 2px;
    }

    .home .blocksList .win-item .item-image-container {
        -ms-grid-columns: 1fr;
        -ms-grid-rows: 1fr;
        -ms-grid-row: 1;
        display: -ms-grid;
        padding: 4px;
        -ms-transition: opacity ease-out 0.2s, -ms-transform ease-out 0.2s;
        -ms-transform: scale(1.0, 1.0);
    }

        .home .blocksList .win-item .item-image-container:hover {
            opacity: 0.9;
            -ms-transform: scale(1.1, 1.1);
        }

    .home .blocksList .win-item .item-image {
        -ms-grid-row: 1;
        -ms-grid-column-align: center;
        -ms-grid-row-align: center;
        max-height: 90px;
    }

    .home .blocksList .win-item .item-overlay {
        -ms-grid-row: 2;
        padding: 3px 15px 2px;
        background-color: rgba(0, 0, 0, 0.8);
    }
Et grâce à CSS3 Transitions (http://msdn.microsoft.com/en-us/library/windows/apps/Hh781227.aspx), c’est simplissime de faire une jolie animation pour gérer le survol (“hover”).

Par la suite, la liste (blocksList) est remplie en utilisant les données récupérées précédemment et la fonction createGrouped de la classe WinJS.Binding.List :

var groupDataSource = UrzaGatherer.Expansions.createGrouped(this.groupKeySelector, 
this.groupDataSelector, this.groupCompare); ui.setOptions(listView, { itemDataSource: groupDataSource.dataSource, groupDataSource: groupDataSource.groups.dataSource, layout: new ui.GridLayout({ groupHeaderPosition: "top" }) });

Un point important ici est situé autour de la fonction groupKeySelector. Cette dernière est utilisée pour créer une clef unique pour chaque groupe. Cette clef est ensuite utilisée pour grouper les éléments et sera aussi utile lorsque l’on ajoutera le SemanticZoom :

groupKeySelector: function (item) {
    return item.block.name + "*" + item.block.index;
},

Faites bien attention ici: Il faut obligatoirement retourner une chaine de caractères et pas un nombre sous peine de faire planter les contrôles.

La fonction groupCompare se charge de faire le tri en se basant sur les clefs :

groupCompare: function (i0, i1) {
    var index0 = parseInt(i0.split("*")[1]);
    var index1 = parseInt(i1.split("*")[1]);

    return index1 - index0;
},

Ajout d’un contrôle personnalisé pour afficher les images

Un des problèmes que j’ai rencontré avec l’affichage des images est le fait que leur téléchargement peut prendre du temps et comme tout est asynchrone (ce qui est bien) la page peut s’afficher avant que toutes les images ne soient chargées. Cela donne alors un effet de clignotement désagréable quand une image remonte.

Pour contrer ce problème, je vous propose de créer notre propre contrôle pour afficher les images de manière plus gracieuse :

La déclaration d’un contrôle personnalisé se fait via la fonction WinJS.Class.define :

(function () {

    var delayImageLoader = WinJS.Class.define(
            function (element, options) {
                this._element = element || document.createElement("div");
                this.element.winControl = this;
                WinJS.Utilities.addClass(this.element, "imageLoader");
                WinJS.Utilities.query("img", element).forEach(function (img) {
                    img.addEventListener("load", function () {
                        WinJS.Utilities.addClass(img, "loaded");
                    });
                });
            },
            {

                element: {
                    get: function () { return this._element; }
                },
            });

    WinJS.Namespace.define("UrzaGatherer.Tools", {
        DelayImageLoader: delayImageLoader
    });
})();

Comme vous pouvez le voir, le contrôle recherche toutes les enfants de type image et se branche sur leur événement “load”. Toute la magie est en fait dans le CSS puisque le contrôle ne fait que rajouter une classe CSS au début (imageLoader) et une autre à la fin du chargement (loaded).

Ces deux classes devant être globales, je les ai défini dans le fichier default.css :

.imageLoader img {
    opacity: 0;
    -ms-transform: scale(0.8, 0.8);
}

    .imageLoader img.loaded {
        opacity: 1;
        -ms-transition: opacity ease-out 0.2s, -ms-transform ease-out 0.2s;
        -ms-transform: scale(1, 1);
    }

En utilisant les CSS3 transitions, l’image arrive avec une petite animation du meilleur effet Sourire

 

Ajout du zoom sémantique

Finalement, nous allons ajouter un zoom sémantique (http://msdn.microsoft.com/en-us/library/windows/apps/hh465492.aspx) pour permettre à nos utilisateurs de sauter rapidement vers un bloc:

image_thumb[6] 

Pour ce faire, nous avons juste à embarquer notre ListView avec une autre ListView (celle responsable de la vue zoomée) au sein d’un contrôle de type WinJS.UI.SemanticZoom :

<div class="zoomControl" data-win-control="WinJS.UI.SemanticZoom">
    <div class="blocksList" aria-label="List of blocks" data-win-control="WinJS.UI.ListView"
        data-win-options="{itemTemplate:select('.itemTemplate'), groupHeaderTemplate:select('.headerTemplate'), 
                            selectionMode:'none', swipeBehavior:'none', tapBehavior:'invoke',  
                            layout:{type:WinJS.UI.GridLayout}}">
    </div>
    <div class="zoomedList" aria-label="Zoomed List of blocks" data-win-control="WinJS.UI.ListView"
        data-win-options="{itemTemplate:select('.semanticZoomTemplate'), selectionMode:'none', 
                            swipeBehavior:'none', tapBehavior:'invoke',  layout:{type:WinJS.UI.GridLayout}}">
    </div>
</div>

Pour synchroniser les deux listes il faut juste utiliser la même source de données pour les groupes dans la première liste et pour les éléments dans la seconde :

var groupDataSource = UrzaGatherer.Expansions.createGrouped(this.groupKeySelector, 
this.groupDataSelector, this.groupCompare); ui.setOptions(listView, { itemDataSource: groupDataSource.dataSource, groupDataSource: groupDataSource.groups.dataSource, layout: new ui.GridLayout({ groupHeaderPosition: "top" }) }); ui.setOptions(zoomedListView, { itemDataSource: groupDataSource.groups.dataSource });

A suivre

Le prochain article introduira les fonctionnalités suivantes :

  • La page des cartes
  • La page des extensions
  • Gestion du mode offline
  • Gestion des settings
 
 
 
Leave a Comment
  • Please add 3 and 3 and type the answer here:
  • Post
  • Ca sert a quoi de ce casser le cul a faire du Html/JavaScript si c'est pour que ca ne fonctionnement pas sur un browser classique ?

    Je suis un dev .net et javascript et si ca ne fonctionne pas sur Mozilla et que ca se fait en C#, je pense pas que toutes vos api specifiques a metro ai beaucoup de succes!

  • Hello Sebastien, l'objectif du Framework JavaScript est de permettre aux développeurs connaissant HTML5/CSS3 et JavaScript de pouvoir développer des applications Windows 8 sans avoir à apprendre C++ ou C#.

    Le but n'est donc pas ici de faire du JavaScript en lieu et place du C#. Si vous connaissez bien C#, go pour C# (la version 5 en fait clairement un des langages le mieux aboutis qui soient) mais si vous ne connaissez pas et que vous connaissez JavaScript, go pour JavaScript.

    On ne veut pas une opposition entre les deux mais bien un libre choix pour les développeurs

  • Merci beaucoup pour vos articles...

    Comme vous l'avez très bien souligné, pour ma part, le faite de ne pas avoir à apprendre un langage pour développer du "natif" est un réel plus.

    Je n'exclu pas de me mettre à apprendre le C# mais c'est vraiment une bonne chose de pouvoir basculer vers le "monde metro" en douceur :)

  • L'article est intéressant, dommage que je n'ai pas le temps de le lire :( .

    Par contre, en ce qui concerne le dégradé, vous auriez pu utiliser la fonctionnalité CSS3 pour le faire. Merci.

  • Est-on obligé d'utiliser visual studio 11 sur windows 8 ?

    Je m'explique j'ai Windows 7 et je n'arrive pas à virtualiser windows 8 (problème de virtualisation matérielle sur les sony vaio) et je n'ai pas envi non plus de booter ma machine sur windows 8. Est-ce que je peux installer visual studio 11 béta sur windows 7 et créer mon application métro windows 8 ?

  • Helas oui il faut utiliser  vs11 sur Win8 pour faire du Metro

  • J'ai trouvé une alternative : VMware au lieu de VirtualBox.

    J'ai réussi à installer windows 8 mais je n'arrive pas à installer visual studio 11 beta for windows 8. J'ai le message suivant : Product is under license... Mais comme c'est une béta c'est censé être gratuit.. Où est-ce que je peux renseigner la licence ?

  • Normalement elle est dispo sur preview.Windows.com

  • Je suis nouveau sur ce domaine !!

    J'ai pas mal de connaissances en HTML & CSS mais rien a propos de Java

    Est ce que je pourrait moi aussi participer !?

  • Bonjour, j'espere que ce commentaire seras lus, j'ai voulut me lancée dans les application metro, et ce tuto a été le plus complet que j'ai pus trouver, mais malheureusement je ne comprend pas tout ce qui est dit, on a des ligne de code part-ci part-la et je ne sais pas quoi faire, donc voilas je demmande si je pourai savoir quelque explication supplementaire (pas la peine de me demander ce que je n'ai pas compris, mon probleme c'est que je ne comprend pas ce que fait tel ou tel ligne de code, ce qui m'empeche de savoir ou ecrire mon code car il y a beaucoup de page de code differente). Bien sur si il faut pour cella s'exprimer en privée je fournirai smon adresse mail pour pouvoir parlé librement. Sur ce je vous shouaite une bonne journée et bon developpement à tous.

  • Hello une autre approche est d'utiliser le code complet présent en début d'articles. Comme ca tu peux debugger sur une version complete de l'application pour découvrir comment tout cela fonctionne

  • D'accord, masi a chaque fois que je telecharge le fichier je ne peut pas l'ouvrir, j'ai un message d'erreur qui me dit que certain fichier sont manquant...

  • Vous pouvez m'indiquer le message d'erreur précis? Vous etes bien sur Windows 8 RP avec vs2012?

  • Bonjour,

    J'ai téléchargé les sources présentes sur www.catuhe.com/.../day0.zip  

    Lorsque j'essaye de lancer la solution, VS m'indique "Could not find SDK "Microsoft.WinJS, Version=0.6". J'ai alors regardé les références qui indiquent que Microsoft.WinJS n'est pas résolu.

    J'ai alors ajouré la librairie Microsoft Library for Javascript 1.0.RC et l'erreur apparait toujours.

    Que dois je faire ?

    Merci par avance,

    Nicolas

  • Hello, il vous faut prendre les sources du jour 5 qui ont été portées de la Consumer Preview vers la Release Preview :)

Page 1 of 2 (17 items) 12