2010-05-09 9 views
85

L'implementazione MVVM ortodossa è inutile? Sto creando una nuova applicazione e ho preso in considerazione Windows Form e WPF. Ho scelto WPF perché è a prova di futuro e offre molta flessibilità. C'è meno codice e più facile apportare modifiche significative all'interfaccia utente utilizzando XAML.MVVM è inutile?

Dato che la scelta per WPF è ovvia, ho pensato che potrei anche andare fino in fondo usando MVVM come architettura della mia applicazione poiché offre sfumabilità, problemi di separazione e testabilità dell'unità. In teoria, sembra bello come il Santo Graal della programmazione dell'interfaccia utente. Questa breve avventura; tuttavia, si è trasformato in un vero mal di testa. Come previsto nella pratica, sto scoprendo che ho scambiato un problema con un altro. Tendo ad essere un programmatore ossessivo in quanto voglio fare le cose nel modo giusto così da ottenere i risultati giusti e possibilmente diventare un programmatore migliore. Il pattern MVVM ha appena fallito il test sulla produttività e si è appena trasformato in un grande hacker!

Il caso chiaro al punto è l'aggiunta del supporto per una finestra di dialogo Modale. Il modo corretto è di creare una finestra di dialogo e legarla a un modello di vista. Ottenere questo a lavorare è difficile. Per beneficiare del pattern MVVM, è necessario distribuire il codice in più punti all'interno dei livelli dell'applicazione. Devi anche usare costrutti di programmazione esoterici come i modelli e le espressioni di lamba. Cose che ti fanno fissare lo schermo grattandoti la testa. Ciò rende la manutenzione e il debug di un incubo in attesa di accadere come ho scoperto di recente. Avevo a circa un box funzionante fino a quando non ho ottenuto un'eccezione la seconda volta che l'ho invocato, dicendo che non poteva mostrare di nuovo la finestra di dialogo una volta chiusa. Ho dovuto aggiungere un gestore di eventi per la funzionalità close alla finestra di dialogo, un altro nell'implementazione di IDialogView e infine un altro in IDialogViewModel. Pensavo che MVVM ci avrebbe salvati da uno stravagante spettacolo!

Ci sono molte persone là fuori con soluzioni in competizione per questo problema e sono tutti hack e non forniscono una soluzione elegante, facilmente riutilizzabile ed elegante. La maggior parte degli strumenti MVVM nasconde le finestre di dialogo e quando le affrontano, sono solo caselle di avviso che non richiedono interfacce personalizzate o modelli di visualizzazione.

Sto pensando di rinunciare al modello di visualizzazione MVVM, almeno la sua implementazione ortodossa. Cosa ne pensi? È valsa la pena per te se ne avessi? Sono solo un programmatore incompetente o MVVM non è ciò che è pubblicizzato?

+6

Ho sempre messo in dubbio se MVVM è o meno di ingegneria. Domanda interessante –

+10

Pattern come MVVM e MVC sembrano overengineering, fino a quando non è necessario eseguire alcune modifiche o modificare un componente. La prima volta che devi farlo, tutta la cerimonia * si ripaga da sola. * –

+0

Se sai perché lo stai facendo, MVC e MVVM sono abbastanza semplici e diretti. Se hai fatto qualcosa di difficile da capire e/o chiaramente violato il SoC o altri principi, è chiaramente l'ipogeo. Riepilogo: se lo rendi semplice, non sarà eccessivamente ingegnerizzato e non sarà complicato neanche. – Venemo

risposta

57

Scusa se la mia risposta è diventata un po 'prolungata, ma non incolparmi! Anche la tua domanda è lunga.

In sintesi, MVVM non è inutile.

Il chiaro esempio è l'aggiunta supporto per una finestra di dialogo modale. Il modo corretto di consiste nel creare una finestra di dialogo e legarla a un modello di vista. Ottenere questo a lavorare è difficile.

