Technology Experience

Autore: Igor Damiani

.NET WorldVisualStudioTips.net

[Ammy.3] Primi passi con MVVM

Come ho raccontato nel mio ultimo post dedicato a questa serie, preferisco continuare a raccontarvi il linguaggio Ammy usando un progetto il più possibile reale, motivo per cui ho creato questo repository sull’account GitHub di Brain-Sys, che potete tranquillamente clonarvi sul vostro PC:

https://github.com/Brain-Sys/FsxLogger.Client

Allo stato attuale, la solution che vi ritroverete sul PC è così composta:

image

Tralasciamo per ora lo scopo preciso della nostra applicazione WPF. I progetti sono quattro:

  • FsxLogger.Client : l’applicazione WPF sviluppata con Ammy
  • FsxLogger.ViewModels.Portable : una serie di viewmodel implementati in PCL
  • FsxLogger.ViewModels.Wpf : una serie di viewmodel che ereditano da quelli PCL, ma si specializzano per il mondo WPF
  • FsxLogger.ViewModels.Message : messaggi da utilizzare per far comunicare viewmodel con l’applicazione WPF, utilizzando la classe Messenger di MvvmLightLibs

Detto questo, parto dal presupposto che conosciate WPF, C#, MVVM, il motore di binding di WPF, e la solita serie di nozioni che è necessario avere. Andiamo per gradi.

Prima di partire in quarta…qualche nozione introduttiva
La nostra applicazione WPF ha una finestra di Login per l’autenticazione, che ovviamente è la prima che compare quando l’applicazione parte. Essa si chiama, con molta fantasia, LoginWindow.ammy. E’ questa la prima finestra che andremo a sviluppare. Il corrispondente viewmodel si chiama LoginViewModel, e si trova nell’assembly PCL.

image

Importare un namespace
La prima necessità che abbiamo è quella di importare un namespace in linguaggio Ammy, esattamente come faremmo con lo XAML, né più né meno. La sintassi è molto semplice, perchè basta utilizzare la keyword using, che è la stessa che useremmo con C#. Dopo aver aggiunto le reference (dal progetto FsxLogger.Client ho aggiunte le reference agli altri 3, per capirci), possiamo prendere un file .ammy ed all’inizio dichiarare il namespace in questo modo:

using FsxLogger.ViewModels.Portable

Da questo momento in poi, l’Intellisense reagirà e potremo inserire le classi contenute in quel namespace. Nelle risorse della Window inseriamo il viewmodel.

Resources: [
    LoginViewModel Key="vm" { }
]

Questa è la sintassi da utilizzare. La proprietà Resources delle Windows è di tipo ResourceCollection, quindi può contenere ovviamente più oggetti, motivo per il quale abbiamo dovuto usare le parentesi [ e ], come in JSON, per indicare un array di oggetti. All’interno ho inserito la classe LoginViewModel (notare: senza usare alcun prefisso come invece accadrebbe in XAML), assegnando una Key “vm”. Fatto.

Passo successivo è quello di assegnare la proprietà DataContext ad un controllo (la finestra? il controllo più esterno del visual tree?) per far propagare il viewmodel per tutta la view.

Nel mio caso, ho impostato DataContext sulla Grid a linea 14.

Grid
    {
        DataContext: resource "vm",
        #TwoColumns(120), #ThreeRows("Auto", "Auto"),
        Margin: "8"
    }

Il codice che vedete qui è semplificato rispetto a ciò che vedete su GitHub. Notare l’utilizzo della keyword Ammy resource, equivalente alla StaticResource di XAML, ma lievemente più compatta.

Come accade con lo XAML, il DataContext fa propagare la classe di viewmodel per tutto il visual tree della nostra UI. Grazie a questo meccanismo, da qui in avanti potremo fare binding sui controlli e rendere il tutto funzionante. Ma questo è argomento dei prossimi post.

Prima di chiudere, due note importanti

Ricordiamoci sempre che compito di Ammy è quello di generare l’equivalente codice XAML. Ciò significa che mentre noi lavoriamo sulla view LoginWindow.ammy, da qualche parte esiste un altro file LoginWindow con estensione XAML. Dove si trova? E’ semplice: nel solution explorer attivate l’opzione “Show All Files”, così cominciate a vedere anche quelli nascosti. Eccolo lì, l’avete trovato!!!

image

E’ molto comodo perchè questo file XAML è autogenerato dal codice Ammy, e quindi potete man mano verificare che tutto funzioni regolarmente.

E perchè, allora, usare Ammy? Lo ripeto: perchè è estremamente più compatto, perchè ci sono mixin ed alias (utilissimi), perchè fare binding con la sintassi XAML è più veloce e parlante (Intellisense permettendo), per i bellissimi inline binding converter, che sono meravigliosi.

La seconda ed ultima cosa che vi voglio far notare è che Ammy non si lamenta se per sbaglio specificate due volte la stessa proprietà sullo stesso controllo, cosa che invece XAML fa. Mi spiego meglio; guardate questo stralcio di codice:

Window "FsxLogger.Client.LoginWindow"
    {
    Width: 320, Height: 240, Width: 320, Height: 240
    WindowStartupLocation: CenterScreen,
    WindowStyle: ToolWindow, Title: "Login"
    FocusManager.FocusedElement: bind from "focus"
    }

Ho ripetuto Width e Height della Window due volte, volutamente, per sbaglio. Ammy non si lamenta. XAML lo farebbe, invece. Andate a dare un’occhiata al codice XAML generato. Ammy fa una cosa molto semplice: evita di duplicare quelle proprietà, esattamente come dovrebbe fare.

