Le modal dialog sono uno strumento molto usato nelle applicazioni per interagire con l’utente. Purtroppo, mentre in una applicazione Windows esse sono tutto sommato semplici da gestire dato che il framework ci mette a disposizione più o meno tutto ciò di cui abbiamo bisogno, così non è nelle applicazione web in cui abbiamo solo alert e confirm che sono quanto di meno user friendly si possa immaginare. Inoltre, inserire delle proprie dialog è più o meno complicato in quando richiede non solo l’inserimento del codice Javascript che le gestisce, ma anche sel markup HTML. Un doppio lavoro quindi che complica non poco la questione. Personalmente ho trovato molto proficuo usare un servizio di AngularJS, scritto in Typescript, per cercare di risolvere questo problema alla radice. Per farlo mi sono appoggiato alle Modal popop di bootstrap che sono semplici ed efficaci e gestiscono molto efficacemente la responsività. Vediamo il servizio come è realizzato:

   1: module sys.services
   2: {
   3:     export class Constants
   4:     {
   5:         static containerId: string = '#modalContainer';
   6:         static defaultModalTitle: string = 'Message';
   7:         static modalDialogId: string = '#modalDialog';
   8:     
   9:         static Negative: string = '0';
  10:         static Positive: string = '1';
  11:         static Cancel: string = '2';
  12:     
  13:         static modalYesNo: sys.services.IDialogCommand[] = [
  14:             { id: Constants.Negative, text: 'No' },
  15:             { id: Constants.Positive, text: 'Yes', style: 'btn-primary' }];
  16:         static modalYesNoCancel: sys.services.IDialogCommand[] = [
  17:             { id: Constants.Cancel, text: 'Cancel' },
  18:             { id: Constants.Negative, text: 'No' },
  19:             { id: Constants.Positive, text: 'Yes', style: 'btn-primary' }];
  20:         static modalOkCancel: sys.services.IDialogCommand[] = [
  21:             { id: Constants.Cancel, text: 'Cancel' },
  22:             { id: Constants.Positive, text: 'Ok', style: 'btn-primary' }];
  23:     
  24:         static containerMarkup: string =
  25:         '<span></span>';
  26:         static modalMarkup: string =
  27:         '<div id="modalDialog" class="modal fade"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h4 class="modal-title">Modal title</h4></div><div class="modal-body"><p>One fine body&hellip;</p></div><div class="modal-footer"></div></div></div></div>';
  28:         static modalButtonMarkup: string =
  29:         '<button type="button" class="btn" data-dismiss="modal">Close</button>';
  30:     }
  31:     
  32:     export interface IDialogCommand
  33:     {
  34:         id: string;
  35:         text: string;
  36:         style?: string;
  37:     }
  38:  
  39:     export class ModalManager
  40:     {
  41:         private container: JQuery;
  42:         private modalDialog: JQuery;
  43:  
  44:         constructor()
  45:         {
  46:             this.appendModals();
  47:         }
  48:  
  49:         private exists(name: string): boolean
  50:         {
  51:             if (this.container == undefined)
  52:                 this.container = $(Constants.containerId);
  53:  
  54:             return this.container.find(name).length != 0;
  55:         }
  56:  
  57:         private appendModals(): void
  58:         {
  59:             if (!this.exists(Constants.containerId))
  60:             {
  61:                 this.container = $(Constants.containerMarkup);
  62:                 this.container.appendTo($(document.body));
  63:             }
  64:  
  65:             if (!this.exists(Constants.modalDialogId))
  66:             {
  67:                 this.modalDialog = $(Constants.modalMarkup);
  68:                 this.modalDialog.appendTo(this.container);
  69:             }
  70:         }
  71:  
  72:         public showDialog(message: string, title: string = Constants.defaultModalTitle, commands?: IDialogCommand[], callback?: (id: string) => void)
  73:         {
  74:             this.modalDialog.find('.modal-body').text(message);
  75:             this.modalDialog.find('.modal-title').text(title);
  76:  
  77:             var footer = this.modalDialog.find('.modal-footer');
  78:             footer.empty();
  79:  
  80:             for (var i in commands)
  81:             {
  82:                 var cmd = commands[i];
  83:  
  84:                 var button = $(Constants.modalButtonMarkup);
  85:  
  86:                 button.text(cmd.text);
  87:                 button.addClass(cmd.style == undefined ? 'btn-default' : cmd.style);
  88:                 button.data('command-id', cmd.id);
  89:  
  90:                 button.click((ev) =>
  91:                 {
  92:                     var id = $(event.srcElement).data('command-id');
  93:  
  94:                     this.modalDialog.modal('hide');
  95:  
  96:                     if (callback != undefined)
  97:                         callback.apply(this, [id]);
  98:                 });
  99:  
 100:                 button.appendTo(footer);
 101:             }
 102:  
 103:             this.modalDialog.modal('show');
 104:         }
 105:     }
 106: }

