2010-11-14 14 views
12

sto iniziando la mia prima incursione nel mondo del prisma v4/MVVM con MEF & WPF. Ho costruito con successo una shell e, usando MEF, sono in grado di scoprire e inizializzare i moduli. Tuttavia, non sono sicuro del modo corretto di fornire la navigazione alle viste esposte da questi moduli.Prism/MVVM (MEF/WPF): Esposizione di navigazione [per esempio di Menu] dai moduli

Per esempio, diciamo che uno dei moduli espone tre punti di vista e voglio visualizzare la navigazione a questi punti di vista su un controllo di menu. Finora, ho esposto con successo una vista basata su una MenuItem e questo MenuItem contiene bambino MenuItem controlli fornendo così una gerarchia di comando che può essere utilizzato. Grande.

Il fatto è che questo sembra sbagliato. Ora sto affermando nel mio modulo che la navigazione (e quindi la shell) DEVE supportare l'uso dei menu. Cosa succede se volevo passare all'utilizzo di ToolBar o anche a Ribbon. Dovrei quindi cambiare tutti i miei moduli per esporre i corrispondenti tipi di controllo per la shell.

Mi sono guardato intorno e su alcuni siti è stato menzionato l'utilizzo di un "Servizio" per fornire la navigazione, per cui durante l'inizializzazione del modulo, le opzioni di navigazione vengono aggiunte al servizio che a sua volta viene utilizzato dalla shell per visualizzare questa navigazione in qualsiasi formato che vuole (ToolBar, TreeView, Ribbon, MenuItem ecc) - ma non riesco a trovare alcun esempio di realtà facendo questo.

Per mettere tutto in prospettiva, alla fine sto cercando di essere in grado di selezionare le visualizzazioni da un menu e/o un altro controllo di navigazione (probabilmente uno Ribbon) e quindi aprire tali visualizzazioni su richiesta all'interno di un TabControl. Sono già riuscito a creare le viste nel TabControl in fase di inizializzazione del modulo, ora ho bisogno del passaggio successivo.

Quello che ho bisogno di sapere è questo: quale sarebbe il modo corretto di esporre le opzioni di navigazione in modo tale da non insistere sul supporto di un controllo specifico da parte della shell, e se un servizio è la strada da percorrere allora come si potrebbe mettere questo insieme nei modelli Prism/MVVM.

Grazie in anticipo per qualsiasi comprensione si può offrire.

risposta

7

Suppongo che tu abbia un modulo principale contenente interfacce comuni. Si potrebbe creare una semplice interfaccia simile

public interface IMenuService { 
    void AddItem(string name, Action action); 
    IEnumerable<MenuItemViewModel> GetItems { get; } 
} 

Crea 1 attuazione e una singola istanza.

public class MenuService : IMenuService { 

    private readonly IList<MenuItemViewModel> items = new List<MenuItemViewModel>(); 

    void AddItem(string name, Action action) { 
     items.Add(new MenuItemViewModel { 
      Name = name, 
      Action = action 
     }); 
    } 

    IEnumerable<MenuItemViewModel> GetItems { 
     get { return list.AsEnumerable(); } 
    } 
} 

Entro i moduli, utilizzare MEF per risolvere questo caso e chiamare AddItem() per registrare le vostre opinioni. La proprietà Action è un semplice delegato per attivare una vista o fare qualsiasi altra cosa.

Poi nella shell o qualsiasi vista, è solo bisogno di chiamare la proprietà GetItems per popolare il menu.

+0

Mi piace in quanto è un'opzione totalmente generica che lascia la shell per decidere come visualizzare gli elementi. Detto questo, ho avuto ulteriori riflessioni sul mio argomento e sono effettivamente passato a un'altra strada che documenterò come una risposta separata. Grazie. –

+0

Ricordatevi che è possibile impostare 'MenuItemViewModel 'su MenuItems (controllabile o con voci secondarie). Dovrai creare un'interfaccia più specifica. Ma questo era un esempio. Divertiti. – SandRock

1

