Le problematiche più comuni di un'architettura M-V-VM con WPF

5 pagine in totale: <<Indietro 1 2 3 [4] 5 Avanti >>

Ottenere le instanze del ViewModel

Con i primi passi nel mondo dell'architettura basata su M-V-VM si apprende come il ViewModel sia un oggetto funzionale alla View. E' quest'ultima che in genere lo istanzia e lo imposta come DataContext in modo da sfruttare il data binding per il caricamento di dati, l'esecuzione di comandi e animazioni. La tecnica più semplice per fare ciò consiste nell'istanziare il VM nel costruttore e impostarlo nel contesto:

public partial class MainWindow : Window, IMessageRecipient 
{ 
    public MainWindow() 
    { 
        this.DataContext = new MainViewModel(); 
    } 
}

In alternativa si può fare la stessa cosa sfruttando il markup XAML, funzionante anche all'interno di Expression Blend:

<Window x:Class="CustomersApplication.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:vm="clr-namespace:CustomersApplication.ViewModel"> 
    <Window.DataContext> 
        <vm:MainViewModel /> 
    </Window.DataContext>

Durante lo sviluppo di un'applicazione è però difficile pianificare e individuare esattamente le unità logiche e suddividere correttamente i vari VM. In certe circostanze è poi inevitabile dover accedere ad un altro VM per ottenere informazioni o eseguire su di esso delle operazioni. Anche dalla View a volte è necessario invocare metodi sul rispettivo VM, perché non è magari possibile passare attraverso i comandi e per semplificare, se le circostante lo permettono, si scrivono poche righe di codice nella View.

Per accedere a VM sottostante occorre quindi fare il cast del DataContext sul tipo specifico e interrogare le informazioni che interessano. Questo purtroppo non è sempre possibile farlo, perché per esempio non è possibile accedere alla View da un ipotetico VM.

Toolkit come WPF Toolkit e MVVM Light Toolkit propongono due soluzioni molto simili tra loro che sostanzialmente centralizzano la creazione dei ViewModel e permettono di accedervi attraverso proprietà statiche. In pratica un'ipotetica classe ViewModelLocator, visibile da View e VM, può contenere una proprietà statica Main di tipo MainViewModel che mantiene un'unica istanza accessibile da qualsiasi punto dell'applicazione.

public static class ViewModelLocator

public static class ViewModelLocator 
{ 
    private static MainViewModel _main; 
 
    public static MainViewModel Main 
    { 
        get 
        { 
            if (_main == null) 
                _main = new MainViewModel(); 
            return _main; 
    } 
}

L'utilizzo all'interno della View si traduce in una singola riga che si appoggia alla markup extension x:Static:

<Window x:Class="CustomersApplication.MainWindow" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:vm="clr-namespace:CustomersApplication.ViewModel" 
        DataContext="{Binding Source={x:Static vm:ViewModelLocator.Main}}">

Tutto questo purtroppo non è ancora sufficiente se si vuole avere un supporto a design time con Expression Blend. Occorre infatti usare il ViewModelLocator come una risorsa; basta quindi rendere la classe anche di istanza creando proprietà ponte sui membri statici:

public class ViewModelLocator 
{ 
    // codice dell'esempio precedente 
 
    public MainViewModel Main 
    { 
        get { return MainStatic; } 
    } 
}

Cambia inoltre leggermente l'utilizzo nel markup: prima di tutto a livello di applicazione si istanzia l'oggetto così da renderlo disponibile per tutte le View.

<Application x:Class="CustomersApplication.App" 
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             xmlns:vm="clr-namespace:CustomersApplication.ViewModel">        
    <Application.Resources> 
        <vm:ViewModelLocator x:Key="locator" /> 
    </Application.Resources> 
</Application>

Nella View poi il DataContext si imposta usando la risorsa e appongiandosi alla proprietà di istanza Main che fa da ponte su MainStatic, ottenendo il pieno supporto a design time di Expression Blend.

DataContext="{Binding Main,Source={StaticResource locator}}"

L'aspetto interessante di questo è approccio è che in certe situazioni, sebbene la View possa morire perché non più visualizzata, il relativo VM continua a funzionare e a mantenere lo stato (elementi selezionati, operazioni in corso) che l'utente si ritrova non appena la View riparte.

Purtroppo questo è anche il punto critico perché in certe circostanze il ciclo di vita del ViewModel non deve essere perenne, ma gestito secondo certe logiche, o morire non appena la sua utilità è terminata.

5 pagine in totale: <<Indietro 1 2 3 [4] 5 Avanti >>

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.

Segnala su:  Facebook  Messenger  Twitter        |

TUTORIALS

Silverlight

.NET Framework

Accesso ai dati

Architettura e design software

Windows Azure

TOP TEN ARTICOLI
ARTICOLI VIA E-EMAIL

Iscriviti alla nostra newsletter nuoviarticoli per ricevere via e-mail le notifiche!

Iscrivi subito! »»»

MEDIA
IN EVIDENZA
MISC