Sì, lo è davvero.
Tuttavia, MVVM fornisce un modo per separare l'aspetto dell'interfaccia utente dalle sue logiche. Nessuno ti obbliga a usarlo ovunque, e nessuno sta tenendo una pistola contro la fronte per farti creare un ViewModel separato per tutto.

Ecco la mia soluzione per questo particolare esempio:
Come l'interfaccia utente gestisce un determinato input non è parte dell'attività di ViewModel. Aggiungerei il codice al file .xaml.cs della View, che crea un'istanza della finestra di dialogo e imposta la stessa istanza ViewModel (o qualcos'altro, se necessario) come DataContext.

Per beneficiare del pattern MVVM, è necessario distribuire il codice in più punti all'interno dei livelli dell'applicazione. Devi anche usare costrutti di programmazione esoterici come i modelli e le espressioni di lamba.

Bene, non è necessario utilizzarlo in più punti. Questo è come vorrei risolverlo:

  • Aggiungere il XAML alla vista, e nulla nelle .xaml.cs
  • scrivere ogni logica app (tranne la roba che dovrebbe operare direttamente con elementi dell'interfaccia utente) all'interno di un ViewModel
  • Tutto il codice che deve essere fatto da l'interfaccia utente, ma non ha nulla a che fare con la logica di business va in file .xaml.cs

Penso che lo scopo di MVVM è principalmente quello di separare la logica di l'applicazione e l'interfaccia utente concreta, consentendo quindi modifiche semplici (o completa sostituzione) nt) dell'interfaccia utente.
Io uso il seguente principio: la Vista può conoscere e assumere tutto ciò che vuole dal ViewModel, ma il ViewModel può non conoscere NIENTE della Vista.
WPF fornisce un modello di associazione piacevole che è possibile utilizzare per ottenere esattamente quello.

(a proposito, i modelli e le espressioni lambda non sono esoterici se usato bene. Ma se non si vuole, non li uso.)

Roba che ti fa fissare lo schermo graffiare la tua testa.

Sì, conosco la sensazione. Esattamente quello che stavo provando quando vidi per la prima volta MVVM. Ma una volta capito, non sarà più male.

ho avuto una scatola di circa lavorando bene ...

Perché si mettere un ViewModel dietro un su scatola? Nessun punto in questo.

La maggior parte degli strumenti MVVM lucida sulle finestre di dialogo e quando vengono indirizzate, sono solo caselle di avviso che non richiedono interfacce personalizzate o modelli di visualizzazione.

Sì, perché il fatto stesso che un elemento dell'interfaccia utente si trovi nella stessa finestra o in un'altra finestra o che stia orbitando su Marte al momento non è il problema di ViewModels.
Separation of Concerns

EDIT:

Ecco un video molto bello il cui titolo è Build your own MVVM framework. Vale la pena guardare.

+2

+1 per le ultime tre parole. Ma anche il resto della risposta è buono. :) –

+0

Grazie per quello. :) – Venemo

+12

+1 per il consiglio sull'utilizzo di code-behind. È un errore comune pensare che sia "cattivo" utilizzare il code-behind in MVVM ... ma per cose puramente relative all'interfaccia utente, questa è la strada da percorrere. –

0

Ho riscontrato lo stesso problema con molte implementazioni MVVM quando si tratta di finestre di dialogo (modali). Quando guardo i partecipanti al pattern MVVM, ho la sensazione che manchi qualcosa per costruire un'applicazione coerente.

  • Guarda contiene i controlli specifici GUI e definisce l'aspetto dell'interfaccia utente.
  • ViewModel rappresenta lo stato e il comportamento della presentazione.
  • Il modello può essere un oggetto aziendale dal livello dominio o un servizio che fornisce i dati necessari.

Ma manca è:

  • Chi crea le ViewModels?
  • Chi è responsabile del flusso di lavoro dell'applicazione?
  • Chi media tra ViewModels quando devono comunicare tra loro?

