2010-11-14 12 views
12

Zaczynam swoją pierwszą podróż w świat Prism v4/MVVM z MEF & WPF. Z powodzeniem zbudowałem powłokę i używając MEF, jestem w stanie odkryć i zainicjować moduły. Nie jestem jednak pewien, w jaki sposób można zapewnić nawigację do widoków odsłoniętych przez te moduły.Prism/MVVM (MEF/WPF): Ekspozycja nawigacji [menu na przykład] z modułów

Na przykład, powiedzmy, że jeden z modułów udostępnia trzy widoki i chcę wyświetlić nawigację do tych widoków w menu sterowania. Do tej pory z powodzeniem wyeksponowałem widok oparty na MenuItem i ten MenuItem zawiera elementy sterujące podrzędne, które zapewniają hierarchię poleceń, która może być użyta. Wspaniały.

Chodzi o to, że czuje się źle. Teraz stwierdzam w swoim module, że nawigacja (a więc i powłoka) MUSI wspierać obsługę menu. Co jeśli chciałbym zmienić na ToolBar lub nawet Ribbon. Musiałbym wtedy zmienić wszystkie moje moduły, aby odsłonić odpowiednie typy kontrolne dla powłoki.

Rozejrzałem się i na niektórych witrynach jest mowa o "usłudze" zapewniającej nawigację, przy czym podczas inicjalizacji modułu opcje nawigacji są dodawane do usługi, która z kolei jest używana przez powłokę do wyświetlenia tę nawigację w dowolnym formacie, jakiego chce (ToolBar, TreeView, Ribbon, MenuItem itd.) - ale nie mogę znaleźć przykładów takiego działania.

Aby przedstawić to wszystko w perspektywie, ostatecznie szukam możliwości wyboru widoków z menu i/lub innej kontroli nawigacji (prawdopodobnie Ribbon), a następnie otworzyć te widoki na żądanie w TabControl. Już udało mi się stworzyć widoki w TabControl w czasie inicjalizacji modułu, teraz potrzebuję następnego kroku.

Co muszę wiedzieć, to: jaki byłby właściwy sposób na wyeksponowanie opcji nawigacji w taki sposób, aby nie wymagać obsługi określonej kontroli przez powłokę, a jeśli usługa jest drogą do zrobienia, jak by to połączyć w pryzmat/wzorce MVVM.

Z góry dziękujemy za wszelki wgląd, jaki możesz zaoferować.

Odpowiedz

7

Przypuszczam, że masz główny moduł zawierający popularne interfejsy. Można stworzyć prosty interfejs jak

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

Stwórz 1 wdrożenia i jedno wystąpienie.

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

w swoim modułów, należy użyć MEF aby rozwiązać ten przypadek i nazywają AddItem() zarejestrować swoje poglądy. Właściwość Action to prosty element delegujący do aktywowania widoku lub wykonywania innych czynności.

Następnie w powłoce lub w dowolnym widoku wystarczy wywołać właściwość GetItems, aby zapełnić menu.

+0

Podobają mi się, ponieważ jest to całkowicie ogólna opcja, która pozostawia powłokę, aby zdecydować, w jaki sposób będzie wyświetlać przedmioty. To powiedziawszy, miałem dalsze przemyślenia na ten temat i faktycznie przeszedłem inną drogę, którą będę dokumentować jako oddzielną odpowiedź. Dzięki. –

+0

Nie zapomnij, że możesz ustawić 'MenuItemViewModel' dopasowany do MenuItems (można sprawdzić lub mieć podpozycje). Będziesz musiał stworzyć bardziej specyficzny interfejs. Ale to był przykład. Baw się dobrze. – SandRock

1

Po przemyśleniu tego więcej, doszedłem do następującego wniosku, że mam wpływ na sposób, w jaki muszę sobie z tym poradzić ...

W każdym razie moduły muszą być częściowo świadome układu powłoki - to znaczy, że powłoka udostępnia kilka regionów, a moduły muszą być świadome tych regionów (według nazwy i tego, co ma być pokazane) w celu ich prawidłowego wypełnienia, gdy wymagana jest funkcjonalność (albo poprzez rejestrację widoku w regionie, albo jako reakcję na działanie użytkownika).

