2010-04-05 15 views
17

Sto sperimentando il modello MVVM spesso menzionato e in alcuni casi ho avuto difficoltà a definire limiti chiari. Nella mia applicazione, ho una finestra di dialogo che mi consente di creare una connessione a un controller. Esiste una classe ViewModel per la finestra di dialogo, che è abbastanza semplice. Tuttavia, la finestra di dialogo ospita anche un controllo aggiuntivo (scelto da un ContentTemplateSelector), che varia a seconda del particolare tipo di controller che viene connesso. Questo controllo ha il proprio ViewModel.MVVM: come gestire l'interazione tra ViewModels nidificati?

Il problema che sto riscontrando è che, quando chiudo la finestra di dialogo premendo OK, devo effettivamente creare la connessione richiesta, che richiede informazioni acquisite nella classe ViewModel specifica per Controller interna. Si sta tentando semplicemente di avere tutte le classi ViewModel specifiche del controller che implementano un'interfaccia comune che costruisce la connessione, ma il ViewModel interno dovrebbe davvero essere responsabile di questa costruzione?

La mia domanda generale è: ci sono schemi di progettazione generalmente accettati su come ViewModels dovrebbe interagire tra loro, in particolare quando una macchina virtuale "madre" ha bisogno di aiuto da una VM "bambina" per sapere cosa fare?


EDIT:

sono venuto su con un disegno che è un po 'più pulita di quanto mi è stato originariamente pensato, ma non sono ancora sicuro se è il modo 'giusto' per fare questo. Ho alcuni servizi di back-end che permettono a ContentTemplateSelector di guardare un'istanza di Controller e pseudo-magicamente trovare un controllo da visualizzare per il generatore di connessioni. Quello che mi ha infastidito è che il mio ViewModel di primo livello avrebbe dovuto guardare il DataContext per il controllo generato e inviarlo a un'interfaccia appropriata, il che sembra una cattiva idea (perché il View DataContext ha qualcosa a che fare con la creazione ? il collegamento)

finii con qualcosa di simile (semplificando):

public interface IController 
{ 
    IControllerConnectionBuilder CreateConnectionBuilder(); 
} 

public interface IControllerConnectionBuilder 
{ 
    ControllerConnection BuildConnection(); 
} 

io ho la mia classe ViewModel interna implementare IControllerConnectionBuilder e il controllore restituisce il ViewModel interiore. Il ViewModel di livello superiore visualizza quindi questo IControllerConnectionBuilder (tramite il meccanismo pseudo-magico). Mi infastidisce ancora un po 'il fatto che sia il mio ViewModel interno a eseguire l'edificio, ma almeno ora il mio ViewModel di livello superiore non deve conoscere i dettagli sporchi (non sa nemmeno che il controllo visualizzato sta usando un ViewModel).

Sono lieto di ulteriori pensieri se ci sono modi per ripulirlo ulteriormente. Non mi è ancora chiaro quanta responsabilità è "okay" per il ViewModel.

+2

Ci poniamo costantemente questo tipo di domande sul mio lavoro. Hai formulato questa domanda molto bene, quindi spero che tu abbia qualche buon feedback qui. –

+2

Per fortuna questo è un progetto per animali domestici, quindi ho il lusso di esplorare diversi progetti. Il mio negozio non ha adottato WPF o MVVM perché il sovraccarico e l'imbarazzo in questa fase iniziale non sono accettabili per i nostri programmi attuali. Credo fermamente che questa sia una tecnologia che pagherà grandi dividendi in termini di produttività una volta capito come usarla, ma è un tale cambiamento di prospettiva che è difficile sapere dove disegnare le linee in un disegno. –

risposta

3

Un'opzione che funziona bene per l'interazione tra viewmodels consiste nel collegarsi direttamente alle classi observer che si trovano tra le classi viewmodel.

+0