Il codice compila, l’applicazione parte, noi siamo felici.

Alla prossima! Happy coding!

Send to Kindle
My daily work

Scusi, mi rifà il programma?

Questo post è basato su fatti realmente accaduti.

E’ successo. E’ ricapitato. Per l’ennesima volta, è riaccaduta la stessa cosa.

Un potenziale cliente vi contatta, vi incontrate, chiaccherate per la prima volta su quello che dovrà fare il meraviglioso software che ha in testa. E per l’ennesima volta devi ricostruire, riprogettare da zero, un software già esistente, scritto lustri prima in MFC, o in Visual Basic 4.0, o in Access 97 o addirittura 2.0. E chiamano te per riconvertirlo e riprogettarlo in .NET, magari perchè si sono accorti che non sono più competitivi sul mercato, perchè il codice è diventato ingestibile, perchè vogliono avere l’app sotto iOS o Android, o per mille altri motivi. Non c’è documentazione, c’è solo un gruppetto di persone che sanno perfettamente cosa deve fare il software, ma non c’è nulla di scritto e di formalizzato. Non c’è nulla di male in tutto questo, d’altronde lavoro è lavoro.

Tu, con il tuo bravo e fidato Visual Studio, vorresti cominciare lo sviluppo di questo software magari con DDD, scrivendo le classi e pensando accuratamente il dominio applicativo, quindi – per farla breve – approcciando ad una metodologia code-first. Prima le classi, in seguito la logica, poi penserai al modello di persistenza. Ma il tuo cliente ragiona diversamente; come accadeva decenni fa (quando il suo software è stato scritto la prima volta) ragiona partendo dal database. Per lui è essenziale vedere lo schema del database, per capire se stai scrivendo la cosa giusta. Prima di vedere anche una sola linea di codice C#, vuole vedere le tabelle, le relazioni, i campi ed i nomi dei campi come piacciono a lui.

Di fronte ad una situazione di questo tipo, ci sono tante strade. Ne cito due.

  1. Tu ragioni sempre e comunque code-first. Scrivi le classi e lasci che sia l’ORM (Entity Framework?) a generarti tutto il mondo della persistenza relazionale. Ma siccome per il cliente lo schema del database è fondamentale – dal quale dipende il Supremo Destino della nostra Galassia – allora cominci a litigare con attributi o con vagonate di codice, per educare l’ORM a generarti lo schema del db esattamente come lo vuole il cliente
  2. Ti arrendi all’evidenza e cominci a progettare il database. Quindi segui il modello database-first. Fattibile, no? Al massimo, parlando di Entity Framework, una volta creato il database puoi farti comunque generare le classi tramite l’approccio “Code First from database”. Così al massimo puoi attivarti le migration…

image

Il discorso, a mio avviso è semplice. Se vuoi portare a casa la pagnotta, al cliente devi comunque dare retta. Se il tuo committente, magari perchè è stato educato male, ragiona partendo dal database, purtroppo non puoi farci nulla. Io poi parto da un semplice presupposto: se hai chiamato me, non vuoi semplicemente uno che digita o scrive codice, ma vuoi uno che ci metta la testa. Però non sempre si ha questa possibilità, per diversi motivi.

Detto questo, il primo approccio è code-first solo in apparenza. Tecnicamente cominci scrivendo un sacco di classi, ma in realtà nella tua testa sei costantemente traviato da ciò che dovrai ottenere come struttura sul database. E’ solo un palliativo, insomma. Scrivi una classe, e poi via…tonnellate di codice nel metodo OnModelCreating di Entity Framework per piegare ai tuoi voleri l’ORM. Burp, equivalente al ruttino.

Il secondo approccio è a tutti gli effetti database-first. E se il cliente ragiona in questo modo, che male c’è? Siamo pagati per scrivere un software o per fare gli accademici? Quindi, che male c’è ad aprire il Microsoft SQL Server Management Studio, stendere tutte le tabelle, campi, relazioni, e poi importarle via Entity Framework? In questo modo il cliente è soddisfatto, io ho le mie classi su cui poi cominciare a sviluppare. Se il progetto è di una certa importanza e/o durata, ci sarà magari tutto il tempo per guadagnare stima e fiducia verso il cliente, e ci saranno tutte le occasioni per indirizzarlo verso strade e percorsi più moderni allo sviluppo del software.

Send to Kindle
My personal life

Riportare in vita Microsoft Money?

Non so quanti di voi miei lettori lo abbiano utilizzato in passato. Microsoft Money è un bel software di produttività personale, per tener traccia delle proprie spese, di tenere sotto controllo il proprio budget, dotato (secondo me) di un’interfaccia utente pulita, colorata ed accattivante.

Money è stato dismesso da parecchi anni. Ma ieri, 30 gennaio, è stata avviata una raccolta di firme, una petizione insomma, per riportarlo in vita e farlo rientrare nella ben nota suite Microsoft Office. La petizione è rivolta a niente meno che Satya Nadella. E sono richieste anche feature innovative, come una versione per dispositivi mobili, o la possibilità di averne una versione Web integrata con Office 365. Sarebbe davvero una cosa molto molto interessante.

Nel momento in cui vi scrivo mancano 300 firme al raggiungimento delle 1.000 necessarie all’invio di tutte le firme a Sua Maestà Nadella. Chissà se qualcuno ci farà un pensierino.

Trovate maggiori informazioni qua:
https://www.change.org/p/satya-nadella-bring-back-microsoft-money-as-part-of-microsoft-office

Beh, che ne dite? Si può fare? Ci state?

