2010-11-14 6 views
12

Ich beginne meinen ersten Ausflug in die Welt von Prism v4/MVVM mit MEF & WPF. Ich habe erfolgreich eine Shell gebaut und mithilfe von MEF Module entdecken und initialisieren können. Ich bin mir jedoch unsicher, wie die Ansichten dieser Module richtig dargestellt werden.Prism/MVVM (MEF/WPF): Exposing Navigation [Menü zum Beispiel] von Modulen

Angenommen, eines der Module bietet drei Ansichten und ich möchte die Navigation zu diesen Ansichten in einem Menü-Steuerelement anzeigen. Bis jetzt habe ich erfolgreich eine Ansicht basierend auf einer MenuItem ausgesetzt und diese MenuItem enthält Kind MenuItem steuert so eine Befehlsherarchie, die verwendet werden kann. Groß.

Das ist, das fühlt sich falsch an. Ich sage jetzt in meinem Modul, dass die Navigation (und damit die Shell) die Verwendung von Menüs unterstützen muss. Was wäre, wenn ich einen ToolBar oder sogar einen verwenden möchte? Ich müsste dann alle meine Module ändern, um die entsprechenden Kontrolltypen für die Shell freizulegen.

Ich habe mich umgesehen und es gibt auf einigen Seiten die Erwähnung eines "Service" zur Navigation, wobei bei der Initialisierung des Moduls Navigationsoptionen dem Dienst hinzugefügt werden, der wiederum von der Shell zur Anzeige verwendet wird Diese Navigation in welchem ​​Format auch immer (ToolBar, TreeView, , MenuItem etc.) - aber ich kann keine Beispiele dafür finden, dies tatsächlich zu tun.

Um all dies in die richtige Perspektive zu bringen, suche ich schließlich in der Lage sein, Ansichten aus einem Menü und/oder anderen Navigationssteuerung (wahrscheinlich ein) auszuwählen und dann diese Ansichten bei Bedarf innerhalb einer TabControl zu öffnen. Ich bin schon so weit gekommen, dass ich die Ansichten in der TabControl zur Modulinitialisierungszeit erstellen kann, jetzt brauche ich den nächsten Schritt.

Was ich wissen muss, ist das: Was wäre der richtige Weg, um Navigationsoptionen so zu exponieren, dass nicht auf die Unterstützung einer bestimmten Steuerung durch die Shell bestehen, und wenn ein Service der richtige Weg ist Wie würde man das innerhalb der Prism/MVVM-Muster zusammensetzen?

Vielen Dank im Voraus für jede Einsicht, die Sie anbieten können.

Antwort

7

Ich nehme an, Sie haben ein Hauptmodul mit gemeinsamen Schnittstellen. Sie könnten eine einfache Schnittstelle erstellen wie

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

erstellen 1-Implementierung und eine einzelne Instanz.

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(); } 
    } 
} 

Innerhalb Ihrer Module, MEF verwenden diese Instanz zu lösen und AddItem() rufen Sie Ihre Ansichten zu registrieren. Die Eigenschaft Action ist ein einfacher Delegat, um eine Ansicht zu aktivieren oder irgendetwas anderes zu tun.

Dann in Ihrer Shell oder einer Ansicht, müssen Sie nur die GetItems Eigenschaft aufrufen, um Ihr Menü zu füllen.

+0

Ich mag diese Art, da es eine völlig generische Option ist, die die Shell verlässt, um zu entscheiden, wie sie die Elemente anzeigen wird. Abgesehen davon habe ich weitere Gedanken zu diesem Thema gehabt und bin tatsächlich einen anderen Weg gegangen, den ich als separate Antwort dokumentieren werde. Vielen Dank. –

+0

Vergessen Sie nicht, dass Sie ein MenuItemViewModel an MenuItems anpassen können (check-fähig oder mit Unterpunkten). Sie müssen eine spezifischere Schnittstelle herstellen. Aber das war ein Beispiel. Habe Spaß. – SandRock

1

Nachdem ich darüber nachgedacht habe, bin ich zu der folgenden Schlussfolgerung gekommen, dass ich die Art und Weise, wie ich damit umgehen muss, beeinflusst ...

Die Module müssen das Shell-Layout trotzdem teilweise kennen - das heißt, die Shell legt eine Anzahl von Regionen offen und die Module müssen diese Regionen kennen (sowohl Namen als auch was erwartet wird) um sie korrekt zu füllen, wenn Funktionalität angefordert wird (entweder durch Registrieren einer Ansicht in einer Region oder als Reaktion auf eine Benutzeraktion).

