2013-01-09 9 views
6

Ho letto diversi articoli, tutorial e post sul blog sul pattern MVVM. Tuttavia c'è una cosa che non capisco. Prendendo i tre "strati":Per che cosa è il modello in MVVM?

  • Modello
  • View
  • vista del modello

Per quanto ho capito MVVM il modello contiene i dati "grezzi", per esempio un nome e indirizzo nel caso di una classe Student. Il modello di visualizzazione espone le proprietà alla vista che rappresentano i dati del modello.

Esempio per una proprietà nel modello di visualizzazione

public string Name { 
get { return model.Name; } 
set { model.Name = value; } 
} 

esempio per il modello

private string name; 

public string Name { 
get { return name; } 
set { name = value; } 
} 

Questo potrebbe sembrare un po 'stupido, ma non questo creare una ridondanza? Perché devo mantenere il nome nel modello e nel modello di visualizzazione? Perché non si dovrebbe gestire completamente il nome sul modello di visualizzazione?

+1

Domanda molto buona, tra l'altro: chiara, concisa e contiene codice di esempio. – JDB

risposta

5

In un esempio così semplice, questa risposta sarebbe sì (è irragionevolmente ridondante). Ma, presumibilmente, una pagina conterrà più di un semplice oggetto Modello. Si può avere lo stato della pagina così come più altri oggetti del modello che devono essere tutti tracciati. Questo è fatto nel ViewModel.

Ad esempio, è possibile avere ulteriori informazioni sull'utente connesso visualizzato in una barra di stato, nonché un servizio in esecuzione per rilevare le modifiche a un file di testo.

È anche possibile disporre di un modulo per la modifica dell'oggetto Studente. Se si intende convalidare tali modifiche, non si desidera modificare direttamente l'oggetto Studente fino a dopo la verifica delle modifiche. In tal caso, ViewModel può fungere da posizione di archiviazione temporanea.

Nota su quanto sopra: Non è insolito che la convalida si verifichi nel modello, ma anche in questo caso è probabile che l'utente possa immettere valori non validi mentre è in corso la modifica di un modulo. Ad esempio, se il tuo modello non consente un valore di lunghezza zero in un campo, desideri comunque consentire all'utente di eliminare il valore, spostarlo in un altro campo (ad esempio, per copiarlo), quindi tornare al campo e terminare la modifica (incolla). Se sei legato direttamente al modello, la tua logica di convalida potrebbe non gestire questo stato "intermedio", "non ancora finito" come desideri. Ad esempio, potresti non voler accostare il tuo utente con errori di convalida fino a quando non hanno finito e fatto clic su "Salva".

Probabilmente avrete anche oggetti Command nel ViewModel per gestire i clic sui pulsanti e simili. Questi sarebbero oggetti specifici del dominio che sarebbero inutili in un modello.

ViewModels sono utili anche quando è necessario filtrare o modificare temporaneamente "oggetti modello" per ottenere qualcosa di utile sullo schermo. Ad esempio, potresti voler visualizzare un elenco di tutti gli utenti in un sistema insieme a un elenco in tempo reale dei primi dieci esecutori tra loro (aggiornato ogni 10 secondi). Oppure potresti voler mostrare un elenco di Report e un grafico che mostra la percentuale complessiva di utilizzo, ecc. Filtraggio, ordinamento e personalizzazione di tali dati all'interno di ViewModel.

Il modello, d'altra parte, è tipicamente il più puro possibile. Idealmente, si desidera solo POCOs che (di solito) modellino esattamente ciò che si trova nella memoria persistente (database o cosa si ha). Se la tua memoria persistente ha i campi FirstName e LastName, anche il tuo Modello. Solo nel tuo ViewModel le combinerai per ottenere un campo Nome (o "Primo Ultimo" o "Ultimo, Primo" a seconda delle necessità della Vista).

Ad esempio:

namespace Model 
{ 
    public class Student 
    { 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
    } 

    public class Class 
    { 
     public string Name { get; set; } 
     public float Score { get; set; } 
    } 
} 

namespace ViewModel 
{ 
    public class EditStudentRecordViewModel 
    { 
     private Model.Student _student; 
     private IEnumerable<Model.Class> _studentClasses; 

     /* Bind your View to these fields: */ 
     public string FullName 
     { 
      return _student.LastName + ", " + _student.FirstName; 
     } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 

     public IEnumerable<Model.Class> PassingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score >= 78); 
      } 
     } 

     public IEnumerable<Model.Class> FailingClasses 
     { 
      get 
      { 
       return _studentClasses.Where(c => c.Score < 78); 
      } 
     } 

     public void Save() 
     { 
      List<string> l_validationErrors = new List<string>(); 
      if (string.IsNullOrEmpty(this.FirstName)) 
       l_validationErrors.Add("First Name must not be empty."); 
      if (string.IsNullOrEmpty(this.LastName)) 
       l_validationErrors.Add("Last Name must not be empty."); 

      if (l_validationErrors.Any()) 
       return; 

      _student.FirstName = this.FirstName; 
      _student.LastName = this.LastName; 
      Model.Utilities.SaveStudent(_student); 
     } 
    } 
} 
5

