Esempio applicazione pattern MVVM in Silverlight.

domenica, 20 giugno 2010 00.18 by marcoCodeBlog
  • Ecco un esempio di implementazione del modello MVVM descritto nel post. Creremo una classe libro e la visualizzeremo in una view di tipo silverlight. Questo esempio trova la sua parte teorica nel post precedentemente scritto. Di seguito riportiamo una rappresentazione grafica di questo esempio per comprendere al meglio i nomi delle classi e dei metodi che useremo all'interno di un pattern MVVM.

 

  • Dal menù dei progetti di visual studio 2010 selezionare un modello di applicazione “Silverlight Application” e mettere come nome “MVVMExamples” come è mostrato nell’immagine sottostante:

 

  • nella schermata che compare lasciare tutte le impostazioni come compaiono a video vedi immagine

 

  • ora si aprirà la solution di Visual Studio 2010 e nel solution explorer dovremmo trovare la situazione rappresentata dall’immagine:

 

  • ora andiamo a creare tre cartelle in cui andremo a inserire i file delle classi che costituiscono il modello MVVM. Le cartelle sono nomiate con lo stesso nome delle componenti che danno il nome al pattern:ModelView,Model,View.

 


 

  • Ora abbiamo bisogno di una classe che gestisca il comportamento degli eventi e che derivi da EventArgs. In particolare vogliamo che quando il metodo che carica la lista dei libri ha finito di fare il suo lavoro scateni un evento BookLoading, questo perchè nel web voglio avere un funzionamento asincrono per non tenere la pagina impegnata per tutto il caricamento della lista di libri.


 

  • creiamo ora una classe c# (book.cs) all’interno della cartella Model. Questa classe rappresenta il modello dei dati.Il contenuto del file book.cs è il seguente:

     

 

  • creiamo una classe c# (ViewModel.cs) all’interno della cartella ViewModel. Questa classe farà da classe base per tutti i view model e deve derivare dall’interfaccia INotifyPropertyChanged. Tale interfaccia serve per notificare al client che il valore di una proprietà è cambiato. Il contenuto del file ViewModel.cs è il seguente:

 

  • ora dobbiamo implenetare un viewmodel specifico per i book che derivi dal viewmodel definito prima. Quindi creiamo una classe bookViewModel.cs.

 

  • la parte di gestione del MVVM è quasi realizzata basta soltanto occuparsi della parte di visualizzazione cioè della view. Per fare questo bisogna modificare la MainPage.xaml del nostro progetto MVVMExamples indicando il name space delle viste  xmlns:myviews="clr-namespace:MVVMExamples.View" e definendo una zona dove verà visualizzata la view "BookView":
    <UserControl x:Class="MVVMExamples.MainPage"
        xmlns="
    http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="
    http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="
    http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="
    http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:myviews="clr-namespace:MVVMExamples.View"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400"><Grid>
            <myviews:BookView Width="800" Height="600"  />
        </Grid>
    </UserControl>
  • ci manca solo progettare l'interfaccia grafica e legarla al nostro viewmodel attraverso il binding. L'interfaccia che io voglio avere è una lista a sinistra che rappresenta i libri e ogni volta che vi clicco sopra compare a destra la descrizioen del libro come si vede nell'immagine sotto: 



    Il codice XAML per realizzare l'inerfaccia è il seguente:

    <UserControl x:Class="MVVMExamples.View.BookView"
        xmlns="
    http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="
    http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="
    http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="
    http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:data="clr-namespace:MVVMExamples.ViewModel"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
        <UserControl.Resources>
            <data:BookViewModel x:Key="TheViewModel"
                             d:IsDataSource="True" />
        </UserControl.Resources>

      <Grid x:Name="LayoutRoot" DataContext="{StaticResource TheViewModel}">
            <Grid.RowDefinitions>
                <RowDefinition Height="134" />
                <RowDefinition Height="166*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="140" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="196" />
            </Grid.ColumnDefinitions>
            <ListBox Grid.Column="0" Margin="5"
                     ItemsSource="{Binding ListBook}"
                     DisplayMemberPath="Title"
                     SelectedItem="{Binding SelectedBook, Mode=TwoWay}" 
    />

            <!-- Databind the right section to ViewModel.SelectedPerson property -->
            <Grid x:Name="BookDetails" Grid.Column="1" DataContext="{Binding SelectedBook}" Margin="5" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="150" />

     <Button Content="Button" Grid.Column="2" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="33,86,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
        </Grid>
    </UserControl>
     

               </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="30" />
                    <RowDefinition Height="20" />
                    <RowDefinition Height="20" />
                    <RowDefinition Height="20" />
                    <RowDefinition Height="20" />
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" Grid.ColumnSpan="2" Text="Book Details" FontSize="15" />
                <TextBlock Grid.Row="1" Grid.Column="0" Text="Name" />

           <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Title, Mode=TwoWay}" />
                <TextBlock Grid.Row="2" Grid.Column="0" Text="Age" />
                <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Description, Mode=TwoWay}" />
                <TextBlock Grid.Row="3" Grid.Column="0" Text="City" />
                <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding ISBN, Mode=TwoWay}" />
            </Grid>

  • Ecco il nostro programmino MVVMExamples.zip (82,29 kb)  che rispetta il pattern MVVM completato. Spero di essere stato chiaro e per ogni informazione non esitate a contattarmi.

 