Il servizio così impostato è completo di tutto ciò che serve al funzionamento. Da solo per scontato che siano reparibili le librerie suddette (AngularJS e Bootstrap). Il metodo appendModals() in particolare si occupa di creare il markup necessario utilizzando alcune stringhe costanti. Esso verifica che il markup non sia già presente ed eventualmente lo inserisce aggiungendolo al body. Questo favorisce l’utilizzo della libreria che non richiede alcuna gestione del markup HTML. L’utilizzo è molto semplice. E’ sufficiente infatti registrare il servizio assieme al controller con la seguente riga:

   1: .service('$modalManager',
   2:     () => new sys.services.ModalManager());

Avremo così a disposizione il servizio $modalManager che possiamo iniettare in un controller. A questo punto, potremo richiamare la gdialog molto semplicemente usando uno dei metodi del servizio:

   1: this.$modalManager.showDialog(
   2:     'Are you sure you want to delete the resource',
   3:     'Confirm operation',
   4:     sys.Constants.modalYesNo,
   5:     (id: string) =>
   6:     {
   7:         if (id == sys.Constants.Positive)
   8:         {
   9:             this.clocks.push(timezone);
  10:         }
  11:  
  12:         this.selectedTimezone = undefined;
  13:         this.scope().$apply();
  14:     });

La dialog è sufficientemente intelligente da gestire numerose combinazioni di pulsanti. Le costanti presenti nella dichiarazione sono di aiuto in questo ma se ne possono creare di proprie dato che si tratta a tutti gli effetti di un array di IDialogCommand.

   1: static modalOkCancel: sys.services.IDialogCommand[] = [
   2:     { id: Constants.Cancel, text: 'Cancel' },
   3:     { id: Constants.Positive, text: 'Ok', style: 'btn-primary' }];

Senza dimenticare l’uso appropriato degli stili di bootstrap.


E' di questi giorni l'annuncio che Angular 2.0 è ora completamente scritto in Typescript. Questo è forse uno dei più sorprendenti risultati della politica di Satya Nadella che sta aprendo giorno dopo giorno alle librerie open source di terze parti. E ancora più sorprendente se pensiamo che Angular è un prodotto dei team di Google che recentemente, supportato da Microsoft ha deciso di adottare questo linguaggio. La cosa che più mi entusiasma, come riportato in questo post, è che la collaborazione sarà fonte di nuovi miglioramenti per Typescript che già dalla versione 1.5 vedrà l'introduzione delle annotations, espressamente progettate per Angular. Le annotation apriranno la strada a una sorta di Reflection che tipicamente è fonte di numerose soluzioni che risparmiano lavoro. Attendiamo con ansia...


L'asincronia sta ormai diventando una questione di tutti i giorni nelle applicazioni moderne così i linguaggi come C# si sono adeguati con costrutti come async/await. Javascript, pur essendo un linguaggio ormai antico secondo i tempi cui l'informatica ci ha abituato, gestisce da sempre molte attività in modo asincrono, utilizzando il meccanismo dei callback. Un esempio è il setInterval in cui uno degli argomenti passati è la funzione da chiamare ad intervalli regolari.

