Technology Experience
Senza categoria

Silverlight4: iniettare il ViewModel in una vista con l’utilizzo di MEF

Qualche giorno fa un certo Alessandro Scardova ha postato un link ad un articolo di un certo Thomas Martinsen, che mostrava come caricare l’istanza del ViewModel attraverso il Managed Extensibility Framework (per gli amici MEF). La cosa è sicuramente interessante, perchè non andiamo più a “cablare” il fatto che sulla MainPage.xaml deve essere utilizzata la classe MainViewModel. Questa dipendenza viene infatti iniettata, attraverso l’utilizzo degli attributi [Import] da una parte, ed [Export] dall’altra. Questi due attributi sono contenuti nell’assembly System.ComponentModel.Composition.dll, installato automaticamente – ricordiamolo – con il .NET Framework 4.

La soluzione, ripeto, è interessante, ma non mi piace più di tanto, perchè (cito dall’articolo originale di Thomas) “In the code-behind of the MainPage.xaml file hosting the view, I have created a property called ViewModel.” Insomma, è necessario aggiungere una proprietà pubblica della classe MainPage, agendo quindi sul file MainPage.xaml.cs, ovvero il code-behind, e quindi vanificando un po’ lo sforzo di adottare M-V-VM. Non voglio fare il fanatico, se c’è da toccare il code-behind facciamolo pure, ma consci del fatto che potrebbero correre dei rischi se il file viene toccato da altre persone, che magari per un motivo o per l’altro cancellano il nostro codice.

Ma la soluzione ovviamente c’è, e sono lieto di proporvela.

L’idea che ho avuto è quello di creare una classe ViewModelLocator, definita come segue:

public class ViewModelLocator
{
 private MainViewModel _mainViewModel;
 
 public ViewModelLocator()
 {
 CompositionInitializer.SatisfyImports(this);
 }
 
 [Import]
 public MainViewModel Main
 {
 get { return _mainViewModel; }
 set { _mainViewModel = value; }
 }
 
 public void ClearMain()
 {
 _mainViewModel.Cleanup();
 _mainViewModel = null;
 }
 
 public void Cleanup()
 {
 ClearMain();
 }
}

 

Non è tutta farina del mio sacco. Ho trascorso questa domenica pomeriggio a studiare il MVVM Light Tookit, di un certo Laurent Bugnion. Questa classe ViewModelLocator è la classe che vi trovate quando create un nuovo progetto usando questo tookit. Io l’ho solo ripulita un po’ apposta per questo esempio. Lo scopo di questa classe è quello di esporre – tramite public properties – tutti i ViewModel necessari al nostro progetto. Data la semplicità, in questo momento il ViewModel è uno solo, MainViewModel, ed è marcato con l’attributo [Import]. Questo significa che l’engine di MEF dovrà cercare ed iniettare la dipendenza, e lo fa con la chiamata a CompositionInitializer.SatisfyImports(this) che vedete nel costruttore della classe stessa.

A questo, basta andare nell’App.xaml ed aggiungere nelle Resources un’istanza di ViewModelLocator, come ho fatto qui sotto:

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
 x:Class="MvvmLight1.App"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:vm="clr-namespace:MvvmLight1.Services;assembly=MvvmLight1.Services"
 mc:Ignorable="d">
 <Application.Resources>
 <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
 </Application.Resources>
</Application>

 

Ho dichiarato il prefix “vm” ed ho istanziato ViewModelLocator.

A questo punto rimane solo un’ultima cosa: creare il MainViewModel vero e proprio, che decoreremo con l’attributo [Export] per informare l’engine di MEF. Supponiamo di scrivere quanto segue:

[Export(typeof(MainViewModel))]
public class MainViewModel : ViewModelBase
{
 public string Welcome
 {
 get
 {
 return "Welcome to MVVM Light";
 }
 }
 
 public MainViewModel()
 {
 if (IsInDesignMode)
 {
 // Code runs in Blend --> create design time data.
 }
 else
 {
 // Code runs "for real"
 }
 }
}

 

Questa è una normalissima classe ViewModel, che eredita da GalaSoft.MvvmLight.ViewModelBase. Notate – appunto – l’aggiunta dell’attributo [Export]. A questo punto, cosa accade? Accade che questo [Export] e l’[Import] messo sul ViewModelLocator si accoppiano fra loro, e MEF è quindi in grado di risolvere la dipendenza. Notate la presenza della public property Welcome sul ViewModel: è di tipo stringa, quindi possiamo bindarla ad una normale TextBlock sulla UI.

Consiglio dell’ultimo minuto :  provate a mettere un breakpoint sul costruttore del ViewModelLocator, dove viene chiamato CompositionInitializer.SatisfyImports(), cioè la risoluzione delle composizioni da parte di MEF. Vedrete che prima della chiamata this.Main è null, mentre dopo la chiamata this.Main vale l’istanza del ViewModel marcata con Export.

Ed il tutto senza toccare il code-behind dello UserControl o della Page!!!
Questo sì che è vero MVVM!!!!

Send to Kindle

Igor Damiani

La sua passione per l'informatica nasce nella prima metà degli anni '80, quando suo padre acquistò un Texas Instruments TI-99. Da allora ha continuato a seguire l'evoluzione sia hardware che software avvenuta nel corso degli anni. E' un utente, un videogiocatore ed uno sviluppatore software a tempo pieno. Igor ha lavorato e lavora anche oggi con le più moderne tecnologie Microsoft per lo sviluppo di applicazioni: .NET Framework, XAML, Universal Windows Platform, su diverse piattaforme, tra cui spiccano Windows 10 piattaforme mobile. Numerose sono le app che Igor ha creato e pubblicato sul marketplace sotto il nome VivendoByte, suo personale marchio di fabbrica. Adora mantenere i contatti attraverso Twitter e soprattutto attraverso gli eventi delle community .NET.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.