Il Pattern MVVM per WPF e Silverlight

venerdì, 11 giugno 2010 23.58 by marcoCodeBlog

Di recente per motivi di lavoro ho dovuto scrivere una applicazione in WPF/Silverlight. Per costruire la mia applicazione e per rimanere fedele al principio architetturale della stratificazione a livelli ho cercato un pattern adatto..
Come prima cosa ho cercato conforto nel pattern MVC.Per chi non ne ha mai sentito parlare l'MVC è un pattern architetturale che isola in modo soddisfacente la logica dell'interfaccia utente dalla logica di business. In tal modo risulta facile apportare modifiche in una delle due parti senza che questa modifica si ripercuota su altre parti. La parola MVC ricalca la struttura che è composta da tre componenti:

  • Model: Rappresenta il modello dei dati
  • View:Rappresenta la vera interfaccia utente con i vari controlli visuali.
  • Controller: si occupa di gestire  la richiesta e di coordinarne la logica di esecuzione utilizzando il Model e selezionando la View da associare per la risposta.

L’utente interagisce con la View che comunica le chiamate al controller che a sua volta comunica con  il model che si occupa di apportare un aggiornamento nella view. Di seguito lo schema di funzionamento dei tre moduli.

Questo tipo di pattern non lavora bene con le le interfacce utente ottenute con la programmazione dichiarativa (cioè XAML) in quanto vi sono moltissimi costrutti di programmazione ,soprattuto nel contesto di associazione dati, che consentono di risparmiare un sacco di codice. Ma il fattore principale riguarda il fatto che tutto ciò che in precedenza doveva essere programmato in C # è ora possibile farlo usando XAML attraverso trigger o eventi.
Dopo aver compreso che non potevo utilizzare il pattern MVC ho provato ad applicare il pattern MVP in cui viene sostituito al pattern precedente il controller con un altro modulo che è il presenter e quindi si ha:

  • Model: Rappresenta il modello dei dati
  • View:Rappresenta la vera interfaccia utente con i vari controlli visuali.
  • Presenter: è responsabile della gestione dello stato delle View e della loro inizializzazione.
     

Anche questo pattern però non si adatta al modo di lavorare di WPF/Silverlight in quanto  lo stesso XAML prevede già la gestione degli stati senza dover avere un modulo che se ne occupi.

 

Quindi vi è la necessità di avere un altro pattern che in qualche modo è il mix del pattern MVC e del pattern MVP. Questo pattern è MVVM (Model-View-ViewModel) che come gli altri pattern visti sopra ha lo scopo di disaccoppiare il più possibile per arrivare al concettto di “Separation of Concerns”. Il MVVM è composto dalle seguenti componenti:

  • Model: è responsabile di esporre i dati in modo che sia facilmente consumabile da WPF. Si deve implementare INotifyPropertyChanged o INotifyCollectionChanged a seconda dei casi.
  • View: è l'interfaccia utente reale. Il processo che usiamo è quello di impostare il DataContext all’interno del ViewModel di una View in questo modo è reso più facile usare il Binding attraverso il ViewModel. Idealmente, la View può essere implementata esclusivamente con Xaml senza usare il code-behind e questo proprio perché si possono usare le proprietà di una classe viewmodel.
  • ViewModel: è un modello per una View in una applicazione. Questo componente esponei dati relativi (proprietà)  alla View e non solo ma espone anche i comportamenti (metodi) delle View che di solito vengono richiamati da dei comandi. Il modello è abbastanza specifico per una certa View all’intenro di una applicazionevi. Poiché queste classi sono separate da quello della  UI sono relativamente semplici da applicare ai test di unità.

 Di seguito vediamo la rappresentazione grafica del pattern:

  