Librerie come jQuery e Angular stesso espongono numerosi casi di utilizzo di metodi asincroni. L'http service di Angular ad esempio è uno di questi casi. Esso però non utilizza normali callback ma un sistema molto simile al Task<T> di C#. Le promise. In effetti da ciascuna chiamata asincrona è ritornato un oggetto Promise che dispone dei metodi then, catch e finally. Questi servono per associare un callback a ciascuno delle condizioni che i nomi dei metodi evocano.

Ma la domanda cui vogli rispondere in questo post è la seguente: come faccio ad esporre una promise da un mio metodo asicrono se esso stesso no usa un servizio che la utilizzi? E' il caso ad esempio di un metodo che visualizzi una dialog modale. Essono mo potrà mai essere sincrono perchè oltre a risultare bloccante per il browser, non sarà comunque possibile gestire una eventuale "attesa" e ritornare dal metodo alla chiusure della dialog. Quello che ci viene in soccorso è il Q service. Esso è usato dallo stesso http service è ha come unico scopo la gestione asincrona. Vediamo un esempio:

   1: public showDialog(message: string, title: string = Constants.defaultModalTitle, commands?: IDialogCommand[]): ng.IPromise<string>
   2: {
   3:     var defer: ng.IDeferred<any> = this.$q.defer<string>();
   4:  
   5:     try
   6:     {
   7:         this.modalDialog.find('.modal-body').text(message);
   8:         this.modalDialog.find('.modal-title').text(title);
   9:  
  10:         var footer = this.modalDialog.find('.modal-footer');
  11:         footer.empty();
  12:  
  13:         for (var i in commands)
  14:         {
  15:             var cmd = commands[i];
  16:  
  17:             var button = $(Constants.modalButtonMarkup);
  18:  
  19:             button.text(cmd.text);
  20:             button.addClass(cmd.style == undefined ? 'btn-default' : cmd.style);
  21:             button.data('command-id', cmd.id);
  22:  
  23:  
  24:             button.click((ev) =>
  25:             {
  26:                 var id = $(event.srcElement).data('command-id');
  27:                 this.modalDialog.modal('hide');
  28:                 defer.resolve(id);
  29:             });
  30:  
  31:             button.appendTo(footer);
  32:         }
  33:  
  34:         this.modalDialog.modal('show');
  35:     }
  36:     catch (error)
  37:     {
  38:         defer.reject(error);
  39:     }
  40:  
  41:     return defer.promise;
  42: }

Diamo per assodato che questo metodo faccia capo ad una classe che ha ricevuto una istanza del Q service come argomento del costruttore. Come segue:

   1: constructor(private $q: ng.IQService)
   2: {
   3: }

Il metodo showDialog al proprio inizio crea una istanza di una classe di tipo IDeferred<any>, dove any è il tipo del valore ritornato dal metodo in questione. L'oggetto deferred è quello che ci serve per gestire l'asincronia. Al termine del metodo infatti viene ritornata la promise che esso contiene con "defer.promise".

A questo punto è necessario invocare i callback di successo (then) e quello di fallimento (catch). Per farlo sono utilizzati i metodi "resolve" e "reject" dell'oggetto deferred.

Così facendo è possibile usare il metodo come segue:

   1: this.showDialog(
   2:     'Are you sure you want to delete the item',
   3:     'Confirm operation',
   4:     sys.Constants.modalYesNo).then(
   5:         (id: string) =>
   6:         {
   7:             if (id == sys.Constants.Positive)
   8:             {
   9:                 // delete the item here
  10:             }
  11:         });

Il sistema è l'unico consigliato. Infatti l'utilizzo dei callback normali crea problemi al sistema di databinding di AngularJS. Invece il q service è perfettamente in grado di supportarlo.


Spesso può risultare molto comodo caricare una porzione di html dal server, magari generata da una partial view di ASP.NET MVC (o magari proprio da una View, perchè no?). con angular questo è del tutto possibile grazie alla direttiva ng-include che consente di specificare l'url da cui  caricare una risorsa all'interno della pagina. Vediamo un esempio con typescript:

Per prima cosa si crea una partialview  che dimostri un po' di dinamismo. Ecco un semplice esempio:

   1: <h2>@DateTime.Now.ToLongDateString()</h2>
   2: <h3>@DateTime.Now.ToLongTimeString()</h3>