Aus diesem Grund müssen die Module so entworfen werden, dass sie mit der Shell interagieren, um Inhalt in die benannten Regionen zu platzieren. Daher sehe ich keinen Grund, warum die Module keine Art von Navigation der Shell unterstützen sollten.

Daher stellen meine Module (derzeit) ein "RibbonView" (ein RibbonTab) mit den notwendigen Symbolen, Schaltflächen und Befehlen usw. zur Verfügung, um die Funktionalität des Moduls zu offenbaren. Jedes "RibbonView" wird mit der "RibbonRegion" der Shell zusammen mit Hinweisen für die Reihenfolge registriert, und dies wird dann in der Shell gerendert.

Wenn ich in Zukunft meine Shell zu aktualisieren, um die neueste + größte Navigationssteuerung (was auch immer in x Jahre Zeit) verwenden kann, muss ich einfach jedes der Module aktualisieren, um die erforderlichen Elemente zu offenbaren Integration mit dieser neuen Navigation und, weil ich in eine neue Shell lade, kann ich dann meine Ansicht Registrierung entsprechend aktualisieren.

Ich hoffe nur, dass ich keine der Prinzipien der zusammengesetzten Anwendung dabei durchbringe, aber das sagte ich habe noch nie ein Muster gefunden, das tatsächlich in einem realen Szenario ohne irgendeine "Interpretation" implementiert werden kann.

Ich würde mich interessieren zu hören, ob jemand irgendwelche Meinungen dazu hat.

0

Ich habe die gleiche Situation, und ich denke, die Lösung liegt in der Unterscheidung zwischen Schnittstelle und Implementierung. Zum Beispiel können Sie eine Ansicht in einem Modul entwerfen, das eine bestimmte Funktion ausführt. Mehr ist es nicht. Sobald Sie dies in einem bestimmten Kontext verwenden oder konsumieren, sind Sie in die Implementierung übergegangen. Nun, im Idealfall ist die Ansicht nicht bewusst, wie sie implementiert wird, und sicherlich würde sie die benannten Regionen in der Shell nicht kennen. So, Sitzansichten in Regionen innerhalb eines Moduls ist ein No-No.

Um dies zu umgehen, habe ich entschieden, diese Verantwortung an eine Komponente von Drittanbietern, einen LayoutManager zu delegieren. Der LayoutManager befindet sich zwischen der Shell und dem Modul und definiert "was wohin geht". Es ist eine spezifische Implementierung und definiert die Implementierung wirklich. Sowohl die Shell- als auch die Modulansicht bleiben generisch.

Werfen Sie einen Blick auf: http://rgramann.blogspot.com/2009/08/layout-manager-for-prism-v2.html

Welche Ihnen einige Ideen, um dieses Problem geben kann.

Ich hoffe, es hilft.

+0

Ich stimme vollkommen zu, dass meine Module durch die Kenntnis der Shell-Regionen an eine bestimmte Implementierung gebunden sind, aber bis jetzt habe ich um Ideen gekämpft, wie ich das umgehen kann. Obwohl Ihr Artikel nicht direkt auf meine Situation eingeht (Sie haben nur eine einzige Region und Sie wissen genau, dass die Ansichten geladen werden, um sie in Ihre Konfiguration zu bringen), hat er mir einige Ideen gegeben, wie ich mich um die Problem. Vielen Dank. –

0

Diese article verwendet eine Abstraktion (IMenuItem), um die ViewModels für Ihre Menüauswahl darzustellen. Wie Sie diese importierten Objekte tatsächlich rendern, hängt wirklich von der Host-Anwendung ab. Das Beispiel verwendet ein WPF-Menü, aber Sie können es natürlich beliebig darstellen, weil IMenuItem abstrakt genug ist. Wenn Sie IMenuItem zu INavigationItem geändert haben, haben Sie, was Sie wollen.

In diesem Artikel, wenn das bestimmte Navigationselement benachrichtigt wird, dass es "ausgeführt" wurde, instanziiert es normalerweise ein ViewModel für ein Dokument oder ein "Pad" und übergibt das an den ILayoutManager-Dienst.Es verfügt über eine Pluggable-Architektur, sodass Sie den LayoutManager-Service für eine andere Layout-Engine austauschen können (die Standard-Engine ist ein Wrapper um AvalonDock).

Verwandte Themen