2010-10-27 18 views
10

En essayant de maîtriser l'écriture de ViewModels testables dans Silverlight 4. Je suis actuellement en train d'utiliser la lumière MVVM.Silverlight Constructor Injection dans le modèle View + Design Mode

Im utilisant AutoFac et le IoCContainer fait son travail bien. Cependant, pour injecter dans le constructeur de ViewModels, qui sont liés à ce Vues je constructeur Enchaînement:

public UserViewModel() : this(IoCContainer.Resolve<IUserServiceAsync>()) 
    { 

    } 

    public UserViewModel(IUserServiceAsync userService) 
    { 
     if (this.IsInDesignMode) return; 

     _userService = userService; 
    } 

Ce qui ne se sent pas propre, mais est la meilleure option que j'ai trouvé jusqu'à présent. Cela fonctionne et mon application fonctionne comme vous le souhaitez, et est testable avec contrôle inversé.

Cependant, avec ma VM lié à mon avis comme celui-ci:

<UserControl.DataContext> 
      <ViewModel:UserViewModel /> 
</UserControl.DataContext> 

Dans mes attributs de page XAML, le mode de conception à la fois VS2010 et Blend travail ne marche pas.

Y a-t-il une façon plus agréable de réaliser ce que j'essaie dans Silverlight qui fonctionne encore avec le mode design? Perdre le mode de conception n'est pas un briseur d'affaire, mais sera utile lors de l'apprentissage de XAML. Un nettoyeur non enchaîné serait bien quand même! Je pense qu'il est peut-être possible d'utiliser AutoFac/IoC pour résoudre les viewmodels aux vues, comme cela est associé à l'approche de balisage XAML ci-dessus, et suivre cette voie?

Merci.

Répondre

10

Au lieu de mettre en œuvre le premier constructeur, je vous suggère de mettre en œuvre un ViewModelLocator, comme ceci:

public class ViewModelLocator 
{ 

    IoCContainer Container { get; set; } 

    public IUserViewModel UserViewModel 
    { 
     get 
     { 
      return IoCContainer.Resolve<IUserViewModel>(); 
     } 
    } 

} 

Puis en XAML vous déclarez le localisateur comme une ressource statique:

<local:ViewModelLocator x:Key="ViewModelLocator"/> 

Pendant que vous initialisez votre application, il est nécessaire de fournir au localisateur l'instance du conteneur:

var viewModelLocator = Application.Current.Resources["ViewModelLocator"] as ViewModelLocator; 
if(viewModelLocator == null) { // throw exception here } 
viewModelLocator.Container = IoCContainer; 

Puis en XAML vous pouvez utiliser la ressource proprement:

<UserControl 
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}" 
    /> 
    <!-- The other user control properties --> 

Pour le temps de conception, vous pouvez mettre en œuvre un MockViewModelLocator:

public class MockViewModelLocator 
{ 

    public IUserViewModel UserViewModel 
    { 
     get 
     { 
      return new MockUserViewModel(); 
     } 
    } 

} 

Déclare en XAML correctement:

<local:MockViewModelLocator x:Key="MockViewModelLocator"/> 

Et enfin l'utiliser dans votre contrôle d'utilisateur:

<UserControl 
    d:DataContext="{Binding Path=UserViewModel, Source={StaticResource MockViewModelLocator}}" 
    DataContext="{Binding Path=UserViewModel, Source={StaticResource ViewModelLocator}}" 
    /> 
    <!-- The other user control properties --> 

Vous pouvez faire en sorte que votre localisateur de modèle de vue simulée retourne des données sécurisées et facilement lisibles que Blend utilisera et pendant l'exécution, vous utiliserez votre vrai service. De cette façon, vous ne perdez pas les données de temps de conception et vous n'avez pas à sacrifier la propreté de la méthodologie d'injection de dépendance dans vos modèles de vue.

J'espère que cela aide.

+0

Merci pour la réponse détaillée! – Jammin