In seguito aggiungiamo al controller il codice per poterla chiamare dal browser:

   1: public ActionResult _PartialContent()
   2: {
   3:     return PartialView();
   4: }

A questo punto diciamo che l'url per raggiungere la partial view sia il seguente:

/Include/_PartialContent

Creaiamo quindi un controller come segue:

   1: class IncludeController
   2: {
   3:     count: number = 0;
   4:     includeUri: string = undefined;
   5:  
   6:     click(): void
   7:     {
   8:         this.includeUri = '../Include/_PartialContent?ts=' + (++this.count).toString();
   9:     }
  10: }
  11:  
  12: angular.module('include', ['ngRoute'])
  13:     .controller('includeIndex', IncludeController);

Nel controller usiamo una variabile "count" per tenere conto delle volte in cui l'utente clicca il pulsante di test. Questo valore viene accodato all'uri della partial-view per forzarne il caricamento a ciascun click. L'uri così calcolato viene riposto nella proprietà includeUri. Vediamo ora la view:

   1: @{
   2:     ViewBag.Title = "Test Include";
   3: }
   4: <div>
   5:     &nbsp;
   6: </div>
   7: <div ng-app="include" ng-controller="includeIndex as ct" class="row">
   8:     <form>
   9:         <button type="button" class="btn btn-primary" ng-click="ct.click();">Click Me!</button>
  10:         <p ng-show="ct.count>0">clicked {{ct.count}} times</p>
  11:         <div ng-include="ct.includeUri"></div>
  12:     </form>
  13: </div>
  14: @section Scripts {
  15:     <script src="~/Scripts/Views/Include/index.js"></script>
  16: }

Niente più di un normale binding, con un pulsante per invocare la funzione click(), la visualizzazione del count e l'assegnazione della direttiva ng-include sulla variabile includeUri. Il risultato è che la partial view viene inclusa all'interno delle pagina ogni volta che clicchiamo il pulsante.

Interessante notare che mediante questa tecnica possiamo agevolmente caricare nella pagina qualunque tipo di file il server sia in grado di servire. Se ad esempio all'url della partial sostituiamo quello del file TS vedremo apparire il codice.


Sempre più spesso, nelle moderne applicazioni web, il codice Javascript di una pagina ha la necessità di accedere ad una webapi. Questo è certamente il più semplice metodo per attivare la pagina caricando informazioni dal server senza necessariamente effettuare il refresh dell'intera pagina. La chiamata può essere necessaria per riempire una semplice dropdowlist il cui contenuto dipende da qualche altro valore impostato in una form, piuttosto che una lista di risultati di una ricerca. Qualunque sia il contenuto, l'operazione è sempre quella di richiemare un metodo di una webapi e in seguito alla risposta deserializzare il json per popolare l'interfaccia utente.

