ASP.Net  »  Articoli  »  Silverlight 

MVVM in progetti Silverlight: strutturare applicazioni reali

di: Andrea Boschin     07 Luglio 2010

Nei precedenti articoli abbiamo introdotto le basi del pattern Model View ViewModel, spiegando il ruolo e le responsabilità che sono assegnate a ciascuna classe. Abbiamo visto come collaborano la View e il ViewModel e come le informazioni possono transitare dall'uno all'altro sotto forma di dati bindati all'interfaccia in un senso e sotto forma di comandi nell'altro.

Rimane tuttavia da capire come deve essere strutturata una applicazione reale, perchè un conto è realizzare un piccolo esempio contenente una sola View e un solo ViewModel, ma un'altra cosa è realizzare una vera applicazione che possa beneficiare del pattern, ma che mantenga il massimo dell'efficacia e consenta di implementare qualunque funzionalità.

Quando serve un ViewModel?

Nel momento in cui si affronta per la prima volta una applicazione MVVM, il primo dubbio che sorge è proprio quanti ViewModel debbano essere realizzati, insomma quanto profondamente il pattern debba permeare l'applicazione. Per rispondere a questa, non semplice, domanda proviamo ad immaginare, a titolo di esercizio, l'interfaccia di un ipotetico client di feed RSS. Qui di seguito riportiamo il wireframe schematico dell'interfaccia:

Figura 1. Wireframe del lettore RSS

Wireframe del lettore RSS

Il pannello A conterrà i feed registrati, e le relative cartelle che servono a catalogarli, visualizzate per mezzo di un controllo treeview.

La selezione di un nodo nell'albero provocherà la visualizzazione dell'elenco dei messaggi nel pannello B, che è appunto deputato a visualizzare un elenco, sotto forma di DataGrid, riportando il titolo, la data, e altre informazioni.

Infine il pannello C sarà il pannello di lettura che mostra il contenuto del post alla selezione della corrispondente riga nel pannello B.

Ciascun pannello potrà contenere dei comandi, peculiari delle funzioni che esso svolge: i pulsanti per aggiungere e eliminare i feed, un tasto per marcare i post con delle bandierine che ne indicano l'importanza e così via. Quello che conta per ora è decidere quante View e relativi ViewModel implementare.

Chiunque, davanti a questo layout, si renderà conto immediatamente che ciascun pannello è un buon candidato per essere una View. In effetti le responsabilità sono ben delimitate e viene naturale pensare che ogni elemento possa essere completamente indipendente.

Il pannello B ad esempio si occuperà autonomamente di leggere i messaggi presenti nel feed e di visualizzarli su una griglia. Possiamo immaginare il ViewModel di questo pannello come segue:

public class PostListViewModel
{
  public ObservableCollection<Post> Posts { get; set; }
  
  public PostListViewModel()
  {
    this.Posts = new ObservableCollection<Post>();
	
	foreach (Post post in DataSource.GetPostByFeed())
	  this.Posts.Add(post);
  }
}

Il ViewModel in questione dispone di una ObservableCollection<Post>; che verrà collegata alla proprietà ItemsSource della DataGrid. Così facendo il ViewModel recupera i post dallo storage e riempie la collection. Essa verrà quindi visualizzata dalla DataGrid.

Il primo problema però sorge quando dobbiamo gestire l'eventuale comando di cancellazione. Un pulsante ripetuto ad ogni riga della DataGrid infatti non potrà giocoforza essere bindato al ViewModel perchè l'oggetto che è ripetuto nella grid è una istanza di Post e non il ViewModel.

Questo è un problema abbastanza comune, e la soluzione può sembrare in qualche modo sconvolgente, ma a pensarci bene l'unica possibilità per evitare di scrivere codice nel codebehind della View è di considerare ogni singola riga della grid essa stessa una View e di conseguenza bindare ad essa un ViewModel specifico, e non l'istanza di Post.

Tale ViewModel dovrà contenere il post stesso, ma potrà presentare una serie di altre proprietà, ad esempio il comando di cancellazione.

Per esperienza vi dirò che la maggioranza delle volte in cui ci troviamo di fronte ad una lista di qualche genere dobbiamo preparare un ViewModel che incapsuli l'elemento della lista e ci consenta di esporre altre proprietà senza dover "sporcare" in qualche modo l'entità che viene dal Model.

La regola generale è: se deve contenere della logica, allora deve avere un ViewModel.

Esistono casi in cui esso non è utile, ad esempio nelle ComboBox e ListBox senza template, ma un po' alla volta si impara ad accettare questo modo di lavorare ed esso diventa naturale. Ecco come risulterà il ViewModel di B:

public class PostListViewModel
{
  public ObservableCollection<PostRowViewModel> Posts { get; set; }

  public PostListViewModel()
  {
    this.Posts = new ObservableCollection<PostRowViewModel>();
	
	foreach (Post post in DataSource.GetPostByFeed())
	  this.Posts.Add(new PostRowViewModel(post));
	}
}

public class PostRowViewModel
{
  public Post Post { get; set; }
  
  public PostRowViewModel(Post post)
  {
    this.Post = post;
  }
  
  public DelegateCommand<Post> DeleteCommand { get; set; }
}

Guide ASP.Net

Guida Windows Azure Code Snippets

Le migliori pratiche per far girare le applicazioni "in the cloud",...

Guida ASP.NET MVC Best Practices

Un workflow dettagliato e ricco di suggerimenti pratici per...

Guida ASP.NET Starter Kit

Un modo semplice per imparare ad utilizzare le tecnologie Microsoft...

Altre guide

Newsletter @Microsoft Dev

Ogni giovedì, direttamente nella tua e-mail: articoli, guide, tutorial e script ASP, ASP.Net, SQL server e IIS.

Iscriviti alla newsletter

Altre newsletter

Corsi in aula

Corso Progettazione database

11 Maggio 2012 a Milano
Disponibilità: 6 Posti

Amministratore di Reti Windows Server 2008

11 Giugno 2012 a Milano
Disponibilità: 5 Posti

Nessun corso previsto