averci pensato su questo un po ', sono giunto alla seguente conclusione che mi sento colpisce il modo in cui ho bisogno per far fronte a questo ...

I moduli devono essere parzialmente consapevoli del layout shell comunque - cioè, il guscio espone alcune regioni ei moduli devono essere consapevoli di tali regioni (nome così come quello che dovrebbe essere mostrato) per popolarli correttamente quando viene richiesta la funzionalità (o mediante la registrazione di una vista all'interno di una regione o come reazione a un'azione dell'utente).

Per questo motivo, i moduli devono essere progettati per interagire con la shell per posizionare il contenuto nelle regioni nominate e, pertanto, non vedo perché i moduli non debbano esporre il tipo di navigazione supportato dalla shell.

Pertanto, i miei moduli (attualmente) espongono un "RibbonView" (un RibbonTab) con le icone, i pulsanti e i comandi necessari per esporre la funzionalità del modulo. Ogni "RibbonView" è registrata con "RibbonRegion" della shell, insieme a suggerimenti per l'ordinamento, e viene quindi renderizzata all'interno della shell.

Se in futuro ho scelto di aggiornare il mio guscio di utilizzare l'ultima massimo controllo + navigazione (qualunque essa sia in x anni di tempo), poi ho semplicemente bisogno di aggiornare ciascuno dei moduli per esporre gli elementi necessari per integrare con quella nuova navigazione e, poiché sto caricando in una nuova shell, posso quindi aggiornare la registrazione della mia vista di conseguenza.

Spero solo di non infrangere nessuno dei principi dell'applicazione composita, ma ho detto che non ho mai trovato un modello che possa essere effettivamente implementato in uno scenario reale senza alcuna "interpretazione".

Sarei interessato a sapere se qualcuno ha qualche opinione su questo.

0

Ho riscontrato la stessa situazione e penso che la soluzione risieda nella differenziazione tra interfaccia e implementazione. Ad esempio, puoi progettare una vista in un modulo che esegue una determinata funzione. Questo è tutto ciò che fa. Non appena lo usi o lo consumi in un contesto specifico, sei passato all'implementazione. Ora, idealmente, la vista non è a conoscenza di come viene implementata e sicuramente non avrebbe alcuna conoscenza delle Regioni denominate nella Shell. Quindi, posizionare le viste in regioni all'interno di un modulo è un no-no.

Per ovviare a questo, ho deciso di delegare questa responsabilità a un componente di terze parti, un LayoutManager. Il LayoutManager si trova tra Shell e Module e definisce "cosa va dove". È un'implementazione specifica e definisce realmente l'implementazione. Sia la vista Shell che quella modulo rimangono generiche.

Dai un'occhiata alla: http://rgramann.blogspot.com/2009/08/layout-manager-for-prism-v2.html

che potrebbe dare qualche idea per aggirare questo problema.

Spero che aiuti.

+0

Concordo pienamente sul fatto che, conoscendo le regioni della shell, i miei moduli siano legati a un'implementazione specifica, ma fino ad ora stavo lottando per le idee su come eludere ciò. Anche se il tuo articolo non affronta direttamente la mia situazione (hai solo una singola regione e sei pienamente consapevole delle visualizzazioni caricate per metterle nella tua configurazione), mi ha dato alcune idee su come avrei potuto aggirare il problema. Grazie. –

0

Questo article utilizza un'astrazione (IMenuItem) per rappresentare ViewModels per le opzioni di menu. Il modo in cui esegui il rendering di questi oggetti importati dipende in realtà dall'applicazione host. L'esempio utilizza un menu WPF, ma puoi sicuramente renderlo come vuoi perché IMenuItem è abbastanza astratto.

Se hai cambiato IMenuItem in INavigationItem, hai ciò che desideri.

In questo articolo, quando il particolare elemento di navigazione viene notificato che è stato "eseguito", di solito crea un ViewModel per un documento o "pad" e lo passa al servizio ILayoutManager.Ha un'architettura collegabile, quindi è possibile scambiare il servizio LayoutManager con un motore di layout diverso (quello predefinito è un wrapper di AvalonDock).

Problemi correlati