2010-11-17 22 views
6

Je développe une application WPF en utilisant le modèle MVVM. J'utilise MVVM Light Library et j'essaie aussi d'utiliser un injecteur de dépendances (je pense à Ninject et Unity).MVVM: Communication entre le modèle et ViewModels

J'ai lu beaucoup d'articles de blog et je suis assez confus au sujet de la façon «appropriée» de faire communiquer mes classes les unes avec les autres. En particulier, je ne sais pas quand utiliser Dependency Injection et quand me fier au pattern médiateur.

Considérons un exemple. J'ai un ViewModel, appelons-le DataViewModel, et la classe Data qui fournit un certain type de données. Comment est-il préférable de communiquer entre eux:

A. Injecter une dépendance à DataViewModel avec une interface de IData? De cette façon, les données ne devront pas dépendre de Messenger, mais elles devront fournir un événement si les données changent, et le ViewModel devra s'y abonner.

B. Fiez-vous au modèle de médiateur (implémenté dans MVVM Light as Messenger) et envoyez des messages entre Model et ViewModel? De cette façon, il ne sera pas du tout nécessaire d'utiliser l'injection de dépendances, car toute la communication sera basée sur des messages.

De plus, est-ce que mes ViewModels devraient avoir injecté des dépendances sur d'autres ViewModels, ou il vaudrait mieux se fier au Messenger? Si le premier, serait-il nécessaire de définir une interface distincte pour chaque ViewModel? Je pense que la définition d'une interface pour chaque VM sera un travail supplémentaire, mais peut-être que ça en vaut la peine.

Répondre

4

Généralement, ViewModel va à un service (comme l'appelle Prism) pour récupérer les données dont il a besoin. Ce service est transmis au ViewModel via DI (Constructor Injection) bien que vous puissiez le faire d'une autre manière via un ServiceLocator.

Par conséquent, votre ViewModel contiendra une référence à un service qui permettra d'abstraire la récupération de vos données. Les données pourraient provenir d'une base de données, d'un fichier XML, qui sait ... l'abstraction est là. Donc, pour votre cas d'IData, la référence à ce type se produira à un certain moment dans le ViewModel mais pas à partir de DI. Si votre framework IoC le permet (Prism), vous créez des mappages de types d'interface avec des types concrets, puis récupérez ces types via votre conteneur; tel est le cas avec Unity.

Voici un bref exemple ... Scripts est lié à la vue et le ViewModel est injecté dans la vue. Notez l'utilisation de l'IScriptService pour récupérer les données. Les données qui reviennent sont une collection de types d'IScript, cependant nous n'avons jamais injecté ce type dans le ViewModel parce que nous ne nous soucions pas du type en tant qu'entité unique, nous nous soucions du type sur une échelle de grandeur.

 public ScriptRepositoryViewModel(IUnityContainer container, IScriptService scriptService, IEventAggregator eventAggregator) 
     { 
      _container = container; 
      _scriptService = scriptService; 
      _eventAggregator = eventAggregator; 
     } 

     public ICollectionView Scripts 
     { 
      get 
      { 
       if (_view == null) 
       { 
        _view = CollectionViewSource.GetDefaultView(_scriptService.Scripts); 
        _view.Filter = Filter; 
       } 

       return _view; 
      } 
     } 

Lorsque vous faites votre chemin à la vue, le même cas peut être fait là-bas, la vue s'injecté par DI (injection Constructor) avec le ViewModel. Je ne ferais pas dépendre les autres ViewModels les uns des autres, gardez-les isolés. Si vous commencez à voir un besoin de couplage, jetez un coup d'œil sur les données que vous essayez de partager, puis plus souvent que ces données doivent être extraites plus loin et ne pas être couplées à un ViewModel.

+0

Maintenant, je comprends ... mais j'ai eu besoin de temps pour m'habituer à l'injection de dépendance et aux services :) Merci! – madbadger

1

Il y a plus d'une bonne solution à votre problème,

Je vous suggère d'utiliser une interface unique dans vos modèles de données, le mettre dans une classe de base, cette interface permettra de communiquer vos objets de données avec le monde extérieur. Pour les modèles de vue n'injectent pas les données mais une interface qui peut récupérer des données pour vous, les données exposeront les événements que le vm peut enregistrer à eux après qu'il les obtient. Oject ne devrait pas savoir qui le détient, voir le modèle sait quel type de données il détient mais je ne recommande pas d'injecter ces données en raison de problèmes de flexibilité.