[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:
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.
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!!!
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!