Send to Kindle
My personal life

Uso Trello, e non ne faccio più a meno

Dall’estate scorsa utilizzo Trello, e ve ne voglio parlare.

Lo trovo utile per tenere traccia delle mie attività, non solo lavorative.

L’organizzazione avviene tramite Bacheche, che di default è privata, mentre può essere condivisa con altre persone, feature tra l’altro che non ho ancora provato con una certa continuità. Ciascuna Bacheca può contenere una o più Liste, ogni Lista può contenere una o più Schede. Queste ultime contengono le vere attività di lavoro, che possono essere espresse in diversi modi: semplici appunti e check-list da completare, per esempio. Ogni scheda può avere una data di scadenza, allegati, e via dicendo.

Ad oggi, le Bacheche che utilizzo sono fondamentalmente tre:

  • Attività personali
  • Brain-Sys
  • Piloti Virtuali Italiani

image

Ne ho nascosta una per motivi di privacy.

All’interno di Attività personali ho istanziato due schede: Attività Social ed Altro. Nelle Attività Social creo una scheda ogni volta che mi viene in mente un contenuto di cui parlare qua sul mio blog, mentre in Altro mi segno un po’ tutto il resto: ricordarsi di cercare un’assicurazione RCA più conveniente di quello che ho adesso, lista della spesa, ricordarsi di comprare questo o quello, etc.

Per quanto riguarda la Bacheca dedicata a Brain-Sys, ho una scheda per ciascun cliente che gestisco. E per ogni cliente mantengo una lista delle attività in corso, ovviamente sotto forma di appunti rapidi e veloci, perchè l’analisi, gli use-case e la documentazione di progetto sta da tutt’altra parte. Però…sapete…quelle attività estemporanee del tipo: ricordati di mandare la mail, scrivi il rapportino del giorno XYZ, fai due presale, rispondi a Silvia su questo & quello. Quelle attività difficilmente tracciabili in altra maniera.

La Bacheca di Piloti Virtuali Italiani è un po’ in disuso, o comunque meno attive delle altre due. Mi segno di rispondere via mail al socio, mi segno i Direttivi ai quali devo partecipare, etc.

Ad una Bacheca possiamo impostare un colore di sfondo, possiamo installare dei plug-in (chiamati Power-Up) per abilitare funzioni avanzate, possiamo consultare velocemente la history di tutte le modifiche apportare, etc. Tutto molto veloce ed a portata di click.

Alcune feature interessanti delle schede
Ogni scheda ha caratteristiche interessanti. Come dicevo prima, ogni scheda rappresenta un’attività da portare a termine. Possiamo associargli una eventuale etichetta (che determina il colore con la quale verrà rappresentata sullo schermo), una data di scadenza. Ogni scheda è composta da uno o più commenti, che possono essere testo, indirizzi web, etc. In una scheda possiamo inserire una check-list: ve ne parlo più sotto. All’interno di un testo possiamo menzionare un membro con il quale stiamo condividendo i contenuti. Possiamo allegare uno o più file in allegato, di qualsiasi tipo.

Ogni elemento di Trello (Bacheca, Scheda, Lista) può essere archiviato: questo significa che non viene più visualizzato sullo schermo. Ovviamente possiamo sempre recuperarlo in futuro, nel caso in cui ci servisse recuperare qualcosa.

L’interfaccia web è gradevole, pulita, essenziale e risponde bene. Sapete quanto io preferisca, normalmente, le applicazioni desktop o mobile rispetto ad un’applicazione usufruita via browser. Beh, non è questo il caso.

Shortcut tramite tastiera
Una feature interessante è la presenza delle scorciatoie da tastiera, che permettono di avviare subito operazioni veloci. Premete “d” mentre siete su una scheda per impostare la data di scadenza, per esempio. Premete i tasti numerici per associare subito un’etichetta, e così via. Fantastico. Potete vedere o disattivare gli shortcut dal menù di opzioni in alto a destra.

Il punto di forza…sono due…!!!!!
Il primo è, secondo me, la flessibilità di ogni scheda, che consente di prendere appunti in modo libero, impostare una eventuale data di scadenza, allegare file in allegato di qualunque tipo. La feature che mi piace di più è la possibilità di creare le cosiddette check-list, ovvero un elenco di task da portare a termine. Trello evidenzia con una sorta di barra di progresso lo stato di quella check-list, così che avete con un colpo d’occhio la situazione di ciò che dovete fare, quanto e cosa vi manca alla fine, etc.

Ma allo stesso tempo è rigido, nel senso che tutto è ben strutturato e suddiviso in Bacheche, Lista e Schede, e non potete sfuggire – giustamente – da questa struttura generale. OneNote per certi versi è un prodotto paragonabile a Trello, ma quest’ultimo è più improntato alla gestione degli appunti, agli sketch, ad un testo comunque più lungo e complesso. Passatemi il paragone: Trello è il Twitter dei Task Manager. Vi suggerisce di essere concisi, rapidi ed essenziali. Eppure ha tutto.

L’altro punto di forza è la presenza delle app, che vi permettono di aprire, consultare e gestire il vostro Trello da Android o iOS. Onestamente in questo momento, mentre vi sto scrivendo, non sono in grado di garantirvi la presenza di app per Windows 10. Io ho installato l’app per Android, mi trovo più che bene e vi posso assicurare, per quello che vale, che vi capiterà spesso di aprirla per leggere o scrivere qualcosa. O forse dipende da me, dal fatto che ultimamente ho il cervello in fermento!

