Windows 8 Apps – L’importanza del design

Uno degli aspetti fondamentali che ha contraddistinto da sempre lo sviluppo software (o almeno avrebbe dovuto :P) è sicuramente la cura del design e dell’esperienza utente. Chi di noi tra due applicazioni perfettamente identiche in termini di funzionalità, qualità e costo non utilizza come paramentro finale per la scelta del prodotto da acquistare la bellezza di quest’ultimo (e qui potreste ragionevolmente obbiettare che nella vita reale la bellezza della UI in realtà è il primo parametro considerato dall’acquirente indipendentemente dal funzionamento del software ma almeno qui fingiamo di essere in un mondo idealmente sano e razionale!!!).

Ma “diamo a Casere quel che è di Cesare” disse una volta qualcuno… curare il design di un’applicazione non dovrebbe essere una questione di sola gradevolezza ma anche e soprattutto di usabilità!

Chi di noi nel corso degli anni non si è ritrovato più volte a mordersi un labbro quando le interfacce grafiche dei software più utilizzati, magari in ufficio, sono mutate totalemente con un conseguente degrado iniziale delle prestazioni nel loro utilizzo?!?!

Vogliamo fare qualche esempio: Office? (ed ho detto tutto :P)

… eppure dobbiamo considerare che nulla viene fatto a caso e di certo microsoft, nel caso specifico ma analogamente gli altri colossi della produzione software, non gode del nostro malcontento e se nel tempo ha affrontato più volte un cambio radicale nella presentation dei propri pacchetti software lo scopo era quello di migliorare gradualmente la UX e questo purtroppo comporta delle fasi intermedie talvolta poco piacevoli ma necessaria sia per abituare l’utente alle successive novità sia per comprendere la giusta strada da intraprendere in base al riscontro ottenuto …come si dice? sbagliando si impara no?

Le Windows 8 Applications oggi rappresentano l’ennesimo cambio di stile ma questa volta oltre ad avere una rinnovata caratterizzazione grafica rispetto al passato (la cui gradevolezza dipende assolutamente dal gusto personale) stanno portando una modalità di interazione con il software completamente nuova e a mio avviso estremamente semplificata.

Grazie infatti:

  • all’apprendimento che potremmo definire quasi “a colpo d’occhio” grazie ad una UI basata sul contenuto che di conseguenza si descrive quasi da sola nelle sue funzionalità;
  • il minimalismo e la mancanza di elementi inutili in base al contesto funzionale;
  • l’alta fluidità e responsività dell’interfaccia;
  • lo studio dei colori e delle giuste proporzioni per catturare l’attenzione dell’utente;
  • l’interazione basata sul touch che a mio avviso, e qui ci scappa il sorriso, rende più intimo il rapporto tra l’utente e l’applicazione;

si vive frse un cambio generazionale sicuramente meno drammatico delle altre volte eppure questa volta le differenze sono veramente tante.

Inoltre vengono dati finalmente dei canoni base sui quali basare la user experience dei propri pacchetti software, canoni e principi che non devono essere vissuti come delle regole per limitare la creatività (anzi credo che le metro style applications aprano diversi scenari interessanti sotto il punto di vista della creatività) piuttosto come il punto di partenza per ridare la giusta importanza da troppo tempo sotratta alla figura dell’UX Designer.

Metro Style Apps – Data Binding – Quarta Parte

Come promesso in questo ultimo post relativo al Data Binding Dichiarativo relativo alle Metro Style Applicattions vedremo come sia possibile selezionare un item da una WinJS.UI.ListView e visualizzarne i dettagli in una nuova pagina html ovvero vedremo come sia possibile passare informazioni da una pagina all’altra in una Metro Style Application.

Utilizzeremo come base per l’esempio, l’applicazione vista nei post precedenti relativi al Data Binding Dichiarativo (quindi per chi non l’avesse già fatto ne consiglio la lettura). Se ricordate nel primo post della serie abbiamo creato una pagina (contact.html) per la visualizzazione di un singolo contatto e l’abbiamo utilizzata per un primo esempio di Binding non dichiarativo