Il mio approccio è quello di introdurre un (Use-Case) controller che è responsabile per i punti mancanti. Come funziona può essere visto nelle applicazioni di esempio WPF Application Framework (WAF).

+0

Il modello Mediator implementato da Josh Smith ha risolto tutti i problemi di comunicazione del mio modello View. Messenger.NotifyColleagues ha fornito un modo per avere modelli di visualizzazione completamente indipendenti che sapevano come rispondere agli eventi globali (se gliene importava) senza che due modelli di visualizzazione fossero a conoscenza l'uno dell'altro. Adesso ha salvato il nostro bacon già alcune volte. – JasonD

8

Ottenere questo a lavorare è difficile. In per beneficiare del pattern MVVM , è necessario distribuire il codice in diversi punti dei livelli dell'applicazione. È inoltre necessario utilizzare di programmazione esoterica costrutti come modelli e espressioni di lamba .

Per una finestra di dialogo modale comune? Sicuramente stai facendo qualcosa di sbagliato - l'implementazione MVVM non deve essere così complessa.

Considerando che sei nuovo sia per MVVM che per WPF, è probabile che tu stia utilizzando soluzioni sub-ottimali ovunque e complichi inutilmente le cose, almeno così l'ho fatto quando ho iniziato a utilizzare WPF. Assicurati che il problema sia realmente MVVM e non la tua implementazione prima di rinunciare.

MVVM, MVC, Document-View, ecc. È una vecchia famiglia di modelli. Ci sono degli svantaggi, ma non ci sono difetti fatali del tipo che descrivi.

5

Mi occupo del problema dei dialoghi imbrogliando. My MainWindow implementa un'interfaccia IWindowServices che espone tutte le finestre di dialogo specifiche dell'applicazione. Il mio altro ViewModels può quindi importare l'interfaccia dei servizi (io uso MEF, ma potresti facilmente passare l'interfaccia manualmente tramite costruttori) e usarla per realizzare ciò che è necessario. Per esempio, qui è ciò che l'interfaccia si presenta come una piccola applicazione utility di mine:

//Wrapper interface for dialog functionality to allow for mocking during tests 
public interface IWindowServices 
{ 
    bool ExecuteNewProject(NewProjectViewModel model); 

    bool ExecuteImportSymbols(ImportSymbolsViewModel model); 

    bool ExecuteOpenDialog(OpenFileDialog dialog); 

    bool ExecuteSaveDialog(SaveFileDialog dialog); 

    bool ExecuteWarningConfirmation(string text, string caption); 

    void ExitApplication(); 
} 

Questo mette tutte le esecuzioni di dialogo in un unico luogo e può essere facilmente spense per unit testing. Seguo il modello che il client della finestra di dialogo deve creare il ViewModel appropriato, che possono quindi configurare secondo necessità. I blocchi di chiamata Execute e in seguito il client può guardare i contenuti di ViewModel per vedere i risultati della finestra di dialogo.

Un design MVVM più "puro" può essere importante per una grande applicazione, dove è necessario un isolamento più pulito e una composizione più complessa, ma per le app di piccole e medie dimensioni, penso un approccio pratico, con servizi appropriati per esporre i ganci richiesti , è abbastanza sufficiente.

+0

Ma dove lo chiamate? Non sarebbe meglio semplicemente costruire la finestra di dialogo all'interno delle funzioni della classe IWindowServices piuttosto che passarla. In questo modo la vista del modello chiamante non dovrebbe sapere nulla sulla particolare implementazione della finestra di dialogo. –

+0