In casi come questi ho trovato molto utile usare una classe proxy, mimando quello che avviene in C# quando si interroga un servizio WCF. La cosa interessante è che le WebApi mettono a disposizione di un ApiExplorer che è in grado di fare l'inspect della api stessa e restituire tutti i dettagli quali i metodi, i loro parametri, tipi di ritorno etc.. Grazie ad esso è possibile scrivere il seguente metodo:

   1: public abstract class ApScriptableController : ApiController
   2: {
   3:     /// <summary>
   4:     /// Il metodo restituisce lo script Javascript che consente di interrogare il controller
   5:     /// </summary>
   6:     /// <returns>Ritorna il </returns>
   7:     [HttpGet]
   8:     public HttpResponseMessage GetScript()
   9:     {
  10:         ApiExplorer explorer = new ApiExplorer(this.Configuration);
  11:  
  12:         StringBuilder builder = new StringBuilder();
  13:  
  14:         builder.Append("var __extends = this.__extends || function (d, b) {");
  15:         builder.Append("    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];");
  16:         builder.Append("    function __() { this.constructor = d; }");
  17:         builder.Append("    __.prototype = b.prototype;");
  18:         builder.Append("    d.prototype = new __();");
  19:         builder.Append("};");
  20:  
  21:         var actions = (from api in explorer.ApiDescriptions
  22:                        where  api.ActionDescriptor.ControllerDescriptor.ControllerType.IsAssignableFrom(this.GetType())
  23:                        orderby api.ActionDescriptor.ActionName ascending
  24:                        select api).ToArray();
  25:  
  26:         if (actions.Count() > 0)
  27:         {
  28:             string controllerName = actions.First().ActionDescriptor.ControllerDescriptor.ControllerName;
  29:             controllerName = controllerName.Substring(0, 1).ToUpper() + controllerName.Remove(0, 1);
  30:  
  31:             builder.AppendFormat("var {0}Proxy = (function (_super) {{", controllerName);
  32:             builder.AppendFormat("    __extends({0}Proxy, _super);", controllerName);
  33:             builder.AppendFormat("    function {0}Proxy(baseUri, accessToken, context) {{", controllerName);
  34:             builder.Append("        _super.call(this, baseUri, accessToken);");
  35:             builder.Append("        this.context = context;");
  36:             builder.Append("    }");
  37:  
  38:             foreach (var item in actions)
  39:             {
  40:                 builder.AppendFormat("    {1}Proxy.prototype.{0} = function (value) {{", item.ActionDescriptor.ActionName, controllerName);
  41:                 builder.AppendFormat("        return _super.prototype.callApi.call(this, '{0}', value, this.context);", item.RelativePath);
  42:                 builder.Append("    };");
  43:             }
  44:  
  45:             builder.AppendFormat("    return {0}Proxy;", controllerName);
  46:             builder.Append("})(sys.net.Proxy);");
  47:         }
  48:  
  49:         var response = new HttpResponseMessage(HttpStatusCode.OK);
  50:         response.Content = new StringContent(builder.ToString(), Encoding.UTF8, "text/javascript");
  51:         return response;
  52:     }
  53: }

Il codice rappresenta una classe base da utilizzare per i controller delle WebApi. Essa implementa un metodo GetScript che non fa altro che ispezionare i metodi della api stessa e genera di conseguenza un codice Javascript che rappresenterà il proxy della WebApi. In coda al metodo, le ultime righe cambiano il content-type della risposta impostandolo e text/javascript. In questo modo sarà possibile fornire l'url della api ad un tag script e di conseguenza far leggere il codice e caricarlo nel browser.

   1: <script src="~/api/Home/getscript"></script>

L'ultimo tassello di questo piccolo puzzle è una classe Typescript che rappresenta la base per il proxy Javascript. Il codice generato infatti fa uso delle funzioni e dei tipi presenti in questo breve snippet.

   1: module sys.net
   2: {
   3:     // represents a base for api responses
   4:     export interface IApiResponseBase 
   5:     {
   6:         HasErrors: boolean
   7:         Message: string;
   8:     }
   9:  
  10:     // represents a successful response from an api
  11:     export interface IApiResponse<T> extends IApiResponseBase
  12:     {
  13:         Result: T;
  14:     }
  15:  
  16:     export class Proxy 
  17:     {
  18:         // creates and initializes the proxy with the given base uri
  19:         constructor(private baseUri: string, private accessToken: string)
  20:         { }
  21:  
  22:         // calls a generic API with the specified route and argument
  23:         public callApi<T>(route: string, argument: any, context?: string): JQueryPromise<T>
  24:         {
  25:             var uri = this.baseUri + route;
  26:  
  27:             return $.Deferred(
  28:                 (deferred: JQueryDeferred<T>) =>
  29:                 {
  30:                     $.ajax({
  31:                         url: uri,
  32:                         type: 'POST',
  33:                         data: JSON.stringify(argument),
  34:                         contentType: 'application/json; charset=utf-8',
  35:                         beforeSend: (xhr) =>
  36:                         {
  37:                             xhr.setRequestHeader('Authorization', 'Bearer ' + this.accessToken);
  38:  
  39:                             if (context != undefined)
  40:                                 xhr.setRequestHeader('X-Tsf-Context', context);
  41:                         }
  42:                     })
  43:                         .done(
  44:                         (retVal: IApiResponse<T>) =>
  45:                         {
  46:                             if (retVal.HasErrors)
  47:                                 deferred.reject(retVal);
  48:                             else
  49:                                 deferred.resolve(retVal.Result);
  50:                         })
  51:                         .fail((err: any) => deferred.reject(this.mapToError(uri, err)));
  52:                 }).promise();
  53:         }
  54:  
  55:         // maps any error information to a common object
  56:         private mapToError(uri: string, err: any): IApiResponseBase
  57:         {
  58:             return <IApiResponseBase>
  59:                 {
  60:                     Message: 'Api "' + uri + '" reported an error: ' + err.statusText,
  61:                     HasErrors: true
  62:                 };
  63:         }
  64:     }
  65: }

