4. Mumble...mumble... (upfront)
• È difficile? parecchio... :-)
• Siamo troppo abituati al «coupling» tra componenti visuali e logica
• Quindi...il gioco vale la candela?
• Tutta la vita, in particolare al crescere dall’applicazione:
• Sia verticalmente: complessità;
• Sia orizzontalmente: versioning nel tempo;
• C’è rischio di addiction? «Purtroppo» si :-)
• Una volta che ci avete preso la mano scrivereste anche il notepad
con M-V-VM;
5. Why?... pecccchè?
• Perchè adottare un pattern per la presentazione dei dati?
• SoC e SPoR sono sicuramente due buonissimi motivi:
• Diamo un boost alla manutenibilità liberandoci dello spaghetti code;
• Cerchiamo di separare nettamente le figure coinvolte:
• Il designer non è il developer e il devloper non è il designer;
• Non necessariamente sono figure fisicamente diverse, ma
sicuramente sono momenti diversi;
• Introduciamo la possibilità di testare il comportamento
della logica che gestisce la UI;
6. Talebani o Libertini?
• Dogma: Un pattern è un pattern quindi va sempre
adattato al contesto in cui viene calato;
• Model View ViewModel però...:
• Nella sua implementazione con Wpf/Sl è giovane;
• Molte cose sono decisamente borderline;
• Il contesto d’uso classico, un rich client, lo rende complesso da
applicare perchè le celte da fare sono moltissime:
• MVC con Asp.net ha decisamente poca libertà di manovra per come è
fatto http;
• MVP con WinForms è molto limitato dalle limitazioni di WinForms;
• All’inizio essere un po’ talebani aiuta a pensare;
9. Overview
DependencyObject POCO Instance
Tipicamente la UI I nostri dati
Dependency CLR
Binding Expression
Property Property
• La BindingSource può essere una qualsiasi
istanza, senza nessun requisito;
• Il BindingTarget deve essere una Dependency
Property, e quindi un l'istanza di un Dependency
Object;
10. DataFlow Direction
DependencyObject POCO Instance
Dependency CLR
- OneWay
Property Property
- TwoWay
- OneWayToSource
• OneWay: il binding è monodirezionale:
• da Source verso Target;
• è il default per controlli i read-only (eg. TextBlock);
• TwoWay: il binding è bidirezionale:
• I dati viaggiano da Source verso Target e viceversa;
• È il default per tutti controlli r/w (eg. TextBox)
• OneTime: il binding viene valuato una sola valta:
• da Source verso Target;
11. Data «Triggers»
• Cosa causa il pull/push dei dati?
• Source (data) Target (UI):
• OneWay e TwoWay: la source deve implementare un motore di notifica
come ad esempio INotifyPropertyChanged;
• Nel caso di collection la collection deve supportare la notifica delle
variazioni interne... More to come;
• Target (UI) Source (data):
• TwoWay e OneWayToSource:
• «Default»: predefinito, la source viene aggiornata nel momento in cui il
controllo corrente perde il focus;
• «PropertyChanged»: la Source è aggiornata ad ogni variazione della
proprietà del target;
• «Explicit»: la source viene aggiornata solo su richiesta esplicita:
BindingExpression.UpdateSource();
13. Da WinForms a *.DataContext
• In Windows Forms era responsabilità di ogni singolo
controllo esporre un sistema per il data binding:
• .DataSource;
• .SetDataBinding(...);
• TextBox.????;
• FrameworkElement espone DataContext:
• Razionalizza e uniforma l'approccio;
• È una Dependency Property:
• beneficia del concetto di ereditarietà del valore;
• Supporta a sua volta data binding;
14. Binding Pipeline
TextBlock MyObject
Source Target
Text DateTime
Property Target Source Property
• Per impostazione predefinita il motore di binding per
la conversione chiama ToString()
• NB: In assenza di un template;
• Possiamo intervenire nel processo di conversione
scrivendo un ValueConverter
15. Binding Pipeline: IValueConverter
• IValueConverter definisce solo 2 metodi:
• Convert( ... ): viene invocato dal processo di binding nel momento
in cui il dato si muove dalla Source verso il Target;
• ConvertBack( ... ): viene invocato durante il passaggio
opposto, mentre il dato viaggia dal Target verso la Source;
<TextBlock Text="{Binding
Path=PropName,
Converter={StaticResource myConverter}}" />
17. Separation of Concern
• Il concetto di command in Silverlight/Wpf è basato sul
command pattern:
• La logica di esecuzione è independente dalla UI;
• Incapsulare la logica di esecuzione permette di avere più entry-
point verso quel comando
• Chi si ricorda le Action di delphi...?
18. L'interfaccia ICommand
• CanExecute( Object ):
• L'invoker può sapere se il comando può essere eseguito in un
determinato contesto;
• Execute( Object ):
• L'invoker può invocare il comando;
• CanExecuteChanged event:
• Il comando può notificare l'invoker di eventuali variazioni del suo
stato;
20. Please welcome M-V-VM
presentation
View
DataBinding
Command
engine
Il centro del ViewModel D.I.
mondo!
Repository<T>
Model
data
Adapter
Somewhere in
time...
22. Actors: Model
• È uno ed uno solo:
• Rappresenta i dati, che in quanti tali, vanno sempre protetti;
• Può essere un Object Model o un Domain Model:
• È molto più facile che sia un «Object Model» condito da servizi;
• È responsabile della validazione statica:
• Le regole di validazione non pertinenti al caso d’uso;
• È totalmente ignaro del mondo in cui è inserito:
• Non implementa INotifyPropertyChanged;
23. Actors: ViewModel
• Rappresenta un caso d’uso del Modello:
• È un aggregatore di logica e dati;
• È responsabile della validazione contestuale:
• Casi d’uso diversi con regole di validazione diverse per dati uguali;
• È conscio di essere in un mondo basato su DataBinding:
• Implementa INotifyPropertyChanged, ma non deriva da Dep.Obj;
• E’ responsabile del «flattening» del grafo:
• Ricuce l’uso dei comodi ma scomodi converter;
24. Actors: View
• È «stupidamente» legata al ViewModel:
• Non prende la benchè minima decisione;
• Deve essere a prova di designer:
• Quindi non deve aver nessun rapporto con il codice;
• Deve poter essere disegnata:
• Focus on the «Blendability»;
25. Who comes first?
• Abbiamo un duopolio...
• ma...chi comanda?
• ViewModel first?
• View first?
• Io sono per il ViewModel first perchè vedo la View come
una passive-view;
27. Recap
• Abbiamo definito il modello: Person/Address;
• OT: Abbiamo introdotto il concetto di DataContext;
• Abbiamo costruito dei casi d’uso sul modello: ViewModel
• Visualizzare un elenco di persone;
• Visualizzare il dettaglio della persona selezionata;
• Abbiamo «visualizzato» i casi d’uso: View;
• Potevamo scrivere dei test prima di arrivare alla View?
• Servono ancora gli «U.A.T.»?