Metro Style Apps - Data Binding - Esempio 1

nel secondo post della serie l’abbiamo poi affinata in modo tale da slegare la view dalle logiche di business con l’implementazione del Databiding Dichiarativo, da quel momento in poi abbiamo lavorato esclusivamente sulla pagina (homePage.html) relativa alla visualizzazione dell’intero set di items della nostra lista (che nell’esempio rappresenta un set di contatti per una rubrica)

Metro Style Apps – Data Binding – Esempio 1.2

Adesso quello che ci interessa rendere possibile è che al click su di un item della lista venga visualizzato il dettaglio del relativo contatto nella pagina contact.html.

Bene, come prima cosa dobbiamo aggiungere alla ListView un gestore di evento che si occupi di reagire al click sui singoli items e che passi le informazioni del contatto selezionato alla pagina di destinazione che ne visualizzerà il dettaglio a video, vediamo il codice:


(function () {
    "use strict";
    var nav = WinJS.Navigation;

    function dvContacts_iteminvoked(eventInfo)
    {
        var itemIndex = eventInfo.detail.itemIndex;
        var item = Contacts.items.getAt(itemIndex);
        nav.navigate("/html/contact.html", { item: item });
    }

    function ready(element, options) {
        WinJS.Binding.processAll();
        dvContacts.addEventListener("iteminvoked", dvContacts_iteminvoked);
    }

    WinJS.UI.Pages.define("/html/homePage.html", {
        ready: ready
    });

})();

Come è facile notare abbiamo definito un handler dvContacts_iteminvoked che recupera le informazioni del item selezionato (attenzione quando dico selezionato in realtà non è propriamente corretto in quanto il gestore iteminvoked risponde al click sull’elemento e non alla selezione) e le invia alla pagina /html/contact.html tramite il WinJS.Navigation (vedi post precedenti relativi alla Navigazione Utente) e lo abbiamo poi legato, tramite la funzione addEventListener, alla nostra ListView.
Semplice no??? ..eppure però questo approccio ancora una volta lega fortemente la view e la parte di Business.. quindi per evitare ciò potremmo pensare di apportare le seguenti modfiche:


(function () {
    "use strict";
    var nav = WinJS.Navigation;

    function dvContacts_iteminvoked(eventInfo)
    {
        var itemIndex = eventInfo.detail.itemIndex;
        var item = Contacts.items.getAt(itemIndex);
        nav.navigate("/html/contact.html", { item: item });
    }

    function ready(element, options) {
        WinJS.Binding.processAll();
        //dvContacts.addEventListener("iteminvoked", dvContacts_iteminvoked);
    }

    WinJS.UI.Pages.define("/html/homePage.html", {
        ready: ready
    });

    WinJS.Namespace.define("LestViewContactsEvents", {
        itemInvoked: dvContacts_iteminvoked
    });

})();

Ovvero abbiamo definito un namespace che espone un riferimento al nostro handler (LestViewContactsEvents.itemInvoked) cosicché possiamo lato view collegare dichiarativamente l’evento come segue:

<div id="dvContacts"
     data-win-control="WinJS.UI.ListView"
     data-win-options="{ selectionMode: 'single',
                         itemDataSource: Contacts.items.dataSource,
                         itemTemplate: select('#templateContactItem'),
                         oniteminvoked: LestViewContactsEvents.itemInvoked }">
</div>

Bene ma cosa succede ora nella pagina /html/contact.html che riceve i dati??? ..in realtà avevamo già creato la nostra pagina in modo che sapesse come visualizzare un oggetto JSON con la struttura degli item presenti nella nostra lista… così ci basterà semplicemente recuperare l’item passato dalla pagina /html/homePage.html e bindarlo alla view, vediamo come:

(function () {
    "use strict";
    
    WinJS.Namespace.define("Selected", {
        item: null
    });

    function ready(element, options) {
        if (options != null && options.item != null) {
            Selected.item = new WinJS.Binding.as(options.item);
            WinJS.Binding.processAll();
        }
    }

    WinJS.UI.Pages.define("/html/contact.html", {
        ready: ready
    });

})();