Z tego powodu moduły muszą być zaprojektowane do interakcji z powłoką w celu umieszczenia zawartości w nazwanych regionach i jako takie nie widzę powodu, dla którego moduły nie powinny ujawniać jakiejkolwiek nawigacji obsługiwanej przez powłokę.

Dlatego moje moduły (obecnie) eksponują "RibbonView" (RibbonTab) z niezbędnymi ikonami, przyciskami i poleceniami, aby pokazać funkcjonalność modułu. Każdy "RibbonView" jest zarejestrowany w "RibbonRegion" powłoki, wraz z podpowiedziami do zamawiania, a następnie jest renderowany wewnątrz powłoki.

Jeśli w przyszłości wybrać, aby zaktualizować skorupę do korzystania z najnowszego + największą kontrolę nawigacji (cokolwiek to może być w x lat razem), a następnie po prostu trzeba zaktualizować każdy z modułów wystawiać niezbędne elementy do zintegrować z tą nową nawigacją i, ponieważ ładuję do nowej powłoki, mogę wtedy odpowiednio zaktualizować moją rejestrację widoku.

Mam tylko nadzieję, że nie łamie to żadnej z zasad złożonej aplikacji, ale powiedziałem, że jeszcze nie znalazłem schematu, który może być faktycznie zrealizowany w rzeczywistym scenariuszu bez jakiejś "interpretacji".

Chciałbym usłyszeć, jeśli ktoś ma jakieś zdanie na ten temat.

0

Napotkano na tę samą sytuację i myślę, że rozwiązanie polega na rozróżnieniu interfejsu i implementacji. Na przykład można zaprojektować widok w module, który wykonuje daną funkcję. To wszystko, co robi. Jak tylko użyjesz lub skonsumujesz to w określonym kontekście, przejdziesz do implementacji. Idealnie, widok nie jest świadomy tego, jak jest realizowany i na pewno nie miałby wiedzy o nazwanych regionach w powłoce. Tak więc, widok miejsc w regionach w module jest nie-nie.

Aby obejść ten problem, postanowiłem przekazać tę odpowiedzialność do komponentu innej firmy, LayoutManager. LayoutManager znajduje się pomiędzy powłoką a modułem i definiuje "co dalej". Jest to specyficzna implementacja i naprawdę definiuje implementację. Widok powłoki i modułu pozostaje ogólny.

Zapraszamy do obejrzenia: http://rgramann.blogspot.com/2009/08/layout-manager-for-prism-v2.html

co może dać Ci kilka pomysłów wokół tego problemu.

Mam nadzieję, że to pomaga.

+0

Całkowicie zgadzam się, że wiedząc o regionach powłoki, moje moduły są powiązane z konkretną implementacją, ale do tej pory walczyłem o pomysły, jak to obejść. Chociaż twój artykuł nie odnosi się bezpośrednio do mojej sytuacji (masz tylko jeden region i jesteś w pełni świadomy załadowanych widoków w celu umieszczenia ich w twojej konfiguracji), to dało mi to kilka pomysłów na to, jak mogę obejść problem. Dzięki. –

0

Ten article używa abstrakcji (IMenuItem) do reprezentowania ViewModels dla wyborów menu. Sposób renderowania zaimportowanych obiektów zależy od aplikacji hosta. W przykładzie użyto menu WPF, ale z pewnością można go renderować w dowolny sposób, ponieważ IMenuItem jest wystarczająco abstrakcyjny.

Jeśli zmieniłeś IMenuItem na INavigationItem, masz to, czego chcesz.

W tym artykule, gdy dany element nawigacyjny otrzyma powiadomienie, że został "uruchomiony", zwykle tworzy instancję ViewModel dla dokumentu lub "pada" i przekazuje go do usługi ILayoutManager.Ma on wtyczkową architekturę, więc możesz zamienić usługę LayoutManager na inny mechanizm układu (domyślnie jest to wrapper wokół AvalonDock).

Powiązane problemy