Una volta che il codice sia caricato nell'ordine corretto, avremo a disposizione una classe che riporta il nome del controller seguito dalla parola Proxy. Perciò se il controller ha il nome "Home" il proxy sarà "HomeProxy".

   1: var proxy = new HomeProxy(sys.Application.ServiceUri, sys.Application.AccessToken, sys.Application.Context);
   2: proxy.GetValuesForList()
   3:     .done((result) =>
   4:      {
   5:         // TODO: process here
   6:      });

Il proxy fa uso delle promise di jQuery perciò il suo utilizzo è molto semplice e gestisce perfettamente la asincronicità.


Capita talvolta (spesso in effetti), che quando entrate in una pagina in cui sia utilizzato AngularJS per una frazione di secondo appaiano le notazioni del binding che spariscono poco dopo quando il databinding viene applicato. Questo accade perchè in quella frazione di secondo in cui il browser scarica il codice e avvia angular, tutte quelle parentesi graffe sono niente più che semplice testo e in gran parte esse sono visualizzate dal browser perchè occupano posizioni "visibili".

Per evitare questo comportamento viene in aiuto la direttiva ng-Cloak. Essa, come testimonia la documentazione ha proprio lo scopo di applicare un "display:none" agli elementi, e questo funzione nella maggioranza dei casi. Tuttavia anche se applichiamo la direttiva ng-Cloak (ad esempio al body per generalizzare, ma anche ad un singolo elemento come invece è consigliabile) talvolta le graffe appaiono comunque. Questo è imputqabile al medesimo ritardo. Per evitarlo è opportuno aggiungere al proprio css il seguente:

   1: [ng\:cloak], [ng-cloak], .ng-cloak {
   2:   display: none !important;
   3: }

In questo modo il CSS cercherà tutti gli elementi con l'attributo ng-Cloak e li nasconderà automaticamente.

Il trick è spiegato più estensivamente qui: http://stackoverflow.com/questions/11249768/angularjs-ng-cloak-ng-show-elements-blink


Ho sempre avuto l’insana convinzione che fosse meglio vivere, sempre e invariabilmente, scommettendo il possibile contro il probabile. Questo perchè in definitiva il probabile esiste e basta… è probabile, e quindi serve il minimo sforzo perchè di verifichi, ma da esso non ti puoi aspettare sorprese, niente di positivo, niente che faccia evolvere la tua situazione in meglio, niente che sia in più rispetto a quello che tutti si aspettano. Il probabile è il minimo sindacale, è l’oppressore che vince sull’oppresso, è lo stesso quotidiano tutti i giorni, è il latte consegnato all’uscio, quello che non ti fa “mandare dalla mamma”.

Il possibile invece è creativo. Lui non esiste e te lo devi costruire, pezzo per pezzo, con fantasia e immaginazione. Il possibile in realtà sono i tuoi sogni, quelli che fai mentre guidi sulla via del ritorno dall’ufficio, e che tutti il più delle volte archiviano dicendo… “ah, impossibile!”.

Alla fine il probabile è una vacanza in una comune località di mare dove il massimo che ti puoi aspettare è che un ombrellone sia un po’ fuori posto. Arriva il bagnino, lo sistema e tutto torna nell’ambito della semplice probabilità. Il possibile invece è una settimana in barca, alla scoperta di angoli del mondo che nemmeno ti aspettavi potessero esistere, pieno del colore, del profumo e delle sensazioni che mai avresti immaginato.

