2010-04-29 10 views

Odpowiedz

7

jestem w środku budynku pełnoprawną rozszerzalna aplikacja na MEF (i przy użyciu WPF wzorkiem MVVM) . Wziąłem podstawowe ramy aplikacji, które zbudowałem i otworzyłem je jako SoapBox Core. Wydałem także demo oparte na SoapBox Core w Code Project: Building an Extensible Application with MEF, WPF, and MVVM.

Nie jestem pewien, czy przy użyciu MVVM cechy, ale jeśli tak, to istnieje wiele można dowiedzieć się, patrząc na realizację MVVM z MEF. Szczególnie sposób, w jaki importuje widoki.

Jeśli chodzi o najlepsze praktyki ... Stworzyłem zagnieżdżoną hierarchię rozszerzeń (tak, że podstawowy moduł nazywa się Host, a wszystko, co robi, to komponowanie aplikacji i importowanie kilku podstawowych rozszerzeń). Następnie rozszerzenia te eksponują inne punkty rozszerzeń, a rodzaj aplikacji buduje się sam, gdy go uruchomisz (skrzyżowanie kompozycji i rozszerzeń).

Aby wszystko było proste, ustawiam hierarchię rozszerzeń w zestaw klas statycznych. Na przykład, tutaj są wszystkie punkty rozszerzeń, że ramy rdzeń zapewnia:

namespace SoapBox.Core.ExtensionPoints 
{ 
    public static class Host 
    { 
     public const string Styles = "ExtensionPoints.Host.Styles"; 
     public const string Views = "ExtensionPoints.Host.Views"; 
     public const string StartupCommands = "ExtensionPoints.Host.StartupCommands"; 
     public const string ShutdownCommands = "ExtensionPoints.Host.ShutdownCommands"; 
    } 
    public static class Workbench 
    { 
     public const string ToolBars = "ExtensionPoints.Workbench.ToolBars"; 
     public const string StatusBar = "ExtensionPoints.Workbench.StatusBar"; 
     public const string Pads = "ExtensionPoints.Workbench.Pads"; 
     public const string Documents = "ExtensionPoints.Workbench.Documents"; 

     public static class MainMenu 
     { 
      public const string Self = "ExtensionPoints.Workbench.MainMenu"; 
      public const string FileMenu = "ExtensionPoints.Workbench.MainMenu.FileMenu"; 
      public const string EditMenu = "ExtensionPoints.Workbench.MainMenu.EditMenu"; 
      public const string ViewMenu = "ExtensionPoints.Workbench.MainMenu.ViewMenu"; 
      public const string ToolsMenu = "ExtensionPoints.Workbench.MainMenu.ToolsMenu"; 
      public const string WindowMenu = "ExtensionPoints.Workbench.MainMenu.WindowMenu"; 
      public const string HelpMenu = "ExtensionPoints.Workbench.MainMenu.HelpMenu"; 
     } 
    } 

    public static class Options 
    { 
     public static class OptionsDialog 
     { 
      public const string OptionsItems = "ExtensionPoints.Options.OptionsDialog.OptionsItems"; 
     } 
    } 
} 

Więc jeśli chciał swoje rozszerzenie coś dodać do menu Plik, by eksportować coś, który implementuje IMenuItem o nazwie kontrakt SoapBox.Core. ExtensionPoints.Workbench.MainMenu.FileMenu

Każde rozszerzenie ma "ID", który jest tylko identyfikatorem łańcucha. Identyfikatory te istniejące są zdefiniowane w innej hierarchii:

namespace SoapBox.Core.Extensions 
{ 
    public static class Workbench 
    { 
     public static class MainMenu 
     { 
      public const string File = "File"; 
      public const string Edit = "Edit"; 
      public const string View = "View"; 
      public const string Tools = "Tools"; 
      public const string Window = "Window"; 
      public const string Help = "Help"; 

      public static class FileMenu 
      { 
       public const string Exit = "Exit"; 
      } 

      public static class ViewMenu 
      { 
       public const string ToolBars = "ToolBars"; 
      } 

      public static class ToolsMenu 
      { 
       public const string Options = "Options"; 
      } 
     } 
    } 
} 

Jak widać FileMenu zawiera już rozszerzenie exit (który jest zaprogramowany, aby zamknąć aplikację). Jeśli chcesz dodać rozszerzenie do menu Plik, prawdopodobnie chcesz, aby pojawił się przed elementem menu Wyjście. IMenuItem dziedziczy IExtension, który ma dwie właściwości:

  • InsertRelativeToID
  • BeforeOrAfter

Więc przedłużenie wróci SoapBox.Core.Extensions.Workbench.MainMenu.FileMenu.Exit dla InsertRelativeToID, i return Przed dla właściwości BeforeOrAfter (wyliczenie). Gdy środowisko robocze importuje wszystkie rozszerzenia menu Plik, sortuje wszystko na podstawie tych identyfikatorów. W ten sposób późniejsze rozszerzenia wstawiają się w stosunku do istniejących rozszerzeń.