Quindi se andiamo ad analizzare i riferimenti che legano i vari moduli tra le varie architetture MVC,MVP.MVVM abbiamo il seguente schema:

E' Possibile trovare un esempio pratico dell'MVVM qui.

Approcio “Composite” per realizzare applicazioni WPF e Silverlight – Parte 1

sabato, 5 giugno 2010 10.24 by marcoCodeBlog

Pochi giorni fa mi sono imbattuto in alcune linee guida (Guidance) interessanti per sviluppare con WPF e Silverlight. Queste guidance introducono un approcio per affrontare la progettazione e la realizzazione di applicazioni di livello Enterprise includendo al loro interno diversi pattterns di programmazione. L’applicazione di queste guidance permette di realizzare delle applicazioni molto flessibili con un basso accoppiamento e con la possibilità di evolvere le singole componenti in modo indipendentemente ma facilmente integrabili tra di loro; tali applicazioni vanno sotto il nome di Composite Application.

Problematica:
Tipicamente quando si progetta un software ci si trova davanti alla sfida di progettarlo pensando alla sua evoluzione nel tempo in quanto per svariati motivi i requisiti cambiano. E proprio per questo motivo che è importante costruire l’applicazione in modo tale che sia flessibile e facile da modificare o da estendere nel tempo. Ovviamente progettare un software pensando con un occhio di riguardo alla flessibilità diventa difficile in quanto richiede un’ archittettura che cerca di mantenere indipendenti le singole parti di un sistema in modo tale da poter  facilitare lo sviluppo il test e gli aggiornamenti senza che le atttività su una singola parte comprometta le altre componenti dell’applicazione.

Soluzione:
Un modo per risolvere le problematiche viste sopra è quello di dividere l’applicazione in componenti che siano poco accoppiate (loosley coupled) inoltre devono essere indipendenti ma che sia facile integrarle tra di loro in una unica applicazione “Shell”. Le applicazioni che sono costruite in questo modo si chiamano “composite application”.

Composite Application
Questo tipo di applicazioni sono molto adatte per una vasta gamma di scenari in cui si utilizzano applicazioni client. Una applicazione di questo tipo può essere sempre usata quando abbiamo dei componenti indipendenti che evolvono nel tempo e che stanno nella stessa UI e che sono correlati tra di loro ma che sono sviluppati da diversi team.

Composite Application Guidance
Esitono quindi delle linee che permettono di aiutarci nello sviluppo di Composite Application e inoltre  vi è una
libreria (CAL = Composite Application Library) che aiuta gli sviluppatori nell’utilizzare tali concetti. Analizziamo ora i concetti di base  per la costruzione di Composite Application che sono stati riportati nella CAL.

  • UI Composition

  • Modularity

  • Container

  • Multi-targeting.

UI Composition
In queto tipo di applicazioni l’interfaccia in genere è popolata da diversi componenti visuali che sono poco accoppiati e che vengono chiamati Views. Una singola view è definita all’interno di un modulo dell’applicazione. Tutte le view si sono raccolte dal un contenitore che si chiama “Shell”  come si vede nell’immagine.

Ovviamente le singole view devono essere poco loosley coupled e devono essere generate a run-time. Per fare questo abbiamo bisogno di una particolare architettura che metta assieme più strategie per fornire il risultato desiderato. Le strategie utilizzate sono le seguenti:

  • View composition: La composizione di view precede che ci siano delle zone che si chiamano “named location” che sono definite a priori dallo sviluppatore e a run-time le view vengono assegnate ad una “named location” piuttosto che all’altra in due modi:

Automaticamente con il modello “View Discovery" la CAL mette a disposizione il RegionViewRegistry per questo tipo di implementazione)

Con la programmazione attraverso il modello “View injection” la CAL mette a disposizione il Region Manager e l’interfaccia IRegion)

Le View sono implementate usando “separated presentation pattern” come i modelli: MVP,presentation Model, MVVM in cui si ha una separazione della logica di presentazione da quella di business e quindi vi sono dei moduli “presenter” o “presentermodel” che contengono la logica di presentazione per la view e sono legati durante la composizione.