Il problema è che mentre il probabile non ti delude mai, dato che non ti da nulla, il possibile è armato di scimitarra ed è pronto, in ogni istante, a menarti un fendente che ti lascia tramortito. Succede, spesso, che inseguendo il possibile si rimanga trafitti, bastonati, delusi e tramortiti, ma alla fine ne vale sempre la pena. Vale la pena il sapere di aver fatto qualcosa che ti ha cambiato o che ha cambiato, sentire la soddifazione di essere riusciti a lasciare un segno, a migliorare le cose, a… a… a… … anche se il prezzo il da pagare il più delle volte è lo stare male perchè il probabile ha vinto ancora una volta.

Già, impossibile… tutti invariabilmente lo hanno detto almeno una volta, i più se lo dicono sempre con insistenza. Il risultato è l’aver dovuto archiviare con una sola parola un sogno, e aver chiuso un libro di speranze senza nemmeno provare a renderlo concreto. Anche io spesso, ma mai volentieri, cedo al probabilismo, alla tentazione della uniformità e prevedibilità. Ma spesso, soprattutto se mi fermo a pensarci, allora il possibile mi illumina e braccio a braccio al mio ottimismo mi guida alla scoperta di aspetti e possibilità che nemmeno osavo esprimere.

Lasciamo la noia a quei dannati probabilisti. La vita sta nel possibile.


mvplogoPrimo luglio, la calura, l'estate che arriva e anche quest'anno come da otto a questa parte è arrivata l'attesissima mail, regalandomi un'emozione cui non sono ancora riuscito ad abituarmi. MVP Windows Platform Development.

MVP ancora una volta, parte di questa straordinaria community di persone che condivisono la passione per la tecnologia, la condivisione della conoscenza e il lavoro, quello pratico, "sul pezzo", a risolvere problemi e a escogitare soluzioni.

Ma un ricordo particolare va a Silverlight. Ho avuto l'onore di essere il primo italiano ad entrare nella categoria MVP su questa tecnologia e sono anche l'ultimo che la lascia. Abbiamo ormai tutti digerito i motivi che hanno portato alla trasformazione di questo splendido strumento in quello che oggi vediamo in Windows 8 e in Windows Phone... è tutta farina che viene da quella splendida esperienza. E ora Windows Platform Development ne è la logica conclusione.

Grazie. Grazie a tutti, in particolare a Cristina Gonzalez Herrero e Marjorie di Clemente che si occupano del programma per l'Italia. Grazie a Microsoft Italia, Grazie al nostro "sommo" lead Alessandro Teglia :) e in definitiva grazie a Microsoft.

E naturalmente Grazie e tutti quelli che ci seguono, nei nostri eventi, e che ci scrivono e leggono ogni giorno.

tags: - categories: News

Sabato ho avuto il piacere di partecipare alla Fiera del Radioamatore, nello spazio dedicato a Windows, e presentare una sessione sulle novità in ambito Windows Phone 8.1. Oggetto della presentazione sono state in particolare le novità anticipate durante la recente BUILD in cui è stato evidenziato come la piattaforma sta convergendo verso una quasi totale sovrapposizione con il Windows Runtime di Windows 8.1.

Ne approfitto per ringraziare 1nn0va nella persona di Marco Parenzan per l’ottima organizzazione dell’evento che ha visto tre giorni di sessioni articolate e gli amici di dotnettoscana che con noi hanno lavorato per preparare il materiale e le sessioni.
Speriamo che il prossimo anno si possa migliorare ancora questo appuntamento che merita una giusta attenzione dal pubblico, che sono certo arriverà sempre più numeroso se messo a conoscenza di questi argomenti innovativi.

logo_xedotnetCi siamo, dopo lunghi preparativi è finalmente pubblico il prossimo One Day Mobile 2014, un evento di una intera giornata, con ben 7 talk a proposito dello sviluppo mobile in ambito Microsoft. Sarà una ghiotta occasione di condividere esperienze pratiche e novità, in un ambito in cui la velocità di sviluppo è la chiave del successo. Avremo quindi sessioni ad ampio spettro, sia su Windows Phone e Windows 8, ma anche su argomenti cross-platform come Xamarin e PhoneGap. 