Il modello è il grafico dell'oggetto che contiene la logica aziendale.

Ecco dove si tiene il comportamento (convalida, calcolo e così via).

ViewModel è qualcosa che modella l'interfaccia utente e le sue interazioni.

Questi sono diversi e hanno diversi motivi per esistere: il punto del modello è separare la logica del display dal VVM (View e ViewModel) e avere la logica aziendale completamente separata.

0

Modello in MVVM è esattamente lo stesso come in MVP o Model2 MVC. È l'unica parte dei pattern ispirati a MVC che non è influenzata dalle variazioni sul tema.

Modello è il livello che contiene archivi, unità di lavoro, oggetti dominio/modello, mappatori dati, servizi e altre strutture. Tutto ciò che hanno combinato crea il livello del modello, che contiene tutta la logica di business del dominio per la particolare applicazione.

Il modello non è una singola istanza. Chiunque ti domandi è pieno.

Gli specifici casi di utilizzo, per i quali MVVM è stato progettato, sono situazioni quando non è possibile modificare il livello del modello o visualizzare le istanze o entrambi.

P.S. Tuttavia, se si utilizzano le istanze ViewModel come da documentazione ASP.NET MVC, in realtà NON si utilizza MVVM. È solo Model2 MVC con nomi diversi per le cose (dove "viewmodels" sono effettivamente viste e "viste" sono modelli). Si sono incasinati quando hanno commercializzato l'architettura Rails come "MVC".

4

Il modello è vista in cui si desidera tenere traccia delle proprietà che sono specifici per la visualizzazione e non è necessario il modello.

Prendiamo il tuo modello, supponiamo che si chiami Person.

e quindi si crea un modello di visualizzazione per Person chiamato PersonViewModel, che assomiglia a questo:

public class PersonViewModel 
{ 
    public Person Person { get; set; } 
} 

(Nota, non si potrebbe desiderare di esporre il modello come questo direttamente, ma questa è un'altra storia)

Ora diciamo che nella vista è presente un pulsante che consente di salvare l'istanza Person.Per offrire un'esperienza utente migliore (UX), si desidera abilitare il pulsante solo se il modello è effettivamente cambiato. Così si implementa il INotifyPropertyChanged interface sulla classe Person:

public class Person : INotifyPropertyChanged 
{ 
    ... 

Ora, si potrebbe esporre una proprietà HasUnsavedChanges dal Person cui la proprietà Enabled sul pulsante di salvataggio sarebbe legarsi a, ma che la logica ha nulla a fare con la persona

Questo è dove il modello di vista è disponibile in Si potrebbe definire questo proprietà specifici vista sul modello di vista, in questo modo:.

public class PersonViewModel 
{ 
    public Person Person { get; set; } 

    public bool HasUnsavedChanges { get; set; } 
} 

Poi, il modello di vista sarebbe iscriversi alla PropertyChanged event della Interfaccia INotifyPropertyChanged e attivare la proprietà HasUnsavedChanges nel modello di visualizzazione.

Quindi, se l'associazione è impostata correttamente, il pulsante di salvataggio si abilita/disabilita quando si verificano cambiamenti sul modello, ma il modello non ha alcuna logica che lo leghi alla vista.

Nota che è necessario implementare anche INotifyPropertyChanged sul modello di visualizzazione per consentire alla vista di essere rilevata quando vengono apportate modifiche al modello di vista a cui è associato.

Anche in questo caso, il punto funge da ponte per contenere la logica che è una combinazione di proprietà del modello e proprietà di visualizzazione che non appartengono al modello.

1

Ho sempre visto i modelli come i "blocchi" dell'applicazione. Di solito sono classi autonome con alcune proprietà e forse qualche validazione o logica rudimentale solo per le sue proprietà.

Visualizza I modelli d'altra parte sono le mie effettive classi di applicazione che finiscono per utilizzare i "blocchi predefiniti" (Modelli) durante la creazione e l'esecuzione dell'applicazione. Fanno cose come eseguire la convalida avanzata, i comandi di processo, gestire gli eventi, qualsiasi tipo di logica di business, ecc

Va notato che non hanno per esporre le proprietà del modello in vostro ViewModel come avete in il tuo codice di esempio. Questo è l'approccio "purista MVVM" poiché separa completamente il livello del modello dal livello Visualizza, tuttavia è anche perfettamente accettabile esporre l'intero modello alla vista. Questo è quello che di solito uso nella maggior parte dei piccoli progetti a causa della sua semplicità e della mancanza di duplicazione del codice.

public MyModel CurrentModel 
{ 
    get { return _model; } 
    set 
    { 
     if (_model != value) 
     { 
      _model = value; 
      RaisePropertyChanged("CurrentModel"); 
     } 
    } 
} 

Tuttavia, se ci sono casi in cui è necessario solo pochi oggetti di modello nella vista, o se il progetto è abbastanza grande dove andrò voglio mantenere gli strati totalmente separati, allora espongo il mio modello di proprietà alla vista attraverso il ViewModel come nel codice di esempio.

Problemi correlati