Il programmatore possiede due modalità per poter progettare la composizione delle view:

View-First Composition: in cui la view viene creata logicamente prima  seguita dal presenter dal quale dipende. Questo spiega il perché questo tipo di approcio si sposa bene con il “view discovery” in quanto la view per una particolare “named location” viene creata automaticamente e seguita dal presenter in base alla relazione sul register.

Presenter-First: composition in cui il presenter è creato logicamente prima seguito dalla vista dal quale dipende.

  • Commanding: In una applicazione in cui si usa il “separated presentation patterns” vi è un disaccoppiamento tra la view e la logica di presentazione. Però cosa succede se abbiamo delle azioni dell’utente sulla view? Devono essere indirizzate su un appropriato handlers al di fuori della view che avrà il suo codice nel moduli di presenter. Inoltre gli elementi di una UI associati con delle azioni potrebbero essere abilitati o disabilitati in base agli stati che assume l’applicazione. Per questo tipo di esigenza WPF introduce il concetto di Commands che supporta questo tipo di interazioni. Questo lo fa utilizzando la tecnica di associare “bound” un elemento di UI ad un comando che è rappresentato da un handler che contiene la logica. Inoltre utilizzando la tecnica del Bound si può abilitare o disabilitare un componente di UI semplicemente abilitando o disabilitando il comando a cui è associato. In questo caso WPF mette già a disposizione il meccanismo di ggestione degli handlers attraverso RoutedUICommand e i comandi devono derivare da ICommand. Ci sono due possibili meccanismi da utilizzare per la gestione dei comandi:

Command Delegation :questo approcio  usa il comando come un delegato per la logica di handling che a questo punto può trovarsi su una classe esterna come un presenter, service o un controller. Il comando richiede due metodi:

Execute() che serve per eseguire la logica associata al comando.

CanExecute() che serve per sapere se un comando può essere eseguito o meno.

Command composition: è una variante di quanto visto prima in quanto la logica di gestione è assegnata ad una serie di comandi figli debolmente accoppiati. Questo approcio prevede un metodo per registrare i comandi figli ad un comando padre e in questo caso il metodo CanExecute ritornerà sempre false almeno che tutti i comandi figli non ritornano true. Per la gestione di questa particolare implementazione dei comandi il CAL mette a disposizione due classi la DelegateCommand<T> e la CompositeCommand.

  • Eventing: Generalmente in applicazioni composte come quelle che stiamo trattando i vari componenti quali i presenter, services e i controller risiedono in moduli differenti che spesso devono comunicare tra di loro. Per fare questo utilizzaimo il Design pattern del publisher/subscriber, utilizzato per la comunicazione asincrona fra diversi. In questo schema, mittenti e destinatari di messaggi dialogano attraverso un tramite, che può essere detto dispatcher. Il mittente di un messaggio (detto publisher) non deve essere consapevole dell'identità dei destinatari (detti subscriber); esso si limita a "pubblicare" il proprio messaggio al dispatcher. I destinatari si rivolgono a loro volta al dispatcher "abbonandosi" alla ricezione di messaggi. Il dispatcher quindi inoltra ogni messaggio inviato da un publisher a tutti i subscriber interessati a quel messaggio. Ci sono diversi modi di  implementare questo pattern ma per le Composite Application Guidance ne esistono due:

Event Services: Con questo approcio si usano il sistema di gestione degli eventi del .Net framework. Sia il publisher che il subscriber si referenziano alle interfacce del servizio e non dipendono direttamente l’una dall’altra. Con questo approcio il subscriber ha bisogno di gestire manualmente la registrazione e la de-registrazione all’evento prima che sia gestito dal garbage collector.

Event Aggregtion:con questo approcio si usa un event aggregator generico che contiene un repository degli eventi per gli oggetti. Gli eventi degli oggetti usano dei delegati istanziati dal .Net Framework. Il vantaggio di questa tecnica e che i delegati possono essere creati  quando si pubblica un messaggio e poi rilasciati senza prevedere un carbage collected da parte dei subbscribers. Ogni oggetto evento contiene una collection di subscribers che riceveranno il messaggio. Nella libreria CAL è disponibile  la classe CompositePresentationEvent<T> che permette questo tipo di approcio.