Anche qui quindi abbiamo dichiarato un namespace tramite il quale manteniamo un riferimento all’item selezionato (ovviamente il namespace essendo dichiarato nel file contact.js sarà visibile sono nei casi in cui questo file sarà linkato nella view consiglio quindi di dichiarare i namespace specifici per la view nel sorgente della view stessa in modo da non creare confusione) ed lo abbiamo poi valorizzato nell’evento ready con le informazioni recuperate da options che rappresenta, in questo caso, un riferimento all’item passato dalla pagina /html/homePage.html
Per quanto poi riguarda la view avremo il seguente codice:

<h2>Informazioni Contatto</h2>
<div id="divContact" 
     data-win-bindsource="Selected.item">
   <input id="contactName" type="text" data-win-bind="value: name" />
   <br />
   <input id="country" type="text" data-win-bind="value: country" />
   <br />
   <input id="phone" type="text" data-win-bind="value: phone" />
   <br />
   <input id="msn" type="text" data-win-bind="value: msn" />
   <br />
   <input id="skype" type="text" data-win-bind="value: skype" />
</div>

Conclusioni

Bene con questo post abbiamo chiuso il giro del DataBinding, ovviamente questi post rappresentano solo un infarinatura generale per capire come iniziare a lavorare con i dati nelle Metro Style Applications non hanno quindi la pretesa di essere esaustivi… ed inoltre è bello anche sperimentare no?!? 🙂 ..quindi sperimentate, sperimentate, sperimentate…..

Disattivazione, ripristino e terminazione di una Metro Style Application

In questo periodo purtroppo il tempo che ho a disposizione per la scrittura del mio “diario operativo sullo sviluppo di Metro Style Application” – così come l’ho chiamato – e comunque in genere al blog  è veramente minimo, però… – c’è sempre un però! – volevo proporvi la visione di un completissima sessione video tenuta per chanel9 da Paolo Pialorsi relativa alla gestione del ciclo di vita delle Applicazioni Metro Style.

Paolo ci parla quindi di disattivazione, ripristino e terminazione delle applicazioni, di dove come e quando salvare lo stato della nostra applicazione, ma anche di come poter lanciare processi in background, e molto altro ancora…

Come al solito poi il tutto è arricchito da tutta una serie di considerazioni e consigli personali sempre di grande spessore, consglio quindi vivamente la visione del video raggiungibile all’indirizzo: http://channel9.msdn.com/Events/Windows-Camp/Windows-8-Developer-Event-Crea-la-tua-prima-Metro-App/How-and-When-Metro-Style-Apps-Run

Buona Visione!

Metro Style Apps – Data Binding – Terza Parte

Negli ultimi post relativi allo sviluppo di Metro Style Apps con Javascript ed HTML5 ho iniziato a parlare di come possa essere sfruttato il Data Binding nelle Metro Style Apps con un esempio estremamente semplice ma utile allo scopo. In questo e nel prossimo post vorrei approfondire l’argomento completando l’esempio e presentando alcune classi che forniscono una serie di funzionalità interessanti per migliorare l’approccio utilizzato.

Ma dove eravamo arrivati? …nei due post precedenti Metro Style Apps – Data Binding – Prima Parte e Metro Style Apps – Data Binding – Seconda Parte avevamo creato un’applicazione per visualizzare i dati relativi ad una lista di contatti con 2 pagine html homePage.htmlcontact.html (oltre all’ormai consueta default.html).  Avevamo quindi definito tramite la funzione WinJS.Namespace.define una struttura dati nel file /js/data/dataSourceContacts.js (un oggetto JSON contentente le informazioni da gestire) ed in fine tramite l’utilizzo dell’attributo data-win-bind avevamo collegato quest’ultima agli elementi HTML5 della pagina contact.html per visualizzare i dati di uno specifico contatto (utilizzando il data binding dichiarativo). Questa volta vedremo come bindare l’intera lista contatti nella pagina homePage.html e nel prossimo post invece come permettere all’utente di selezionare un contatto dalla lista per visualizzarne i dettagli e come passare informazioni da una pagina all’altra.