L'interfaccia viene iniettata in qualsiasi delle istanze ViewModel deve accedere alle finestre di dialogo dell'applicazione. Nella maggior parte dei casi, sto passando in ViewModel per la finestra di dialogo, ma sono diventato un po 'pigro e uso OpenFileDialog di WPF e SaveFileDialog per le chiamate di dialogo dei file. Il mio obiettivo principale era l'isolamento ai fini del test unitario, quindi questo è sufficiente per questo obiettivo. Se si desidera un migliore isolamento, è consigliabile creare OpenFileViewModel e SaveFileViewModel, che duplicano le proprietà necessarie per le finestre di dialogo. –

+0

Si noti che questo non è assolutamente un approccio puro, in quanto il ViewModel che utilizza le finestre di dialogo conosce lo specifico ViewModel per ogni finestra di dialogo che desidera aprire. Ritengo che questo sia abbastanza pulito, ma è sempre possibile aggiungere un ulteriore livello di isolamento con una classe che esponga semplicemente i parametri richiesti per l'utilizzo della finestra di dialogo, nascondendo qualsiasi visibilità non necessaria delle proprietà ViewModel utilizzate durante l'associazione. Per le applicazioni più piccole, sento che questo isolamento aggiuntivo è eccessivo. –

0

No, non è inutile, ma è difficile avvolgere la testa anche se il modello è ridicolmente semplice. Ci sono tonnellate di disinformazione là fuori e vari gruppi che combattono nel modo giusto. Penso che con WPF e Silverlight si debba usare MVVM o si finisca la codifica e si cerchi di risolvere i problemi in un nuovo modello, la "vecchia" metodologia delle forme di vincita che ti porta nei guai. Questo è più il caso in Silverlight poiché tutto è richiesto per essere asincroni (gli hacks attorno a questo sono possibili, ma dovresti semplicemente scegliere un'altra piattaforma).

Suggerirei di leggere questo articolo Simplifying the WPF TreeView by Using the ViewModel Pattern attentamente per vedere come MVVM può essere implementato bene e consentire di cambiare la mentalità delle forme di vincita al nuovo modo di pensare in MVVM. In breve, quando vuoi ottenere qualcosa, applica la logica al ViewModel prima non alla vista. Vuoi selezionare un articolo? Cambia un'icona? Non scorrere gli elementi dell'interfaccia utente, basta aggiornare le proprietà dei modelli e lasciare che il data-binding faccia il nocciolo.

1

Come il pattern stesso MVVM è ottimo. Ma la libreria di controllo di WPF fornita con il supporto per l'associazione dati di NET 4.0 è molto limitata, è molto meglio di WinForm, ma ancora non è sufficiente per MVVM bindable, direi che la potenza è circa il 30% di ciò che è necessario per MVVM bindable.
MVVM collegabile: si tratta di un'interfaccia utente in cui ViewModel è cablato con View only using data binding.
Il pattern MVVM riguarda la rappresentazione dell'oggetto del ViewState, non descrive come si mantiene la sincronizzazione tra View e ViewModel, in WPF il binding dei dati ma può essere qualsiasi cosa. E in realtà puoi usare il pattern MVVM in qualsiasi toolkit dell'interfaccia utente che supporti gli eventi \ callbacks, puoi usarlo in puro WinAPI in WinForms (l'ho fatto, e non c'è molto più lavoro con eventi \ callbacks), e puoi anche usarlo in Text Console, come riscrivere il Norton Commander di DoS usando il pattern MVVM.

In breve: MVVM non è inutile, è fantastico. La libreria di controllo di NET 4.0 WPF è spazzatura.

Ecco la semplice dimostrazione del concetto di ViewModel che non è possibile associare ai dati in puro modo MVVM utilizzando WPF.

public class PersonsViewModel 
{ 
    public IList<Person> PersonList; 
    public IList<ColumnDescription> TableColumns; 
    public IList<Person> SelectedPersons; 
    public Person ActivePerson; 
    public ColumnDescription SortedColumn; 
} 

righe È possibile non i dati legano intestazioni di colonna DataGrid di WPF, non è possibile i dati legano selezionati, etc etc, si sia farlo in modo semplice codice, o scrivere 200 righe di codice XAML mod per queste 5 linee di ViewModel più semplici. Puoi solo immaginare come le cose peggiorano con i complessi ViewModels.
Quindi la risposta è semplice a meno che non si stia scrivendo un'applicazione Hello World, l'utilizzo di MVVM associabile in WPF è inutile. Trascorrerai la maggior parte del tuo tempo pensando a un trucco per legare ViewModel. Il bind dei dati è bello, ma sii pronto a ricorrere al 70% del tempo dell'evento.

+0

È possibile associare questo, con i convertitori, a un DataGrid. –

+0

@CameronMacFarland: non tutte, alcune proprietà sono pronte e non leggibili, alcune semplicemente non esistono e ci sono solo eventi che cambiano lo stato dei report. –

+0

Devo ammettere che non ho molta esperienza con il DataGrid di WPF. Tendo ad evitarlo perché è brutto e non si adatta più con WPF. Detto questo, una combinazione di convertitori e AttachedProperties per gestire gli eventi dovrebbe farti ottenere ciò di cui hai bisogno. –

4

Sono al centro di uno sviluppo MVVM piuttosto complesso utilizzando PRISM, quindi ho già dovuto affrontare questo tipo di preoccupazioni.

Le mie conclusioni personali:

MVVM vs MVC/PopUps & co

  • MVVM è davvero un grande disegno e nella maggioranza dei casi sostituisce completamente MVC grazie ai dati potenti binding in WPF
  • Chiamare il livello di servizio direttamente dal presentatore è un'implementazione legittima nella maggior parte dei casi
  • Anche gli scenari List/Detail abbastanza complessi possono essere implementati da MVVM puro grazie al {Percorso vincolante = /} sintassi
  • Tuttavia, quando è necessario implementare una complessa coordinazione tra più viste, è possibile utilizzare un controller obbligatorio negli eventi
  • ; il vecchio schema che implica IView memorizzare (o AbstractObserver) istanze nel controllore è obsoleto
  • Il controllore può essere iniettato in ciascun presentatore dal contenitore CIO
  • servizio IEventAggregator Prism è un'altra soluzione possibile se il solo uso del controllore è evento invio (in questo caso può sostituire completamente il controller)
  • Se viste devono essere creati dinamicamente, questo è un lavoro molto adatto per il controller (nel prisma controllore otterrà iniettato (IOC) un IRegionManager)
  • Le finestre di dialogo modali sono per lo più obsolete nelle moderne applicazioni composite, ad eccezione delle operazioni di blocco reali come le conferme obbligatorie; in questi casi l'attivazione modale può essere sottratta come un servizio chiamato all'interno del controller e implementato da una classe specializzata, che consente anche il collaudo avanzato delle unità a livello di presentazione. Il controller, ad esempio, chiamare IConfirmationService.RequestConfirmation (“Sei sicuro”), che attiverà un display finestra di dialogo modale in fase di esecuzione e può essere facilmente preso in giro durante i test delle unità
5

I design pattern sono lì per aiutare voi, non ostacolare. Una piccola parte di essere un buon sviluppatore è sapere quando "infrangere le regole". Se MVVM è ingombrante per un'attività e hai determinato che il valore futuro non vale la pena, non utilizzare il modello. Ad esempio, come altri commentatori hanno commentato, perché dovresti passare attraverso tutto il sovraccarico per implementare una semplice scatola?

Gli schemi di progettazione non sono mai stati concepiti per essere seguiti dogmaticamente.

+2

. Un semplice riquadro dovrebbe essere semplice, ma cosa succederebbe se fosse necessario visualizzare informazioni quali la versione, le licenze, il processo in esecuzione, il nome della società, ecc. Queste sono tutte informazioni che vivono da qualche parte. Nei moduli standard, puoi semplicemente legare tutte queste informazioni e farle. MVVM dice che dovresti creare un modello di visualizzazione per esso, che è ridondante. –