2010-01-15 10 views
5

J'ai rencontré deux façons d'initialiser Views et ViewModels dans WPF CAL MVVM.Quelle est la façon correcte d'initialiser un modèle et une vue dans WPF CAL MVVM

1 - Semble être plus populaire. Vous devez résoudre le ViewModel pour résoudre automatiquement la vue. Le ViewModel contient des informations sur la vue.

public interface IView 
    { 
     void SetModel(IViewModel model); 
    } 

    public interface IViewModel 
    { 
     IView View { get; } 
    } 

    public class View 
    { 
     public void SetModel(IViewModel model) 
     { 
      this.DataContext = model; 
     } 
    } 

    public class ViewModel 
    { 
     private IView view; 

     public ViewModel(IView view) 
     { 
      this.view = view; 
     } 

     public IView View { return this.view; } 
    } 

2 - Semble beaucoup plus propre et supprime la vue du ViewModel. Vous oblige à résoudre la vue pour résoudre automatiquement le ViewModel. Injecte des objets dans la vue (Je ne sais pas si c'est bon ou non). Quelle est la méthode acceptée pour initialiser les vues et les modèles et quels sont les avantages et les inconvénients de chaque méthode. Devriez-vous injecter des objets dans votre vue?

Répondre

3

Ils sont valides, mais # 1 a tendance à être plus testable (au moins fait votre tests plus concis). L'avantage du # 2 est qu'il a tendance à être plus explicite et à rendre la maintenance un peu plus claire, surtout quand vous avez beaucoup de roulement, ce genre de choses. Prend moins d'explications (bien que ce ne soit pas une raison pour l'adopter, c'est juste un truisme).

La différence est que # 1 est appelée injection de dépendances et # 2 est appelé Service Lieu. Ils sont souvent confus car ils utilisent tous les deux une sorte de conteneur IoC (bien que cela ne soit pas forcément le cas). C'est une question de préférence à la fin, mais comme je l'ai dit je pense que vous trouverez # 1 beaucoup plus facile à tester ... vous n'aurez pas à impliquer l'interface IUnityContainer dans vos tests/moqueurs.

1

L'option 1 ressemble à peu près à droite, donne à la vue une référence au modèle de vue. Avoir viewmodels avec une référence à la vue semble un peu louche pour moi cependant. Cela ressemble plus à une architecture de type model-view-presenter. Si vous avez des viewmodels qui interagissent fortement avec la vue et ont besoin d'une référence à la vue pour cela, vous feriez mieux de scinder le viewmodel dans un viewmodel utilisé uniquement pour la liaison de données et un présentateur qui fait des interactions plus complexes.

L'option 2 ne semble pas correcte. Passer une référence au conteneur ioc dans les classes est une grosse odeur de code dans mon livre. Les appels vers un conteneur IoC doivent être minimisés. Dans la plupart de mes applications, j'appelle seulement dans le conteneur au début du programme pour câbler des choses. La création d'objets plus dynamiques est généralement effectuée avec des classes d'usine.

+0

La propriété View en option 1 a été trouvé par moi dans divers exemples mais je suis d'accord qu'il ne devrait pas être là. – anon

2

Je préfère définir le modèle de vue en XAML et fournir une propriété en lecture seule pour l'accès dactylographiée:

<UserControl ...> 
    <UserControl.DataContext> 
     <local:MyViewModel/> 
    </UserControl.DataContext> 

    ... 

</UserControl> 

public partial class MyView : UserControl, IMyView 
{ 
    public MyViewModel ViewModel 
    { 
     get { return this.DataContext as MyViewModel; } 
    } 

    ... 
} 
+0

+1 pour la propriété en lecture seule –

1

Le problème avec ce code est que l'option 2 est en train de cuire plus que nécessaire. Il n'a vraiment pas besoin et ne devrait pas avoir une référence au conteneur.

Une alternative permet à l'option 2 d'être aussi testable que l'option 1, mais conceptuellement plus claire dans la mesure où le ViewModel ne connaît jamais la vue. Ceci est particulièrement utile si vous voulez spécifier votre mise en page en utilisant un fichier xml plutôt que d'utiliser les régions de prisme, ce qui vous permet de configurer facilement la mise en page.

Alternative:

public interface IView 
{ 
} 

public interface IViewModel 
{ 
} 

public class View : IView 
{ 
    private IViewModel model; 

    public View(IViewModel m) 
    { 
     this.model = m; 
     this.DataContext = this.model; 
    } 
} 

public class ViewModel : IViewModel 
{ 
} 

et un autre endroit que vous avez:

Container.RegisterType<IViewModel, ViewModel>(/* appropriate container config */); 
Container.RegisterType<IView, View>(/* appropriate container config */); 

et vous pouvez créer une vue partout avec:

Container.Resolve<IViewModel>(); 
+0

+1 pour noter la résolution de type n'est pas le travail de la vue. J'utilise aussi cette approche et je l'adore. – RMart