2016-05-25 20 views
-1

Ich konvertiere gerade meine WPF/MVVM-Anwendung von Ninject zu MEF, um einige Plugin-Architektur zu nutzen. Es gibt weder Prisma noch Einheit, noch möchte ich diesen Weg gehen. Ich verwende VS2015 und .Net 4.6.MEF: Erstellen eines ViewModel in meinen UserControls

Ich verwendete die Technik, die bei MVVM Light beliebt war, wo Sie das ViewModel innerhalb des XAML mit Ninject instanziieren.

Aber jetzt, wo ich auf MEF umziehen möchte, würde ich gerne sehen, ob es Alternativen gibt. Die meisten der aktuell beantworteten Posts auf Stack Exchange sind ziemlich alt und ich hoffe, dass es jetzt einige neue Alternativen gibt, die verfügbar sind, wenn .NET 4.5 verfügbar ist.


tl; dr

Ich habe ein Fenster, das 10 Benutzersteuerelemente enthält. Jedem Benutzersteuerelement ist eine neue Instanz eines ViewModels zugeordnet. Da das Fenster die Benutzersteuerelemente in XAML erstellt, wie kann ich eine eindeutige Instanz meines ViewModel in jedes Steuerelement importieren?

public partial class FingerprintControl{ 

    public FingerprintControl() { 
     InitializeComponent(); 
    } 

    [Import] 
    public FingerprintControlViewModel ViewModel 
    { 
     get { return DataContext as FingerprintControlViewModel; } 
     set { DataContext = value; } 
    } 

Ein Vorschlag, dass ich sagte, sah

CompositionInitializer.SatisfyImports(this); 

nach dem InitializeComponent() hinzufügen. Aber das ist eine Silverlight-Klasse.

Ich schaute auf https://www.nuget.org/packages/Microsoft.Composition/, aber die Dokumentation für MEF 2 ist einfach unglaublich nicht auf der Website.

Ich sah auch, dass ExportFactory zu MEF 2 hinzugefügt wurde, aber nicht sicher, ob das auch helfen würde.

Ich habe in MEF 2 die statische Methode CompositionContextExtensions.SatisfyImports, finden, aber ich weiß nicht, was mit ihm zu tun. Die Dokumentation sagt nur, "Erfüllt die Importe des angegebenen Objekts aus dem angegebenen Kontext." (Nicht wirklich nützlich ...)

+0

Sie erstellen Ansichtsmodelle für Ihre Benutzersteuerelemente? Die UI-Logik des Benutzersteuerelements einkapseln und aus dem Codebehind entfernen? Wenn ja, tu das nicht. Sie brechen, wie Databinding mit Steuerelementen funktionieren soll. Denken Sie darüber nach - hat eine TextBox ein TextBoxViewModel? Nein, seine Logik ist in der Kontrolle. Hat ein Grid ein GridViewModel? Nee. Das Gleiche gilt dafür.UserControls sollte DependencyProperties auf ihrer Oberfläche anzeigen, an die Sie binden, was auch immer sie benötigen, * oder * so entworfen werden, dass sie an das gebunden werden, was Sie in ihren DataContexts platzieren. (z. B. Personenmodell in PersonEditorUserControl) – Will

+0

Ich verwende Tonnen von DependencyProperties auf meinen Benutzersteuerelementen und versuche wirklich, hervorragende MVVM-Muster zu haben. In diesem speziellen Fall ist das ViewModel des Fensters vollständig leer und stattdessen habe ich sehr gezielte ViewModels für jedes Steuerelement instanziiert. Das Anzeigen von 10 Fingerabdrücken mit Anmerkungen und Kästchen um jeweils ein Fenster mit nur einem ViewModel war äußerst ineffizient und widersprach den SOLID-Prinzipien sehr. –

Antwort

1

Wir verwenden eine Klasse Wrapper für Mef mit statischen Methoden für alle apps:

public class Mef 
{ 
    private static CompositionContainer container = null; 
    public static CompositionContainer Container { get { return container; } } 

    private static AggregateCatalog catalog; 

    public static void Initialize() 
    { 
     catalog = new AggregateCatalog(); 
     catalog.Catalogs.Add(new DirectoryCatalog(path: ".", searchPattern: "*.exe")); 
     catalog.Catalogs.Add(new DirectoryCatalog(path: ".", searchPattern: "*.dll")); 
     container = new CompositionContainer(catalog); 
     StartWatch(); 
    } 

    private static void StartWatch() 
    { 
     var watcher = new FileSystemWatcher() { Path = ".", NotifyFilter = NotifyFilters.LastWrite }; 
     watcher.Changed += (s, e) => 
     { 
      string lName = e.Name.ToLower(); 
      if (lName.EndsWith(".dll") || lName.EndsWith(".exe")) 
       Refresh(); 
     }; 
     watcher.EnableRaisingEvents = true; 
    } 

    public static void Refresh() 
    { 
     foreach (DirectoryCatalog dCatalog in catalog.Catalogs) 
      dCatalog.Refresh(); 
    } 
} 

(Hinweis: Wir verwenden die oben dynamisch Plugins laden On-Demand in unserem Vielleicht möchten Sie ein anderes Katalogsystem verwenden - mehrere zur Auswahl.

Dann initialisieren wir die Klasse früh im App-Lebenszyklus, normalerweise im App.Xaml Code-Behind-Konstruktor :

public App() 
    { 
     this.InitializeComponent(); 
     Mef.Initialize(); 
    } 

und wenn ich eine Basisebene mef-Import haben, in der Klasse/code-behind Konstruktoraufruf:

Mef.Container.SatisfyImports(this); 

Hoffnung, das hilft.

+0

Obwohl ich keine dynamischen Updates benötige, mag ich in diesem Fall, was Sie damit gemacht haben. Ich mache die SatisfyImports (this) wie ich brauche und die Dinge werden viel besser laufen! Danke für die Eingabe, sehr geschätzt! –