6

najlepiej praktyką jest stosowanie modelu Shared (singleton). To doprowadzi nas do zaprojektowania wzajemnego świadczenia, które sugerowałyby, że należy zaprojektować wywożonych części jako bezpaństwowiec i wątku bezpieczne, więc nie zostaną naruszone przez wielu połączeń (być może na różnych wątków) po tej samej instancji.

W przypadkach, że Singleton model nie jest odpowiedni dla ciebie, to zaleca się stosowanie budowniczy (aby oddzielić część eksportowanego od rzeczywistego instancji). Należy pamiętać, że korzystając z braku wspólnego modelu jest dość kosztowne, ponieważ jest przy użyciu odbicia do rzeczywistej instancji (przy użyciu wzorca budowniczy można uzyskać ten sam rezultat z mniejszym bólem).

Zobacz również tutaj http://blogs.microsoft.co.il/blogs/bnaya/archive/2010/01/09/mef-for-beginner-toc.aspx I cource wiesz, że można znaleźć informacji: http://mef.codeplex.com

2

Jestem wciąż nowy w MEF, ale chciałem dodać więcej do tej dyskusji, ponieważ nieustannie przechodzę przez piekło, gdy próbuję zrozumieć, dlaczego rzeczy nie działają tak, jak tego oczekuję.

Przede wszystkim podczas pracy z MEF zalecam dodanie do rozwiązania System.ComponentModel.Composition, a nie tylko dodawanie odniesień do złożeń. Chociaż problemy z debugowaniem w MEF są jak koszmar rekursywny, jest to absolutnie nieuniknione i ważne, kiedy nie możesz zrozumieć, co się dzieje.

To prowadzi mnie do następnego punktu, który nigdy nie zapomnę, że MEF nie wie o tym, czego nie mówisz, lub , jeśli nie powiesz tego właściwie. Na przykład moja aplikacja alpha działała wspaniale z MEF - musiałem komponować części w głównym interfejsie GUI, a wszystkie złożenia, które zostały załadowane przez kontener (które były zależnościami głównej aplikacji) wyeksportowały niezbędne interfejsy. Sprawy się sprawdziły i udało mi się przekonać MEF do rozwiązywania przypadków, kiedy i gdzie chciałem.

Jednak właśnie zacząłem pracować nad kolejną wersją; niektóre załadowane wtyczki (te, które wyeksportowały interfejs, ale nie wymagały importu), a inne nie (wymagające importu). Tym razem skomponowałem części w mojej klasie ApplianceManager, która jest odpowiedzialna za ładowanie wtyczek, ale wtyczki potrzebne do rozpoznania importu z innych klas aplikacji (w moim przypadku Modelu). Pomyślałem, że powinno to nastąpić automatycznie, zwłaszcza, że ​​widzę w konstrukcji katalogu, że te zespoły zostały wykryte ... ale nadal nie mogę go uruchomić ... co przywraca mnie do pierwszego punktu - dodaj źródło kod, a nie same złożenia. Debugowanie tego niemal doprowadza mnie do szaleństwa, ale w końcu odkryję to po długim starannym przejściu przez kod MEF. :)

Chciałbym, aby ktoś wysłał odpowiedź na to pytanie, które mówi o architekturach, które ułatwiają łatwą integrację z MEF. Odpowiedź na temat menu paska narzędzi i tak jest naprawdę dobra, ale chciałbym zobaczyć coś, co mówi o rzeczach, które znajdują się całkowicie po stronie modelu MVVM. Podobnie powinno wyglądać zarządzanie wtyczkami, bazami danych, wtyczkami i bibliotekami współdzielonymi. Nadal staram się zrozumieć, dlaczego miałem dość czasu, aby moja pierwsza aplikacja MEF działała, ale po uzyskaniu więcej "doświadczenia" z nią, nie mogę sprawić, aby moja nowa aplikacja działała w 100%.

UPDATE 2010-06-09

Chciałbym dodać kolejną możliwą praktykę za pomoc nawigować przez MEF krzewów. Dzisiaj musiałem wykonać test poprawności tego projektu, którego "nie mogłem pojąć", więc stworzyłem prosty, niekonwencjonalny schemat klasy UML, w którym używałem zależności do oznaczania importu i eksportu. Oto, co znalazłem, co bardzo wyraźnie wyjaśniło sprawę.

aplikacja robocza: alt text

aplikacja nieprodukcyjnym: alt text

Czy to nie głupie? Model nie był załadowany i był na wyspie sam w sobie. I Wierzę, że to dlatego moje zależności oparte na MEF nie są rozwiązywane (jeśli ktokolwiek może mnie przekląć, jeśli się mylę, to byłbym wdzięczny!)

+2

Twoje zdjęcia są zepsute. –

+0

Ugh ... Musiałem usunąć niektóre obrazy z mojego konta. Będę musiał szukać oryginałów. Dzięki, że dałeś mi znać. – Dave

Powiązane problemy