2016-05-25 1 views
-1

Je suis en train de convertir mon application WPF/MVVM de Ninject en MEF pour bénéficier d'une architecture de plugin. Il n'y a pas de Prisme ou d'Unité, et je ne veux pas non plus suivre ce chemin. J'utilise VS2015 et .Net 4.6. J'utilisais la technique qui était populaire avec MVVM Light où vous instanciez le ViewModel à l'intérieur du XAML avec Ninject.MEF: Création d'un ViewModel dans mes UserControls

public static ImageViewModel ImageVM => Kernel.Get<ImageViewModel>(); 

Mais maintenant que je passe à MEF, j'aimerais voir s'il existe des alternatives. La plupart des messages actuellement publiés sur Stack Exchange sont assez anciens et j'espère que de nouvelles alternatives sont disponibles maintenant que .NET 4.5 est disponible.


tl; dr

J'ai une fenêtre qui contient 10 UserControls. Chaque contrôle utilisateur a une nouvelle instance d'un ViewModel attaché à celui-ci. Puisque la fenêtre crée les contrôles utilisateur dans xaml, comment puis-je obtenir une instance unique de mon ViewModel dans chaque contrôle?

public partial class FingerprintControl{ 

    public FingerprintControl() { 
     InitializeComponent(); 
    } 

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

Une suggestion que j'ai vu dit ajouter

CompositionInitializer.SatisfyImports(this); 

après la InitializeComponent(). Mais c'est une classe Silverlight seulement.

J'ai regardé https://www.nuget.org/packages/Microsoft.Composition/ mais la documentation pour MEF 2 est juste incroyablement inexistante sur le site.

J'ai également vu que ExportFactory a été ajouté à MEF 2, mais je ne sais pas si cela aiderait non plus. J'ai trouvé dans MEF 2 la méthode statique CompositionContextExtensions.SatisfyImports, mais je ne sais pas quoi faire avec. La documentation dit seulement, "Satisfait les importations de l'objet spécifié du contexte spécifié." (Pas utile réel ...)

+0

Vous créez des modèles de vue pour vos contrôles utilisateur? Encapsuler la logique d'interface utilisateur du contrôle utilisateur, en l'enlevant du codebehind? Si oui, ne faites pas ça. Vous êtes en train de casser comment la liaison de données est supposée fonctionner avec les contrôles. Pensez-y: un TextBox a-t-il un TextBoxViewModel? Non, sa logique est dans le contrôle. Est-ce qu'une grille a un GridViewModel? Nan. Pareil pour ça.UserControls devrait exposer DependencyProperties sur leur surface à laquelle vous liez tout ce dont ils ont besoin, * ou * être conçu pour se lier à ce que vous placez dans leurs DataContexts. (par exemple, modèle Person dans PersonEditorUserControl) – Will

+0

J'utilise des tonnes de DependencyProperties sur mes UserControls et je m'efforce vraiment d'avoir d'excellents modèles MVVM. Dans ce cas particulier, le ViewModel de Window est complètement vide et à la place, j'ai instancié des ViewModels très ciblés sur chaque contrôle. Pour afficher 10 empreintes digitales avec des annotations et des boîtes autour de chacun sur une fenêtre en utilisant un seul ViewModel était extrêmement inefficace et très contre les principes SOLIDES. –

Répondre

1

Nous utilisons un emballage de classe pour Mef avec des méthodes statiques pour toutes nos applications:

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

(Note: Nous utilisons ci-dessus pour charger dynamiquement des plugins sur demande dans notre Ensuite, nous initialisons la classe dès le début du cycle de vie de l'application, généralement dans le constructeur App.Xaml code-behind. :

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

et quand j'ai un niveau de base MEF- importation, dans la classe/code-behind appel constructeur:

Mef.Container.SatisfyImports(this); 

Hope this helps.

+0

Bien que je n'ai pas besoin de mises à jour dynamiques, j'aime ce que vous avez fait avec dans ce cas. Je fais le SatisfyImports (ceci) comme j'ai besoin et les choses vont beaucoup mieux! Merci pour la contribution, très appréciée! –