Le problematiche più comuni di un'architettura M-V-VM con WPF
di Cristian Civera, in Windows Presentation Foundation, 6 ottobre 2009
Archiviato in: .NET Framework, .NET Framework 3.0, .NET Framework 3.5, Architettura, Windows Presentation Foundation, XAML, Pattern
5 pagine in totale: <<Indietro 1 2 3 4 [5]
Il pattern Inversion of Control
La tematica affrontata in questo articolo è sostanzialmente basata sulla relazione tra la View e ViewModel e il dialogo fra loro. Attorno a questo problema sono molto le soluzioni applicate tra cui l'Inversion of Control (IoC), partendo dal presupposto che l'oggetto che si necessita non si risolve direttamente istanziandolo, ma bensì lo ottiene da un contenitore che lo identifica attraverso dei contratti prestabili. Tra le tecniche per mettere in pratica questo pattern sono presenti: la Dependency Injection e il Service Locator.
Con la prima tecnica, prendendo spunto dalla necessità originale di chiudere la finestra, si definisce un'interfaccia di cui il VM necessiti e ignori l'implementazione. A runtime la risoluzione viene demandata al contenitore che, in base ai tipi registrati e alla configurazione, istanzia l'oggetto e ne gestisce il ciclo di vita. Invece, con il Service Locator, partendo sempre dalla definizione di un'interfaccia, si ottiene un'istanza all'oggetto che la implementa, ma non avviene nessuna risoluzione, nè gestione del ciclo di vita; semplicemente l'oggetto viene passato attraverso un intermediario.
Nel toolkit WPF Onyx sono presenti entrambe le implementazioni e sono inoltre presenti interfacce specifiche per la gestione delle finestre di dialogo, delle View e del VM. Qualora si voglia far affidamento ad un framework di IoC basato su Dependency Injection (detto anche IoC Container), si può utilizzare Unity, sviluppato da Microsoft.
Non è scopo di questo articolo parlare di questo framework, ma è possibile vedere brevemente quali sono i vantaggi che può dare. Una volta installato, gli assembly Microsoft.Practices.Unity e Microsoft.Practices.ObjectBuilder2 vanno referenziati permettendo di definire il contenitore responsabile di risolvere i tipi, istanziarli, mantenerli in vita e iniettare le dipendenze. Nell'entry point dell'applicazione si istanzia quindi il contenitore andando a registrare le View e i VM.
public class ViewModelLocator { private static IUnityContainer _container; private static ContainerControlledLifetimeManager lifetimeManager = new ContainerControlledLifetimeManager(); static ViewModelLocator() { _container = new UnityContainer(); _container.RegisterType<ICloseView, MainWindow>(lifetimeManager); _container.RegisterType<MainViewModel>(); } }
L'utilizzo del lifetime manager permette di indicare il ciclo di vita dell'istanza del MainWindow che, se non specificato diversamente, non viene mantenuta; in tal caso ad ogni chiamata al metodo Resolve viene creato un nuovo oggetto.
Definito il contenitore, si può quindi ottenere una nuova istanza o ottenere quella già creata, secondo le regole di lifetime, attraverso il metodo Resolve. La classe ViewModelLocator può quindi essere cambiata utilizzando il contenitore per ottenere l'istanza:
public static MainViewModel MainStatic { get { return _container.Resolve<MainViewModel>(); } }
La classe MainViewModel può ricevere facoltativamente nel costruttore il contenitore, attraverso l'interfaccia IUnityContainer, utile poi per poter risolvere dal VM dipendenze cercandole per il tipo di interfaccia e ignorando qual'è il tipo effettivo che le implementa. L'interfaccia ICloseView, per esempio, creata appositamente e implementata dalla finestra principale, può offrire un metodo per chiudere la finestra e disporre un modo alternativo per raggiungere l'obiettivo perseguito in questo articolo. L'implementazione del CloseCommand può quindi essere riscritta in modo da risolvere l'oggetto che implementa ICloseView (l'istanza attuale della View) e chiamare il relativo metodo Close.
private void Close() { container.Resolve<ICloseView>().Close(); }
Il metodo Close è già presente nella classe del framework Window, perciò basta indicare l'interfaccia nella dichiarazione.
public partial class MainWindow : Window, IMessageRecipient, ICloseView { ...
L'esempio visto è solo un assaggio delle potenzialità di Unity, le quali si estendono anche nella possibilità di iniettare dipendenze nelle proprietà, risolvere per nome e impostare delle regole di matching.
Infine, un altro IoC Container da tenere in considerazione che sfrutta la dependency injection è Spring.NET, il quale permette di creare facilmente proxy che aggiungono funzionalità iniettando codice, il tutto definendo semplicemente i settaggi nel file di configurazione.
Tutto questo ha però un costo perché richiede del lavoro di reflection e una maggiore preparazione iniziale dovuta alla creazione e alla configurazione del motore IoC che si sceglie.
Conclusioni
In questo articolo si sono analizzati le problematiche più comuni che si trovano quando si sviluppano applicazioni basate sull'architettura M-V-VM. Tra questi rientrano l'uso del code-behind per gestire certe situazioni e le difficoltà nel far comunicare il ViewModel con la View. Partendo quindi da un approccio più semplice basato sugli eventi, si sono visti gli svantaggi che questo approccio comporta e perciò si sono analizzati due pattern diffusi: il Mediator pattern e l'Inversion of Control. Entrambi mantengono il disaccoppiamento tra i due strati e quindi la completa possibilità di operare test automatici. Il tutto è stato affrontato con un occhio di riguardo ai toolkit disponibili che ci possono venire in aiuto per essere più produttivi nello sviluppo.
Le tematiche affrontate non vogliono assolutamente definire in modo esatto come organizzare un applicazione, ma hanno semplicemente lo scopo di dare la giusta conoscenza in modo da poter scegliere il migliore approccio per ogni esigenza.
5 pagine in totale: <<Indietro 1 2 3 4 [5]
Attenzione: Questo articolo contiene un allegato.
Contenuti dell'articolo
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimeti
-
Introduzione a Team Foundation Server 2010
-
Multithreading e parallelismo con il .NET Framework 4.0
-
Le novità nel .NET Framework 4.0 di WPF, WCF e WF
-
Le novità di Visual Basic 2010 e C# 4
-
Mostrare le camere di sorveglianza tramite il .NET Micro Framework
-
La piattaforma Microsoft per il cloud computing: Windows Azure
-
Interoperabilità con WCF: invocare servizi da PHP e Flash
-
Le novità di Windows 7 per gli sviluppatori
-
Costruire una chat per Silverlight con il PollingDuplexHttpBinding

Commenti
mi piace
non mi piace
Facebook
Twitter