E non ne faccio più a meno
Non ne faccio più a meno, perchè grazie a Trello riesco a mettere in fila le cose che devo fare, e che altrimenti mi sfuggirebbero. Grazie a Trello ho ricominciato a scrivere sul blog, perchè ogni volta che mi si accende la lampadina su un eventuale contenuto, me lo segno…e la sera, quando mi metto davanti al PC a scrivere, pesco a caso da ciò che mi ero appuntato.

Se come me siete un po’ distratti, tendete a dimenticare le cose o volete semplicemente essere più organizzati, date una possibilità a Trello. Per me è diventato uno strumento essenziale.

Send to Kindle
.NET WorldVisualStudioTips.net

[Ammy.2] Il file lib.ammy: mixin e alias

Quando in un progetto WPF installate tramite NuGet la libreria Ammy, nel progetto vi ritrovate anche un file lib.ammy. Cosa contiene? A cosa serve?

Il file lib.ammy contiene tantissime funzioni utilissime e pronte all’uso.
Tali funzioni in linguaggio Ammy sono divise in due tipologie:

  • Mixin
  • Alias

Il file lib.ammy è liberamente modificabile, e quindi possiamo aggiungere nostri mixin o alias, oltre che ovviamente modificare o migliorare quelli esistenti.

Utilizzare i mixin
Concettualmente parlando, un mixin assomiglia ad un tradizionale stile di WPF. Un mixin si applica ad un controllo WPF – come uno stile – e restituisce un set di proprietà ben definito. Ad esempio:

mixin Header() for TextBlock {
    FontWeight: Bold,
    FontSize: 36,
    Foreground: DarkGray
}

Questo stralcio di Ammy definisce un mixin chiamato Header, che è applicabile a tutte le TextBlock, a che in pratica definisce dei valori per le proprietà FontWeight, FontSize e Foregound. Come si utilizza? In questo modo:

Window "StudyAmmy.StartWindow" {
    StackPanel { Orientation: Horizontal,
    Children: [
        TextBlock { Text: "some text", #Header() }
    ] }
}

Nel momento in cui si inserisce un controllo per cui esiste un mixin, esso diventa disponibile nell’Intellisense. Quindi, inseriamo una TextBlock, valorizziamo la proprietà Text e poi richiamiamo il mixin che ci interessa con la sintassi #Header(). Il mixin inietta le sue proprietà all’interno del JSON. Notare la sintassi con le parentesi () che ricorda il fatto che stiamo chiamando una funzione.

Sembra uno stile, vero? Peccato che i mixin siano decisamente più potenti rispetto ad uno Style di WPF, banalmente perchè si possono applicare anche su quelle proprietà che uno Style non raggiunge.

Ad esempio:

mixin TwoColumns (one = "*", two = "*") for Grid {
  combine ColumnDefinitions: [
    ColumnDefinition { Width: $one }
    ColumnDefinition { Width: $two }
  ]
}

Questo mixin chiamato TwoColumns, che fa parte di quelli definiti nel file lib.ammy, permette di definire velocemente una Grid con due sole colonne:

image

Ad esempio, si potrebbe scrivere questo codice:

Grid
    {
        #TwoColumns("*", "2*"),
        
        Background: LightGray,
        Margin: 4,
        ShowGridLines: true,
        TextBlock { Grid.Column: 0, Text: "1° colonna",
            FontSize: 24, Margin: 4 },
        TextBlock { Grid.Column: 1, Text: "2° colonna",
            FontSize: 24, Margin: 4 }
    }

Per ottenere una UI di questo tipo:

image

Notare che i mixin possono avere parametri in input. Il mixin Header non ne aveva, mentre TwoColumns ne aveva due, grazie ai quali è possibile specificare la larghezza delle due colonne. I parametri possono avere valori predefiniti, come è possibile fare con C#.

Ricordiamoci che per richiamare un mixin è necessario utilizzare il carattere #.

Se stiamo scrivendo un mixin e vogliamo utilizzare uno dei parametri in input dobbiamo usare $.

Utilizzare gli alias

Scopo degli alias è quello di generare un oggetto, come un controllo, ma in generale un qualsiasi oggetto inseribile con lo XAML. Mentre un mixin ha un nome, si collega ad un controllo e produce in output un set di proprietà, compito dell’alias è quello di produrre in output un oggetto vero e proprio. Per esempio:

alias ButtonWithPadding(text, padding) {
  Button { Content: $text, Padding: $padding }
}

Questo blocco Ammy definisce un alias che, quando chiamato, produrrà in output un controllo Button. L’alias ha due parametri di input – text e padding – che vi permetterà di inserire nella UI un button con quelle caratteristiche, in modo molto più compatto rispetto a quello che avremmo dovuto fare con XAML o senza usare l’alias.

Se leggete il file lib.ammy, troverete un gran numero di alias pronti all’uso, molto compatti, relativi per esempio a Trigger ed animazioni. Ad esempio, questo è molto interessante:

alias DoubleAnimation(
    property,
    frm = "0",
    to = "1",
    duration = "0:0:1",
    targetName=none,
    beginTime=none) {
  DoubleAnimation {
    Storyboard.TargetProperty: $property
    Storyboard.TargetName: $targetName
    From: $frm
    To: $to
    Duration: $duration
    BeginTime: $beginTime
  }
}

Ho calcato la mano con qualche “a capo” per rendere il codice più leggibile. Con una sola chiamata a questo alias, possiamo inserire una DoubleAnimation, passando in input il nome della proprietà, il valore iniziale e finale, la durata, etc. In modo estremamente compatto.

Sviluppiamo un progetto vero con MVVM?

Smettiamola di parlare di Ammy solo dal punto di vista puramente teorico. Dalla prossima volta implementeremo qualcosa con WPF e Mvvm, il pattern architetturale più adatto quando ci troviamo in un mondo basato su XAML. Vedremo come fare binding e come sfruttare le feature più interessanti di Ammy per essere più produttivi.

Happy coding!

Send to Kindle
.NET WorldVisualStudioTips.net

Pubblicare sul Windows Store un’applicazione desktop nata in WPF

Come ho già venuto modo di dire in passato, CharMapMe è un’applicazione desktop finita sul Windows Store sotto forma di Universal Windows Platform. Come è avvenuto questo passaggio?

Tralasciamo i passaggi tecnologici, perchè sono ampiamente descritti in questo post sul blog di MSDN Italia. Ci tengo a raccontare alcune cose dietro le quinte, magari qualcosa che nessuno vi racconta. Innanzitutto, un normale account developer non ha i permessi per poter completare la submission di un package UWP: questo significa che quando entrate nella vostra dashboard ed inviate il package (file .appx), al termine dell’upload vi ritroverete con questo messaggio di errore.

image

Ho nascosto alcune informazioni sensibili. Il messaggio di errore più importante è il primo in elenco, ovvero: Package acceptance validation error: You need to accept the Centennial Early Adopter Program Addendum before you can submit this app. Se il vostro account developer non è stato ancora sbloccato, cliccare sul link non serve a nulla, perchè vi viene proposta una pagina completamente bianca, con un misero tasto Back per tornare indietro.

Come si procede, quindi? Dovete essere in contatto con un ingegnere Microsoft, al quale inviate il vostro .appx e prova l’installazione della vostra applicazione trasformata in UWP. Come glielo inviate? Nel mio caso, è stato attivata una piattaforma web di condivisione cifrata e protetta, dove ho potuto uploadare il file .appx. Se tutto va bene al primo colpo, come è successo a me, il flusso di lavoro si chiude piuttosto velocemente: l’ingegnere Microsoft approva l’app e sblocca il vostro account developer. A questo punto potete leggere, accettare il Centennial Early Adopter Program Addendum e procedere al completamento della submission come fareste di solito.

Aggiungo qualche nota per essere più esaustivo.

  1. Una volta che l’app è stata approvata secondo la procedura descritta qui sopra, diventa una normale app UWP. Questo significa che potete aggiornarla sullo Store in completa libertà, senza più necessità di intervento da parte dell’ingegnere Microsoft con cui avete lavorato all’inizio
  2. Nel mio caso, quindi, CharMapMe è stata certificata ed approvata, e si trova sul Windows Store. Posso aggiornarla autonomamente. Se un domani volessi convertire un’altra applicazione in UWP tramite il Desktop App Converter, dovrò richiedere nuovamente l’intervento di Microsoft per far approvare questa seconda applicazione
  3. Lo sblocco avviene a livello di account developer. Questo significa che quando tenterete l’invio di un package relativamente ad un’app successiva alla prima, non verrete più bloccati come mostrato nella prima immagine di questo post. Il package verrà accettato e potrete completare la submission, perchè il vostro account è stato sbloccato. Ma poi l’app verrà inesorabilmente bocciata, perchè – come dicevo al punto 2 – dovete chiedere l’intervento di Microsoft per ogni applicazione
  4. Da tutto ciò, si deduce che tutte le app convertire in UWP tramite il Desktop App Converter passano attraverso un processo di certificazione manuale

Direi che è tutto!

Send to Kindle
.NET WorldVisualStudioTips.net

[Ammy.1] Primi passi con Ammy

Per chi mi legge, se benissimo che lavoro tantissimo nel mondo delle applicazioni desktop, quindi ho a che fare principalmente con lo XAML, sia per quanto riguarda WPF che UWP. Quando ho sentito parlare di Ammy, quindi, mi sono interessato, ma la domanda successiva è stata:

devo buttare via lo XAML
ed imparare Ammy ?

 

La risposta è tranquillizzante, perchè in un progetto WPF è possibile utilizzare XAML ed Ammy, senza alcun problema. In un progetto WPF, quindi, possiamo avere delle Window/Page create con XAML, ed altre con Ammy XAML ovviamente non lo butti via, semplicemente è possibile dare un’occhiata ad Ammy e vedere se fa al caso nostro. Questo mi ha tranquillizzato, perchè questo significa in parole povere che posso integrare Ammy nei miei progetti esistenti, e sfruttarne le caratteristiche peculiari che per certi versi lo rendono più potenti rispetto allo XAML.

Quali sono queste caratteristiche?

modifica a runtime delle view
alias e mixin
JSON al posto dello XAML

 

Scriverò un po’ di posto su Ammy, perciò se siete interessati seguitemi e non ve ne pentirete.

Primi passi con Visual Studio
La prima cosa da fare è scaricare dal Marketplace di Visual Studio l’extension per il supporto ad Ammy. Da questo link scaricate il file Ammy.VisualStudio.vsix, di circa 59Kb, che aggiungerà alcuni Item Template molto molto comodi per lavorare con Ammy. Ne parleremo fra poco.

La seconda cosa da fare è creare un progetto WPF. Ammy, ad oggi, si applica solo ed esclusivamente su questo tipo di progetti. Quindi apriamo Visual Studio 2015, creiamo un progetto WPF e poi utilizziamo NuGet per recuperare il pacchetto Ammy.Lo possiamo fare attraverso la Package Manager Console oppure tramite la voce Manage NuGet Packages del nodo References. Decidete voi qual è la strada che preferite.

image

Qui sopra vedete la Package Manager Console, mentre qui sotto NuGet.

image

Fatto questo, possiamo provare a scrivere la nostra prima Window con Ammy.

Aggiunta di una Window nel progetto
Andiamo nella solita dialog “Add new Item” di Visual Studio. L’extension per Visual Studio ci ha installato 4 Item Template, che si trovano nel nodo “Visual C#”; per trovarli più facilmente, vi suggerisco di impostare l’ordinamento “Name Ascending”, oppure di fare una ricerca con “Ammy” nella casella in alto a destra. Fatto questo…

image

…troverete quattro Item Template: Ammy Application, Ammy Mixins, Ammy User Control ed infine Ammy Window. Selezioniamo quest’ultimo, poi diamo un nome, per esempio “StartWindow.ammy”.

Fatto. Notare che, come dicevo prima, il nostro progetto ha la solita MainWindow.xaml (scritta in XAML) ed un altro file, StartWindow.ammy, che è un’altra Window, questa volta scritta in Ammy.

Se facciamo doppio-click su questo file apparirà un codice sorgente simile al JSON:

Window "StudyAmmy.StartWindow" {
}

Il codice qui sopra di fatto crea una Window di WPF. Il primo elemento root di Ammy deve avere un nome, che di fatto indica il nome della classe di code-behind. Un concetto importante di Ammy è che dietro le quinte viene sempre auto-generato del codice XAML; questa cosa è importante ed utile allo stesso tempo, perchè possiamo costantemenet verificare che il codice Ammy che abbiamo scritto produca il codice XAML che desideriamo. Mi spiego meglio: clicchiamo il pulsante Show All Files nel Solution Explorer di Visual Studio. Comparirà il file StartWindow.g.xaml, che possiamo tranquillamente aprire tramite doppio-click.

Facciamo un passettino ulteriore. Editiamo il file StartWindow.ammy in questo modo:

Window "StudyAmmy.StartWindow" {
    StackPanel { Orientation: Horizontal,
    Children: [
        TextBlock { Text: "I Love Ammy!!!" }
    ] }
}

Abbiamo creato uno StackPanel orizzontale, ed abbiamo aggiunto un unico controllo TextBlock. Notare la sintassi json-like. Notare che l’Intellisense è perfettamente funzionante. Se salviamo il file e diamo un’occhiata al file “StartWindow.g.xaml”, il codice è il seguente:

<Window x:Class="StudyAmmy.StartWindow"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:ns0="clr-namespace:AmmySidekick;assembly=AmmySidekick"
  ns0:Ammy.Register="/StudyAmmy;component/StartWindow.g.xaml">
  <StackPanel Orientation="Horizontal">
    <StackPanel.Children>
      <TextBlock Text="I Love Ammy!!!"/>
    </StackPanel.Children>
  </StackPanel>
</Window>

Nota importante. NON modificate mai lo XAML direttamente. Questo XAML viene auto-generato dal file .ammy che abbiamo visto prima. Qui la lesson-learned è che Ammy non fa nient’altro che produrre XAML al posto nostro, quindi tutto ciò che era possibile con XAML lo è anche con Ammy.

Solo che Ammy ha delle feature in più, come alias e mixin che citavo prima, che semplificano e velocizzano tantissimo il nostro lavoro.

Per concludere…

Ok, diciamo che per questa prima puntata abbiamo fatto abbastanza.

Non perdete i miei prossimi post perchè ne vedremo delle belle.

Send to Kindle
.NET WorldVisualStudioTips.net

DevOps.bat : il cuore del sistema di deploy per applicazioni desktop WPF

Nel post precedente ci eravamo interrotti sul più bello, ovvero sul contenuto del file batch DevOps.bat. Questo file ha un compito tanto importante quanto banale.

Ad ogni esecuzione deve produrre le cartelle per distribuire l’applicazione WPF secondo i tre modelli: WPF, Portable Zip e per il Windows Store.

Come nel post precedente, andiamo un passo alla volta ed arriveremo al risultato finale.

Primo passo: avere un folder per ciascun deploy
Le prime righe del file DevOps.bat fanno quanto segue:

@echo TASK - Remove and rebuild directories
rmdir "ClickOnce" /S /Q
rmdir "Portable" /S /Q
rmdir "Windows Store" /S /Q
mkdir "ClickOnce"
mkdir "Portable"
mkdir "Windows Store"

Abbiamo sostanzialmente a che fare con tre folder:

  • ClickOnce
  • Portable
  • Windows Store

Direi che il nome è abbastanza esplicativo: ognuna di queste conterrà i file per ciascun deploy. I parametri del comando rmdir (ovvero /S e /Q) dicono di piallare ad ogni esecuzione tutto il contenuto delle cartelle e sottocartelle (/S), senza chiedere alcuna conferma (/Q).

Secondo passo: ClickOnce

Per generare automaticamente la cartella ClickOnce è necessario ricorrere a msbuild.

@echo TASK - ClickOnce
"C:Program Files (x86)MSBuild14.0inmsbuild.exe"
    "..CharMapMe.sln" /target:publish /p:Configuration=Release
xcopy   "..CharMapMeinReleaseapp.publish*.*"
        "ClickOnce*.*" /E /Q /Y

Il primo comando esegue msbuild.exe dicendo di compilare il file CharMapMe.sln, nella configurazione Release, generando nel contempo la pubblicazione per ClickOnce.

Il risultato di questo comando è un folder “binReleaseapp.publish” che contiene solo ed esclusivamente i file specifici di ClickOnce. Ma non mi piace che sia dentro “app.publish”. Motivo per cui il secondo comando utilizza xcopy per copiare i file all’interno del folder “ClickOnce”.

E difatti, eccoli qua. E’ sufficiente prendere questa cartella ed inviarla via FTP per distribuire a tutti gli effetti l’ultima versione dell’applicazione.

image

Missione compiuta.

Terzo passo: Portable zip

Possiamo passare alla generazione del file zip per il download Portable.

I comandi contenuti nel file DevOps.bat sono i seguenti:

@echo TASK - Portable
xcopy "....CharMapMeinRelease*.*" "..Portable"
cd "..Portable"
del "*.pdb"
del "*.application"
del "*.config"
del "*vshost*"
del "*.manifest"
"..7z" a -tzip "CharMapMe.zip" -sdel -r *.*

In breve: copio tutti i file dalla “binRelease” nella mia cartella “Portable”. Inizialmente, questa cartella conterrà anche un certo numero di file che NON è necessario distribuire: ecco perchè le righe successive vanno a cancellare i file pdb, application, config, vshost e manifest.

Poi utilizzo 7z.exe (ricordate il post precedente? si trovava nella cartella Deploy) per creare al volo uno zip con tutti i file. Il parametro “-sdel” dice di rimuovere i file dopo la creazione del file zip. Il parametro “-r” dice di includere anche i file in eventuali sottocartelle, ma non è il nostro caso.

Fatto questo, nella cartella “Portable” ottengo il file “CharMapMe.zip”, pronto da mettere online.

image

Quarto passo: Windows Store

Il terzo modello di deploy prevede la distribuzione sul Windows Store.

La prima parte di comandi necessari sono i seguenti:

@echo TASK - Windows Store
xcopy "..CharMapMeinRelease*.*" "Windows Store"
xcopy "Support*.*" "Windows Store*.*" /Q /Y
cd "Windows Store"
del "*.pdb"
del "*.application"
del "*.config"
del "*vshost*"
del "*.manifest"

Sono praticamente gli stessi visti prima per la modalità Portable. Copio tutti i file dalla “binRelease” a “Windows Store”. Poi copio tutti quelli contenuti nella cartella “Support” nella cartella “Windows Store”: adesso vi dico la ragione di questa operazione. Poi, esattamente come prima, cancello quelli superflui, che non devono essere inclusi nel package.

A cosa serve la cartella “Support”? Essa contiene 4 file.

image

  • AppxManifest.xml : è il file di manifest per l’applicazione UWP
  • *.png : sono 3 tile in diverse dimensioni per creare il package UWP

E’ un po’ OT, in questo post, raccontare esattamente nel dettaglio questo passaggio. Facciamola breve: per distribuire un’app UWP ci vuole necessariamente un file di manifest. Sempre, in ogni caso. Ma CharMapMe NON è nata come app UWP, quindi il file di manifest l’ho dovuto creare da zero, con il blocco note. Idem le immagini per avere le tile. Per maggiori informazioni su questo particolare aspetto vi consiglio di leggere questo post sul blog di MSDN Italia.

Ok, fino a questo punto ci siamo. Nella cartella “Windows Store” ci sono i file necessari per creare il package: tutti quelli contenuti in “binRelease” + file di manifest + 3 immagini per le tile. Possiamo generare il file di package vero e proprio.

"C:Program Files (x86)Windows Kits10inx64makeappx.exe"
    pack -d . -p "CharMapMe_nosigned.appx"

Eseguo il tool makeappx.exe, dicendo di prendere la cartella corrente, e di generare il file “CharMapMe_nosigned.appx”.

Poi mi duplico il file con il nome “CharMapMe_signed.appx”

copy "CharMapMe_nosigned.appx" "CharMapMe_signed.appx" /Y

Perchè avere due file? Quello “nosigned” sarà quello che invieremo sul Dev Center per tentare la certificazione, mentre quello “signed” potrà essere installato sulla nostra macchina (o su altre di sviluppo e/o test) per testare l’installer vero e proprio, e capire se l’app WPF convertita in UWP parte e funziona correttamente come previsto. Come faccio a firmare un file .appx?

SignTool sign /fd SHA256 /a /f
    ..VivendoByte.pfx /p 123456
    CharMapMe_signed.appx

Utilizzo il tool SignTool per firmare il file “CharMapMe_signed.appx”, passando come parametri il certificato digitale “VivendoByte.pfx”, la password e l’algoritmo di cifratura (SHA256). Fatto, il package è firmato. Ripeto, ne abbiamo due: quello “nosigned” va inviato sul Dev Center, oppure all’ingegnere Microsoft con cui state collaborando per certificare la vostra app; quello “signed” serve a voi e solo a voi per testare la vostra app.

Infine, giusto per fare un lavoro pulito, cancello tutti i file nel folder “Windows Store” che non hanno l’estensione .appx. Così facendo, ottengo una bella cartella pulita con solo i due file package.

for /f %%F in ('dir /b /a-d ^| findstr /vile ".appx"') do del "%%F"

Per ottenere quindi una cosa simile:

image

 

Conclusioni

Beh, missione compiuta! Ci sarebbe molto altro da dire o da raccontare, per esempio:

  • Posso mettere DevOps.bat nelle “post build events” di Visual Studio?
  • Perchè non effettuare davvero il deploy in produzione, facendo l’upload dei file nel posto giusto? Ad eccezione del deploy del Windows Store, perchè quest’ultimo ad oggi passa ancora attraverso una procedura manuale di submission
  • Eseguire “DevOps.bat > DevOps.log” permette di ottenere il log dell’ultima esecuzione, il che può sempre fare comodo

Lascio le porte aperte ad ulteriori sviluppi.

Send to Kindle
.NET WorldVisualStudioTips.net

Automatizzare il deploy di una tradizionale (e banale) applicazione WPF

Mi piacerebbe dedicare qualche post a descrivervi come ho deciso di organizzare il deploy di una piccola e normalissima applicazione desktop implementata in WPF. Penso che la conoscerete, perchè si tratta di CharMapMe, l’applicazione di cui ho già parlato qualche giorno fa. Il caso secondo me è interessante, perchè l’app non è complessa, e mira al cuore di un problema ben preciso, che si può riassumere velocemente con la seguente domanda.

Quanto è complesso ottenere in modo automatizzato i file corretti da distribuire nel caso di deploy tramite ClickOnce, Portable e magari Windows Store?

Ok, andiamo con calma.

Introduzione
CharMapMe sorge dalle ceneri di Show Cars, come vi ho raccontato qui. Vale a dire, quindi, che è un piccolo tool per sviluppatori (ma non solo) nato diversi anni fa, ritagliando tempo libero qua e là e risolvendo un problema che mi affliggeva, ovvero sfogliare tutti i font possibili ed immaginabili alla ricerca di simboli da inserire nelle mie view XAML. Utilizzare charmap, quello predefinito di Windows, è davvero impossibile, non sto qui a raccontare il perchè.

CharMapMe, quindi, è una normale applicazione WPF, puramente desktop, composta dai seguenti file:

image

Un eseguibile ed un po’ di dipendenze esterne. Nulla di che, estremamente banale.

Ho deciso sin da subito di distribuire CharMapMe sicuramente attraverso ClickOnce dal sito ufficiale https://charmapme.azurewebsites.net. E poi di distribuirla attraverso un file zip, in modalità portable, così eventualmente uno si mette l’applicazione dove più gli pare e piace, su una chiavetta USB o da altre parti. ClickOnce dà il vantaggio degli auto-aggiornamenti, ma anche la modalità portable è comoda e perfettamente legittima.

Ho voluto anche distribuirla attraverso il Windows Store, quindi trasformarla in Universal Windows Platform. Avevo due scelte: o la riscrivevo daccapo oppure utilizzavo Centennial, alias Desktop Bridge, per convertirla più velocemente. Ho optato per questa seconda scelta, più veloce e meno invasiva per il mio cervello (LOL). Sì, nei prossimi giorni vi racconterò anche qualcosa su questa esperienza, non tanto dal punto di vista tecnico, quanto piuttosto per descrivervi esattamente cosa accade, perchè non è un processo totalmente automatico.

Quindi, per riassumere…
Voglio distribuire CharMapMe attraverso ClickOnce, uno zip ed il Windows Store.

Di per sè, non è affatto complicato ottenere i package per ciascuna distribuzione.
ClickOnce è in pratica un wizard integrato dentro Visual Studio; dopo averlo configurato la prima volta, sono sufficienti 2-3 click per ottenere i file da uploadare sul sito via FTP.
Ottenere uno zip è pressoché banale: si copiano i file in Bin/Release in un folder dedicato, si cancellano i file non necessari (stando bene attenti), si zippano ed il gioco è fatto.
Ottenere il file .appx è più complesso, ma per ora sorvoliamo.

Ma la questione è: posso automatizzare tutto?
Certo che sì. Andiamo gradualmente. Questa è la struttura di cartelle che compongono CharMapMe, così come vengono scaricate dal TFS su cui sono memorizzati i sorgenti. CharMapMe, perdonatemi, non è (ancora?) open-source.

image

C’è il file di solution CharMapMe.sln, c’è il folder “packages” di NuGet, e poi c’è un folder per ciascuno dei progetti (CharMapMe è l’applicazione client WPF vera e propria, tutti gli altri sono assembly di supporto e di dipendenza).

Ho creato una cartella “Deploy” prima per avere un punto preciso dove finiranno i tre differenti deploy che mi interessa gestire. Vediamo cosa contiene.

image

Elenco e descrivo i file uno ad uno.

  • 7z.exe : è il comando appartenente a 7-Zip per zippare i file (mi serve per creare la distribuzione in modalità Portable)
  • DevOps.bat : è il cuore del sistema, ne parleremo nei prossimi post
  • DevOps.log : log generato automaticamente dall’ultima esecuzione di DevOps.bat
  • VivendoByte.* : certificati digitali per gestire e testare il package Windows Store

Ok, il sistema è pronto.

DevOps.bat è il file batch che si occuperà di generare i tre deploy, invocato on-demand oppure come post build events da Visual Studio.

Ne parleremo con calma nei prossimi post.

Send to Kindle
My personal life

Free ebook

Si sa che nel nostro lavoro non bisogna mai smettere in imparare.

A questo indirizzo GitHub potete trovare un grosso elenco di un sacco di ebook pronti da scaricare. Ce ne sono di tutti i tipi e per tutti i gusti: Assembler, Android, tecnologie Microsoft, HTML, libri puramente teorici su cloud, networking, sistemi operativi. Ce ne sono alcuni su ElasticSearch, Elixir, Git, PowerShell, PHP, Mercurial, .NET SQL e SQL Server. Date un’occhiata al link e troverete sicuramente quello che vi serve e fa al caso vostro!

Da non perdere, insomma:
https://github.com/vhf/free-programming-books/blob/master/free-programming-books.md#aspnet-mvc

Buona lettura ed Happy Coding!

Send to Kindle