Per prima cosa dobbiamo considerare che nelle applicazioni Metro Style possiamo usufruire di una serie di controlli Javascript per assolvere a tutta una serie di operazioni comuni per la gestione della UI.

Nel nostro caso per visualizzare le informazioni della lista contatti tramite l’utilizzo combinato dei controlli WinJS.UI.ListView e WinJS.Binding.Template dove il primo ci permetterà di generare un contenitore in stile ListView per la gestione degli item della lista di contatti (raggruppamento, selezione, ecc..) mentre il secondo di definire un template di visualizzazione per questi ultimi. Prima di poterli utilizzare dovremo però apportare alcune modifiche alla nostra lista contatti, per renderla compatibile con tali controlli (vedi righe di codice evidenziate nel seguente listato)


(function () {
    "use strict";

    var contacts = [
        { name: "Marco Siniscalco", country: "Italy", phone: "Phone 1", msn: "msn.account@hotmail.com", skype: "skype.name" },
        { name: "Mario Rossi", country: "Italy", phone: "Phone 2", msn: "msn2.account@hotmail.com", skype: "skype.name2" },
        { name: "Jane Smith", country: "California", phone: "Phone 3", msn: "msn3.account@hotmail.com", skype: "skype.name3" },
        { name: "Eleonora Plasi", country: "Italy", phone: "Phone 4", msn: "msn4.account@hotmail.com", skype: "skype.name4" },
        { name: "Federico Moro", country: "Italy", phone: "Phone 5", msn: "msn5.account@hotmail.com", skype: "skype.name5" },
        { name: "Armando Simproni", country: "Italy", phone: "Phone 6", msn: "msn6.account@hotmail.com", skype: "skype.name6" },
        { name: "Anna Velio", country: "Italy", phone: "Phone 7", msn: "msn7.account@hotmail.com", skype: "skype.name7" },
        { name: "Paola Moro", country: "Italy", phone: "Phone 8", msn: "msn8.account@hotmail.com", skype: "skype.name8" },
        { name: "Ernesto Doni", country: "Italy", phone: "Phone 9", msn: "msn9.account@hotmail.com", skype: "skype.name9" },
        { name: "Pablo Perez", country: "Spain", phone: "Phone 10", msn: "msn10.account@hotmail.com", skype: "skype.name10" },
        { name: "Davide Porzio", country: "Italy", phone: "Phone 11", msn: "msn11.account@hotmail.com", skype: "skype.name11" }
    ];

    var contactList = new WinJS.Binding.List(contacts);

    WinJS.Namespace.define("Contacts", {
        items: contactList,
        first: contacts[0],
        last: contacts[contacts.length-1]
    });

})();

per ulteriori informazioni su WinJS.Binding.List naviga questo link

A questo punto dobbiamo definire il template da utilizzare per i nostri item e lo facciamo come segue


            <div id="templateContactItem" data-win-control="WinJS.Binding.Template">
                <div class="contacts-list">
                    <div class="item">
                        <h3 data-win-bind="innerText: name"></h3>
                        <span data-win-bind="innerText: phone"></span>
                        (<span data-win-bind="innerText: country"></span>)
                    </div>
                </div>
            </div>

Ovvero creiamo un div html al quale valorizziamo l’attributo data-win-control con il nome del controllo che vogliamo che il nostro div rappresenti in fase di Runtime, all’interno poi del div appena creato inseriremo la struttura html per organizzare le informazioni e facendo uso del databinding (già visto nei posto precedenti) agganciamo i dati dei singoli item.

Quello che abbiamo appena visto però è solo la struttura di un singolo item dobbiamo quindi preparare il contenitore grafico che si riferisca all’intera lista contatti e bindarelo a quest’ultima, ecco come fare


   <div id="dvContacts" 
        data-win-control="WinJS.UI.ListView" 
        data-win-options="{ itemDataSource : Contacts.items.dataSource, itemTemplate: select('#templateContactItem') }">
   </div>