L'evento si terrà il prossimo 15 Maggio 2014 presso il Novotel Castellana di Venezia Mestre e vedrà la seguente agenda:

Andrea Dottor: App connesse con ASP.NET Web API

Realizzare applicazioni connesse può fare la differenza in un mercato in pieno sviluppo.
Aggiornare i dati di un catalogo, caricare/leggere gli score di un gioco, interfacciarsi con applicazioni/database esistenti...tutti validi motivi per non perdervi questa sessione, dove vedremo come sviluppare servizi ASP.NET Web API che implementino l'OAuth2 authentication ed OData, e vedremo come poterli consumare da applicazioni Windows Phone, Windows Store App e Xamarin App.

Andrea Boschin: Condivisione del codice tra W8 e WP8

Lo sviluppo mobile richiede sempre più spesso di fornire applicazioni che siano disponibili su diversi device, siano essi Windows Phone o Windows 8, sfruttando le peculiarità di ciascuno. Questo pone il problema di scrivere codice che possa in qualche modo essere riutilizzato su piattaforme che pur essendo simili hanno diversità marcate. In questa sessione vedremo alcune tecniche che possono aiutare nel migliorare la condivisione del codice quando si sviluppano applicazioni per questi sistemi.

Mirco Vanini: C++ in Windows Phone Apps

In questa sessione vedremmo una panoramica degli strumenti messi a disposizione per lo sviluppo nativo su Windows Phone 8. Verrà posta particolare attenzione al suo utilizzo per lo sviluppo di applicazioni ibride (C#/C++) che hanno la necessità di riutilizzare algoritmi sviluppati su piattaforme desktop.

Davide Vernole: Xamarin do it better!

Xamarin offre un’alternativa al “Write Once, Run Anywhere Approach” permettendo agli sviluppatori di realizzare applicazioni per le principali piattaforme mobile garantendo interfacce utente native, performance native e condivisione del codice tra le diverse piattaforme utilizzando C#, il .NET Framework e Visual Studio. Lo "Xamarin Unique Approach" è il filo conduttore di questa sessione in cui impareremo a conoscerlo meglio. Sfruttate conoscenze, potenzialità e sintassi di C# per ottenere il meglio dalle vostre applicazioni cross-platform; ovviamente con Xamarin!

Lorenzo Barbieri: Architettura WP8

Davide Senatore: PhoneGap & Cordova: building cross platform mobile applications

In questa sessione parleremo di sviluppo mobile cross platform con PhoneGap (AKA Cordova).
Prenderemo in esame tool, skill richieste per iniziare e best practice per non incorrere in spiacevoli scoperte.
Scopriremo come l'investimento in "poche" tecnologie standard possa abilitarci allo sviluppo su tutte le piattaforme mobile al momento disponibili.
Non ultimo, confronteremo anche pro, contro e costi di sviluppo di una soluzione di questo tipo con una soluzione nativa ed una soluzione web-based, prendendo in esame applicazioni realmente sviluppate.

Marco Dal Pino: Sviluppare e pubblicare applicazioni Gestionali (LOB) con Windows Phone

La piattaforma Windows Phone ha raggiunto una buona diffusione di mercato e sempre più si sente la necessità di implementare funzionalità gestionali utilizzando i device WP8. Inoltre la prossima versione di Windows Embedded 8 Handheld sarà basata proprio su Windows Phone, introducendo nuovi device industriali rugged con caratteristiche di lettura barcode o Carte magnetiche; il tutto già compreso nativamente nelle API di Windows Phone. Vediamo come affrontare lo sviluppo di queste applicazioni, quali tipici problemi vanno affrontati e come distribuire il prodotto ai nostri clienti.

Inutile dire che vi aspettiamo numerosi. Non aspettate a riservare la vostra poltrona perchè i posti sono davvero limitati.

https://communitydevtool.microsoft.it/public/frmRegister.aspx?eventid=1203PSOSREGTFTMLKGCQHT