115 votes

Qu'est-ce qu'un ViewModelLocator et quels sont ses avantages et inconvénients par rapport aux DataTemplates ?

Quelqu'un peut-il me donner un résumé rapide de ce qu'est un ViewModelLocator, comment il fonctionne, et quels sont les avantages et les inconvénients de son utilisation par rapport aux DataTemplates ?

J'ai essayé de trouver des informations sur Google, mais il semble qu'il y ait beaucoup d'implémentations différentes de ce système et aucune liste précise de ce qu'il est et des avantages et inconvénients de son utilisation.

213voto

Jon Points 194296

Intro

En MVVM, la pratique habituelle consiste à faire en sorte que les vues trouvent leurs ViewModels en les résolvant à partir d'un fichier de type injection de dépendances (DI). Cela se produit automatiquement lorsqu'il est demandé au conteneur de fournir (résoudre) une instance de la classe View. Le conteneur injecte le ViewModel dans la vue en appelant un constructeur de la vue qui accepte un paramètre ViewModel ; ce schéma est appelé inversion du contrôle (IoC).

Avantages de l'AI

L'avantage principal ici est que le conteneur peut être configuré au moment de l'exécution avec des instructions sur la façon de résoudre les types que nous lui demandons. Cela permet une meilleure testabilité en lui demandant de résoudre les types (Views et ViewModels) que nous utilisons lorsque notre application s'exécute réellement, mais en lui donnant des instructions différentes lors de l'exécution des tests unitaires de l'application. Dans ce dernier cas, l'application n'aura même pas d'interface utilisateur (elle n'est pas en cours d'exécution, seuls les tests le sont). mocks à la place des types "normaux" utilisés lors de l'exécution de l'application.

Problèmes découlant du DI

Jusqu'à présent, nous avons vu que l'approche DI permet une testabilité facile de l'application en ajoutant une couche d'abstraction sur la création des composants de l'application. Il y a un problème avec cette approche : il ne joue pas bien avec les concepteurs visuels comme Microsoft Expression Blend.

Le problème est que, tant dans les applications normales que dans les tests unitaires, quelqu'un doit mettre en place le conteneur avec des instructions sur les types à résoudre ; en outre, quelqu'un doit demandez à le conteneur pour résoudre les vues afin que les ViewModels puissent être injectés dans celles-ci.

Cependant, dans le temps de conception, il n'y a pas de code à nous qui fonctionne. . Le concepteur tente d'utiliser la réflexion pour créer des instances de nos vues, ce qui signifie que :

  • Si le constructeur de la vue nécessite une instance de ViewModel, le concepteur ne sera pas en mesure d'instancier la vue du tout - il se trompera d'une manière contrôlée.
  • Si la vue possède un constructeur sans paramètre, la vue sera instanciée, mais sa fonction DataContext sera null donc nous aurons une vue "vide" dans le concepteur, ce qui n'est pas très utile.

Entrer ViewModelLocator

Le ViewModelLocator est une abstraction supplémentaire utilisée comme ceci :

  • La vue elle-même instancie un ViewModelLocator en tant que partie de son ressources et lie son DataContext à la propriété ViewModel du localisateur
  • Le localisateur en quelque sorte détecte si nous sommes en mode conception
  • S'il n'est pas en mode conception, le localisateur renvoie un ViewModel qu'il résout à partir du conteneur DI, comme expliqué ci-dessus.
  • En mode conception, le localisateur renvoie un ViewModel fixe "factice" utilisant sa propre logique (n'oubliez pas qu'il n'y a pas de conteneur au moment de la conception) ; ce ViewModel est généralement fourni avec des données factices.

Bien sûr, cela signifie que la vue doit avoir un constructeur sans paramètre pour commencer (sinon le concepteur ne sera pas en mesure de l'instancier).

Résumé

ViewModelLocator est un idiome qui vous permet de conserver les avantages de la DI dans votre application MVVM tout en permettant à votre code d'être compatible avec les concepteurs visuels. Ceci est parfois appelé la "blendabilité" de votre application (en référence à Expression Blend).

Après avoir digéré ce qui précède, voyez un exemple pratique ici .

Enfin, l'utilisation de modèles de données n'est pas une alternative à l'utilisation de ViewModelLocator, mais une alternative à l'utilisation de paires View/ViewModel explicites pour certaines parties de votre IU. Souvent, vous constaterez qu'il n'est pas nécessaire de définir une vue pour un ViewModel car vous pouvez utiliser un modèle de données à la place.

4 votes

+1 pour une excellente explication. Pouvez-vous nous en dire plus sur la vue et ses ressources ? Par ressources, voulez-vous dire les propriétés de la vue ? Ou bien ? Avez-vous un lien avec un exemple concret de ce modèle ?

0 votes

@MetroSmurf : Votre lien est dans la section Résumé.

1 votes

Merci. Y a-t-il des limites à l'utilisation d'un ViewModelLocator ? J'avais quelques inquiétudes sur le fait qu'il faisait référence à une ressource statique - les ViewModels peuvent-ils être créés dynamiquement au moment de l'exécution ? Et est-ce qu'il y a beaucoup de code supplémentaire pour en connecter un ?

10voto

BrunoLM Points 26573

Un exemple de mise en œuvre de Réponse de @Jon

J'ai une classe de localisateur de modèle de vue. Chaque propriété va être une instance du modèle de vue que je vais allouer sur ma vue. Je peux vérifier si le code s'exécute en mode conception ou non en utilisant DesignerProperties.GetIsInDesignMode . Cela me permet d'utiliser un modèle fictif pendant la conception et l'objet réel lorsque j'exécute l'application.

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

Et pour l'utiliser, je peux ajouter mon localisateur à App.xaml ressources :

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

Et ensuite pour relier votre vue (ex : MainView.xaml) à votre modèle de vue :

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">

8voto

Hristo Yankov Points 721

Je ne comprends pas pourquoi les autres réponses de cette question tournent autour du Designer.

Le but du View Model Locator est de permettre à votre View de l'instancier (oui, View Model Locator = View First) :

public void MyWindowViewModel(IService someService)
{
}

au lieu de juste ça :

public void MyWindowViewModel()
{
}

en déclarant ceci :

DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"

ViewModelLocator est une classe, qui fait référence à un IoC, et c'est ainsi qu'elle résout le problème de l'IoC. MainWindowModel qu'il expose.

Cela n'a rien à voir avec le fait de fournir des modèles de vue Mock à votre vue. Si vous voulez cela, faites simplement

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

Le View Model Locator est une enveloppe autour d'un conteneur d'inversion de contrôle (n'importe lequel), comme Unity par exemple.

Se référer à :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X