Grazie per il link; In realtà stavo usando un modello simile a questo per altri coordinamenti, condividendo un servizio IMainViewModel, che è implementato dal mio MainViewModel. Sto pensando che abbia senso rifattorizzarlo ulteriormente in modo che la funzionalità 'condivisa' non sia legata nel modello per la finestra principale e sia, invece, un MainObserver. –

+1

Questo è stato un approccio utile. Il mio design è ancora un po 'schizofrenico, ma sto iniziando a vedere come le VM possono comunicare usando i servizi condivisi. Sembra un po 'invertito, dato che sono abituato a un "genitore" che sa tutto sui suoi "bambini". Ora è più una questione della mia classe che dice "Ho bisogno di fare questo" e parte della domanda che non so quasi più di intensificare e prendermi cura di me. –

3

Penso che tu voglia rendere il tuo livello di primo livello ViewModel consapevole dell'esistenza dello NestedViewModel, ha senso da un punto di vista gerarchico, la vista principale contiene la vista figlio.

A mio parere, l'istinto è corretto, non sembra corretto che ViewModel nidificato esponga comportamenti avviati dalle azioni dell'utente al livello principale. Invece, il livello superiore ViewModel dovrebbe fornire comportamenti per la vista a cui è associato.

Ma prenderei in considerazione la possibilità di trasferire la responsabilità per la costruzione di una connessione in un ICommand e di esporre questo comando tramite il tuo livello principale ViewModel. Il pulsante OK nella finestra di dialogo principale sarà quindi associato a questo comando e il comando delegherà semplicemente al livello superiore ViewModel, ad esempio chiamando lo ViewModel.CreateConnection() quando viene eseguito.

La responsabilità del controllo nested è quindi puramente raccogliendo ed esponendo i dati al suo NestedViewModel, per il consumo da parte contenente ViewModel, ed è teoricamente più riutilizzabile in contesti diversi che richiedono le stesse informazioni da inserire (se any) - supponiamo che tu voglia riutilizzarlo per modificare le connessioni già create.

L'unica ruga sarebbe se i diversi tipi di NestedViewModel espongano un insieme di dati radicalmente diverso.

Per esempio, uno espone HostName e Port come proprietà, e un altro espone UserName e password.

In tal caso, potrebbe essere necessario eseguire alcune operazioni infrastrutturali per fare in modo che il livello superiore ViewModel.CreateConnection() funzioni correttamente. Anche se si dispone di una piccola quantità di tipi di controllo annidati, potrebbe non valerne la pena, e un semplice controllo e cast di tipo NestedViewModel può essere sufficiente.

Questo suono è valido?

+0

La sfida qui è che il ViewModel esterno non conosce il tipo del suo InnerViewModel in fase di compilazione. I controller sono introdotti come estensioni all'applicazione in fase di esecuzione, con qualche tipo di scoperta sotto il cofano per collegare lo specifico controllo annidato tramite un DataTemplateSelector personalizzato. So che DataContext implicitamente sarà il ViewModel nidificato specifico, ma mi sembra utile controllare il DataContext e provare a lanciarlo su un'interfaccia condivisa. –

0

Recentemente ho sperimentato con Unity (libreria Microsoft Enterprise) per utilizzare l'iniezione di dipendenza. Questa potrebbe essere una strada da percorrere quando si usano interfacce che definiscono completamente ciò che entrambi i modelli visivi non hanno bisogno l'uno dell'altro. MEF sarebbe un'altra opzione per l'iniezione di dipendenza di cui sono a conoscenza.

HTH

+0

Grazie, in realtà sto usando MEF in questa applicazione e ha aiutato un bel po 'a consentire un'estensibilità molto ricca dell'interfaccia utente. È questa estensibilità a creare sfide di progettazione, poiché ora l'interfaccia utente ospita controlli di cui non sa quasi nulla.In realtà ho trovato un modo più pulito per farlo, che illustrerò di più una volta arrivato a casa oggi. –

Problemi correlati