molto semplicemente creiamo un nuovo div, specifichiamo tramite l’attributo data-win-control che desideriamo venga utilizzato per generare un oggetto ListView e poi utilizzando l’attributo data-win-options inizializziamo le sue proprietà (ovvero bindiamo i dati al cotrollo itemDataSource : Contacts.items.dataSource e specifichiamo il template da utilizzare per la visualizzazione degli item itemTemplate: select(‘#templateContactItem’)

L’ultima cosa che ci resta da fare è invocare la funzione WinJS.Binding.processAll nell’evento ready della nostra pagina (nel file /js/views/homePage.js)


(function () {
    "use strict";

    function ready(element, options) {
        WinJS.Binding.processAll();
    }

    WinJS.UI.Pages.define("/html/homePage.html", {
        ready: ready
    });

})();

Lanciamo l’applicazione ed ecco il risultato

Metro Style Apps – Data Binding – Esempio 1.2

Metro Style Apps – Data Binding – Seconda Parte

Nell’ultimo post relativo allo sviluppo di Metro Style Apps con Javascript ed HTML5 ho iniziato a parlare di come possa essere sfruttato il Data Binding nelle Metro Style Apps e di come questo approccio ci aiuti a separare la UI dalle regole di business della nostra applicazione.

L’esempio proposto era comunque estremamente semplice ed introduttivo, avevo infatti definito un’oggetto JSON contenente le informazioni relative ad una lista di ipotetici contatti e successivamente visualizzato le informazioni del primo in lista in una pagina html (contact.html) utilizzando prima un approccio programmatico e successivamente il databinding dichiarativo.

Nel secondo caso siamo riusciti a visualizzare le informazioni del nostro contatto utilizzando esclusivamente la funzione WinJS.Binding.processAll alla quale avevamo passato come primo parametro un riferimento all’elemento HTML di root contenente i campi testuali legati al modello tramite l’utilizzo dell’attributo data-win-bind (specificato direttamente sulla porzione di HTML ad esso relativo) e come secondo paramentro il primo item della nostra lista.

E’ necessario notare però che seppur questo approccio ci aveva permesso di evitare la valorizzazzione di ogni singolo campo dell’interfaccia grafica quest’ultima è ancora notevolmente accoppiata alle regole di business… infatti nel nostro codice abbiamo ancora la necessità di specificare alla funzione WinJS.Binding.processAll un riferimento all’elemento HTML che dovrà visualizzare i dati, vediamo come tramite l’introduzione dell’attributo data-win-bindsource possiamo ovviare a tale problematica.

L’attributo data-win-bindsource viene utilizzato per specificare su di un elemento della nostra UI che esiste un’associazione con una determinat origine dati (nel nostro caso sarà l’istanza di un contatto della lista Contacts). Prima di andare a specificare tale attributo all’interno del nostro codice HTML apportiamo una serie di piccole modifiche alla nostra lista contatti

(function () {
    "use strict";

    var contacts = [
        {
            name: "Marco Siniscalco",
            country: "Italy",
            phone: "Phone 1",
            msn: "msn.account@hotmail.com",
            skype: "skype.name"
        },
        {
            name: "Mario Rossi",
            country: "Italy",
            phone: "Phone 2",
            msn: "msn2.account@hotmail.com",
            skype: "skype.name2"
        },
        {
            name: "Jane Smit",
            country: "California",
            phone: "Phone 3",
            msn: "msn3.account@hotmail.com",
            skype: "skype.name3"
        }
    ];

    WinJS.Namespace.define("Contacts", {
        items : contacts,
        first: contacts[0],
        last: contacts[contacts.length-1]
    });

})();

Le modifiche apportate sono relative esclusivamente al secondo parametro passato alla funzione WinJS.Namespace.define invece di passare direttamente la lista di contatti abbiamo passato un oggetto JSON con tre property

  • items che rappresente l’insieme dei contatti presenti in lista;
  • first che rappresenta un riferimento al primo contatto in lista;
  • last che rappresenta un riferimento all’ultimo contatto in lista.

Attenzione la struttura dell’oggetto Contacts è “una struttura di comodo” definita allo scopo di recuperare più semplicemente le informazioni dalla nostra lista quindi non consiglio l’utilizzo di questo tipo di struttura in un’applicazione reale (nel corso dei prossimi post e con la spiegazione di ulteriori peculiarità delle Metro Style Apps presenterò delle strutture che meglio si adattano allo sviluppo di applicazioni reali).

A questo punto possiamo passare a specificare l’attributo data-win-bindsource all’interno della UI

<h2>Informazioni Contatto</h2>
   <div id="divContact" data-win-bindsource="Contacts.first">
      <input id="contactName" type="text" data-win-bind="value: name" />
      <input id="country" type="text" data-win-bind="value: country" />
      <input id="phone" type="text" data-win-bind="value: phone" />
      <input id="msn" type="text" data-win-bind="value: msn" />
      <input id="skype" type="text" data-win-bind="value: skype" />
</div>

abbiamo quindi specificato che vogliamo associare il primo contatto della lista al div con id “divContact” e possiamo ora eliminare dal file “contact.js” il codice che associava tale div al nostro contatto (ovvero le due righe di codice commentato)

(function () {
    "use strict";

    function ready(element, options) {

        // var contact = Contacts.first;
        // WinJS.Binding.processAll(divContact, contact);
        WinJS.Binding.processAll();

    }

    WinJS.UI.Pages.define("/html/homePage.html", {
        ready: ready
    });

})();

Sarà infatti la funzione WinJS.Binding.processAll, invocata senza parametri, che si occuperà di associare i dati a tutti gli elemente HTML definiti sull’interfaccia per i quali sia stata specificata un’associazione.

Conslusioni

Questa volta abbiamo associato il nostro modello dati alla UI con un approccio al Data Binding completamente dichiarativo, nei prossimi post aprofondirò ulteriorimente la questione e tenterò di spiegare come migliorare le strutture dati bindate alla UI e come visualizzare intere liste di elementi.

Metro Style Apps – Data Binding – Prima Parte

Da diverso tempo ormai Microsoft fornisce ai programmatori .net potenti meccanismi per la gestione del Data Binding e con l’introduzione delle tecnologie WPF e Silverlight tale feature è stata ulteriormente potenziata con la possibilità ad oggi di gestire il Data Binding in modo dichiarativo. Ciò porta un enorme vantaggio nella progettazione di interfacce grafiche passive basate sul concetto di netta separazione della UI dalle regole di business.

Le Metro Style Apps sviluppate con Javascript ed HTML5 sono perfettamente in linea con questo meccanismo, vediamo come ipotizzando di voler sviluppare un’applicazione che visualizzi i dati relativi ad una lista di contatti.

Tra un attimo vedremo due esempi di codice in modo da comprendere le differenze tra una UI che non utilizza il meccanismo di Data Binding dichiarativo ed una che invece ne fa comodo uso.

Innanzitutto creaimo una nuova Metro Style App selezionando come template di progetto Windows Metro Style > Navigation Application (che nel mio caso ho chiamato: Sample.MetroStyle.JavaScript.DataBind).

Creiamo poi nella directory “js”, del progetto, un’ulteriore directory di nome “data” in essa un file “.js” di nome “dataSourceContacts.js”. (all’interno del quale a breve definiremo le strutture che conterranno i dati del nostro modello).

Il nome utilizzato per i file e per le directory non ha nessun influenza sul databinding e sul suo funzionamento.

Per il nostro primo esempio il file “dataSourceContacts.js” sarà così definito

(function () {
    "use strict";

    var contacts = [
        {
            name: "Marco Siniscalco",
            country: "Italy",
            phone: "Phone 1",
            msn: "msn.account@hotmail.com",
            skype: "skype.name"
        },
        {
            name: "Mario Rossi",
            country: "Italy",
            phone: "Phone 2",
            msn: "msn2.account@hotmail.com",
            skype: "skype.name"
        },
        {
            name: "Jane Smit",
            country: "California",
            phone: "Phone 3",
            msn: "msn3.account@hotmail.com",
            skype: "skype.name"
        }
    ];

    WinJS.Namespace.define("Contacts", contacts);

})();

In questo modo abbiamo definito un oggetto JSON, come insieme di contatti, e lo abbiamo registrato con la funzione WinJS.Namespace.define con il nome Contacts.

Ora immaginiamo di voler creare una pagina html che visualizzi le informazioni di un determinato contatto. Innanzitutto aggiungiamo una nuova pagina html di nome “contact.html” (creeremo ovviamente anche i relativi file .css e .js o in alternativa creeremo un item di tipo Page Control che si occuperà di creare tutte le risorse a noi necessarie) alla quale ci ricordiamo di aggiungere un riferiemento al file “dataSourceContacts.js”.
Nel corpo del file “contact.html” aggiungeremo poi il seguente codice HTML contenente una serie di input testuali.


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Contact</title>
    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
    <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
    <link href="/css/contact.css" rel="stylesheet">
    <script src="/js/views/contact.js"></script>
    <script src="/js/data/dataSourceContacts.js"></script>
</head>
<body>
    <div class="contact 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">Welcome to contact</span>
            </h1>
        </header>
        <section aria-label="Main content" role="main">
            
            <div>
                <h2>Contact info</h2>
                <input id="contactName" type="text" />
                <input id="country" type="text" />
                <input id="phone" type="text" />
                <input id="msn" type="text" />
                <input id="skype" type="text" />
            </div>

        </section>
    </div>
</body>
</html>

Ora per questo primo esempio, nell’ottica di non far uso del Data Binding dichiarativo, avremo nel file “contact.js” il seguente listato di codice dove grazie alla funzione “viewContact” viene recuperato il contatto presente in testa alla lista Contacts per compilare programmaticamente la form con le sue informazioni

(function () {
    "use strict";

   function viewContact(index) {

        var contact = Contacts[index];
        contactName.value = contact.name;
        country.value = contact.country;
        phone.value = contact.phone;
        msn.value = contact.msn;
        skype.value = contact.skype;
    };

    function ready(element, options) {

       viewContact(0);
    }

    WinJS.UI.Pages.define("/html/contact.html", {
        ready: ready,
        updateLayout: updateLayout
    });

})();

eseguendo l’applicazione e navigando alla pagina contact.html avremo a video il seguente risultato

Metro Style Apps - Data Binding - Esempio 1

Ora per ottenere lo stesso risultato senza dover valorizzare a mano il contenuto di ogni singolo campo di testo possiamo aggiungere su ognuno di questi l’attributo data-win-bind in modo da specificare che quel determinato capo è legato ad una determinata property relativa al nostro modello di dati che dovrà essere opportunamente bindato alla UI.

Vediamo le modifiche da apportare ai nostri file per ottenere l’effetto desiderato. Innanzitutto marchiamo i nostri campi con l’attributo data-win-bind in questo modo

<h2>Informazioni Contatto</h2>
<div id="divContact">
 <input id="contactName" type="text" data-win-bind="value: name" />
 <input id="country" type="text" data-win-bind="value: country" />
 <input id="phone" type="text" data-win-bind="value: phone" />
 <input id="msn" type="text" data-win-bind="value: msn" />
 <input id="skype" type="text" data-win-bind="value: skype" />
</div>

in pratica tramite l’attributo data-win-bind stiamo specificando a quale property del modello dati è legato il campo di testo e non solo ma anche quale attributo del campo dovrà essere valorizzato con tale informazione.

Per quanto riguarda il nostro file “/js/views/contact.js” dovremo modificare solo il corpo della funzione “viewContact” come mostrato di seguito

   function viewContact(index) {
        var contact = Contacts[index];
        WinJS.Binding.processAll(divContact, contact);
    };

In pratica la funzione WinJS.Binding.processAll si preoccupa di effettuare l’associazione di tutti i controlli presenti all’interno del div “divContact” (che funge da root) che utilizzano l’attributo data-win-bind con i relativi valori del modello dati.

Conclusioni

Abbiamo visto come agganciare i dati del nostro modello alla UI dell’applicazione in un caso estremamente semplice… nel prossi post analizzeremo come aggiornare l’interfaccia grafica dell’applicazione nel caso in cui lo stato del nostro modello dovesse cambiare poi successivamente analizzeremo un esempio di Data Binding più complesso 🙂

Metro Style Apps – La Navigazione Utente – Terza Parte

In questo post scopriremo finalmente il contenuto del file navigator.js per comprendere i dettagli implementativi della navigazione utente delle Metro Style Apps.

Per semplicità, essendo il file abbastanza lungo, lo analizzeremo per piccole porzioni di codice.

In testa al file troviamo le dichiarazioni di alcune variabili di classe

(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;

subito dopo viene definito un nuovo namespace di nome “Navigation” (il template di progetto utilizza il nome del progetto per specificare tale namespace) tramite la funzione WinJS.Namespace.define  alla quale è possibile passare come secondo parametro l’implementazione di una o più classi che saranno aggiunte al namespace creato, in questo caso specifico il secondo parametro è l’mplementazione di una nuova classe “PageControlNavigator” (creata tramite la funzione WinJS.Namespace.define) ovvero l’implementazione vera e propria del nostro navigator

   WinJS.Namespace.define("Navigation", {
       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);
           },

Il costruttore della classe PageControlNavigator accetta 2 parametri il primo è un riferimento al div contenitore, nel quale saranno ospitate le pagine che navigheremo, mentre il secondo è un’oggetto JSON contenente un insieme di valori di configurazione che potranno essere specificati direttamente sul div tramite l’attributo data-win-options. Come si può notare viene creato un div contenitore, nel caso questo non sia stato passato correttamente al costruttore, e successivamente viene aggiunto a quest’ultimo un altro div come figlio che conterà gli elementi della pagina navigata (il secondo div viene generato tramite la funzione _createPageElement)

              {
               // 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;
               },

Subito dopo viene valorizzata la variabile pubblica this.home con il valore contenuto dell’omonima property del parametro options passato al costruttore e vengono poi agganciati gli eventi onnavigated (per WinJS.Navigation) e onviewstatechanged (per Windows.UI.ViewManagement.ApplicationView) con le due funzioni:

  • _navigated che si occuperà di aggiornare i controlli di navigazione ad ogni passaggio di pagina.
  • _viewstatechanged che aggiornerà le informazioni relative allo stato della vista corrente.

Vengono poi agganciati anche gli eventi onkeyup ed onkeypress del body con:

  • _keyupHandler che gestirà la navigazione alla pressione dei tasti Left, Right e BrowserBack.
  • _keypressHandler che gestirà la navigazione alla pressione del tasto BackSpace quando viene utilizzato al di fuori dei campi di input.

               // 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();
                   }
               },

poi arriviamo alla funzione più importante ovvero quella che permette effettivamente il cambio di pagina ovvero dove quest’ultima verrà finalmente renderizzata tramite una richiesta asincrona (la richiesta asincorna viene gestita tramite WinJs.Promise una classe che fornisce un’astrazione per la gestione delle interazioni con le API asincrona che approfondiremo in post successivi a questo).


               // 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();
                       });
               },

Infine, tornando al costruttore, viene invocata la funzione navigate per far si che venga caricata la pagina specificata come home dell’applicazione.

Il resto delle funzioni implementate nel file si spiegano quasi da sole grazie anche all’aiuto dei commenti inseriti nel sorgente


               // 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);
           }
       },
   });
})();

A questo punto il codice che avevamo visto non funzionare nel post Metro Style Apps – La Navigazione Utente finalmente sarà eseguito senza problemi 😉