2011-02-04 17 views
5

Sto lavorando a un'applicazione Silverlight di grandi dimensioni che utilizza il Net.TCP duplex per comunicare con un back-end WCF. Sono in procinto di spostare questa app da un approccio MVC a MVVM. Tuttavia, sto lottando con il modo giusto per implementare i miei ViewModels. Stiamo usando i proxy generati da WCF per il nostro modello, che è piuttosto complesso, coinvolge decine di classi, un sacco di collezioni e una varietà di relazioni molti-a-molti. Ad esempio, un utente può appartenere a molte stanze, una stanza può avere molti utenti, un utente può avere molti file condivisi e ogni file condiviso può essere condiviso con qualsiasi stanza di cui l'utente fa attualmente parte. Questo genere di cose.Best practice per la sincronizzazione di Modelli e ViewModels

Inoltre, poiché stiamo utilizzando WCF in modalità duplex, le modifiche al modello possono essere attivate dall'utente finale o dal servizio WCF sul back-end. In altre parole, il modello che stiamo utilizzando è di diversi ordini di grandezza più complicato del tipico "Modello" che vedi rappresentato in uno dei vari libri/articoli/post di blog di MVVM. Ed è qui che il problema arriva, perché mantenere il nostro layer ViewModel in sincronia con il sottostante strato del modello sta diventando un po 'complicato.

Ecco un problema tipico. Un nuovo "Utente" si unisce a una "Stanza", quindi i servizi WCF lanciano una notifica "SessionAdded" a tutti gli altri utenti nella stanza. La notifica SessionAdded porta con sé un oggetto Session che ha una Stanza collegata e un oggetto Utente collegato. L'oggetto Room che viene deserializzato dal servizio WCF è fondamentalmente uguale all'oggetto Room sul client locale e probabilmente ha la maggior parte degli stessi dati, ma non ha lo stesso tutti gli gli stessi dati, e almeno alcuni dei dati (come la raccolta null di lavagne bianche) è certamente sbagliato. Quindi dobbiamo in qualche modo prendere questi dati in arrivo e unirli al nostro modello esistente. E poi abbiamo bisogno di creare ViewModels su ciascuno dei nuovi oggetti, e/o aggiornare ViewModels esistenti con i nuovi oggetti e/oi loro dati.

In questo momento stiamo gestendo questo facendo sì che i vari ViewModels rispondano agli eventi di notifica WCF rilevanti e facciano del loro meglio per sistemare i loro modelli sottostanti e i relativi modelli di visualizzazione. Abbiamo individuato alcuni trucchi, come un SynchronizedObservableCollection (vagamente come quello here) che controlla (diciamo) RoomSessions ObservableCollection e crea automaticamente SessionViewModels corrispondenti e li colloca nella collezione RoomViewModel.SessionViewModels. Stiamo anche utilizzando ViewModelFactory, che memorizza nella cache i modelli di visualizzazione e assicura che, ad esempio, SessionViewModel che avvolge una determinata Session rimanga invariato, anche se l'oggetto Session sottostante viene modificato. (Se è importante, stiamo usando un approccio viewmodel-first, dal momento che una grande fetta di ciò di cui abbiamo bisogno è che nuovi elementi dell'interfaccia utente vengano creati in risposta alle modifiche nel ViewModel attivato dalle nostre notifiche WCF.)

E tutto ciò funziona Fondamentalmente. La maggior parte delle volte. Sai. Ma è un sacco di codice da mantenere ed è facile sbagliare. I test unitari sono a portata di mano fino a quando riesci a ricordare cosa dovrebbe succedere, ma quando avrai finito di elaborare il tuo 20 ° evento CollectionChanged a cascata, è difficile tenere traccia di come tutto ciò si è combinato e cosa stavi testando in primo luogo . In altre parole, è tutto piuttosto dannatamente fragile.

Mi sembra che questo sia il tipo di scenario in cui devono essere incontrate molte persone, e sono curioso di sapere come altri hanno affrontato il problema. Posso pensare ad un paio di approcci per renderlo migliore:

(1) Trattare il modello lato client come una sorta di database che deve essere mantenuto completamente coerente e implementare un livello di accesso ai dati lato client il cui lavoro è mantenere il modello coerente. Tutti gli aggiornamenti al modello, sia dell'utente che del server, dovrebbero passare attraverso questo livello. Sarebbe un po 'come l'Entity Framework, in quanto myRoom.Users.Add(myUser) imposterebbe automaticamente myUser.Room = myRoom e viceversa, e così via. (Questo è specialmente la parte in cui sembra che qualcuno da qualche parte dovrebbe aver già sviluppato, anche se non l'ho ancora trovato.)

(2) Appoggiare su qualcosa come Truss o Obtics, per mantenere tutti i pezzi sincronizzati. Non so bene come funzionerebbe ancora, ma suona in teoria come dovrebbe essere possibile.

E ... che altro? Sono curioso riguardo ai pattern o ai framework che sono stati usati per risolvere questo problema.

risposta

3

Capisco il tuo dolore - Attualmente sto sviluppando un'applicazione di visualizzazione dei dati complessa utilizzando il modello MVVM. Una domanda davvero importante da porsi è: "Il Modello di visualizzazione aggiunge valore ovunque che lo si diffonda?", In altre parole, ci sono dei punti in cui è semplicemente in grado di inoltrare le proprietà del livello del modello alla vista?

Spesso trovo che aree del codice, tipicamente a livello di dettaglio (ad esempio le proprietà di un oggetto Person, Età, Nome, Nome), dove il modello di vista non stia effettivamente aggiungendo alcun valore, mentre al più livello di corso, aggiunge valore strutturando viste/finestre ecc ...

Tendo ad adottare un approccio adattivo a MVVM, al livello superiore (Windows, riquadri, moduli) Ho sempre un modello di vista, ma se parti del modello di vista sono così semplici che un modello di vista non aggiunge valore, le espongo direttamente alla vista. Inoltre, in alcuni casi è necessario esporre il modello direttamente alla vista per ottenere prestazioni migliori.

Infine, se si scopre che è necessario reintrodurre un modello al fine di risolvere un problema di legame difficile, ho scritto su un modello semplice, mini-MVVM, che applica una vista del modello locale:

http://www.scottlogic.co.uk/blog/colin/2009/08/the-mini-viewmodel-pattern/

Spero che questo aiuti.

+0

Questo è fondamentalmente quello che sto facendo: non sono un purista :-). Ciascuno dei miei ViewModels ha una proprietà Model che espone il modello sottostante. Dato che il modello in questa istanza è sempre una classe generata da WCF, implementa INotifyPropertyChanged e quindi funziona in modo soddisfacente come fonte di associazione. Le uniche proprietà che aggiungo al mio ViewModel sono quelle che in realtà aggiungono valore in qualche modo. Ma devo ancora affrontare il problema del modello che deve essere aggiornato quando il server invia un messaggio al client con un modello aggiornato. –

Problemi correlati