Qu'est-ce qu'un ViewModelLocator et quels en sont les avantages et les inconvénients par rapport à Dataemplates?

est-ce que quelqu'un peut me donner un résumé rapide de ce qu'est un ViewModelLocator, comment il fonctionne, et quels sont les avantages/inconvénients de l'utiliser par rapport à Dataemplates?

j'ai essayé de trouver des informations sur Google mais il semble y avoir de nombreuses implémentations différentes de celui-ci et aucune liste striaght quant à ce qu'il est et les avantages/inconvénients de l'utiliser.

100
demandé sur Jon 2011-03-28 20:24:48

3 réponses

Intro

dans MVVM la pratique habituelle est d'avoir les vues trouver leurs modèles de vue en les résolvant à partir d'un injection de dépendance (DI) conteneur. Cela se produit automatiquement quand on demande 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 de la commande (IoC).

prestations D'invalidité

le principal avantage ici est que le conteneur peut être configuré au temps d'exécution avec des instructions sur la façon de résoudre les types que nous lui demandons. Cela permet une plus grande testabilité en lui donnant l'instruction de résoudre les types (vues et modèles de vues) que nous utilisons lorsque notre application fonctionne réellement, mais en lui donnant des instructions différentes lors de l'exécution des tests unitaires pour le 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 sont effectués) de sorte que le conteneur résoudra mocks à la place des types "normaux" utilisés lorsque l'application fonctionne.

problèmes découlant de la DI

jusqu'à présent, nous avons vu que l'approche DI permet une testabilité facile pour l'application en ajoutant une couche d'abstraction sur la création de composants d'application. Il y en 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 dans les deux essais d'application normaux et les essais unitaires, quelqu'un doit configurer le conteneur avec des instructions sur les types à résoudre; en outre, quelqu'un doit demander le conteneur pour résoudre les vues afin que les Modèles de vue peuvent être injectés dans eux.

cependant, dans le temps de conception, il n'y a pas de code de notre . 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 a besoin d'une instance de ViewModel, le concepteur ne pourra pas instancier la vue du tout -- il fera une erreur d'une manière contrôlée
  • si la vue a un constructeur sans paramètre la vue sera instanciée, mais son DataContext sera null donc nous aurons une vue "vide" dans le concepteur-qui n'est pas très utile

Entrez Le ViewModelLocator

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

  • la vue elle-même instancie un ViewModelLocator dans le cadre de son resources et databinds son Datacontexte à la propriété ViewModel du localisateur
  • le Localisateur d'une façon ou d'une autre détecte si nous sommes en mode de conception
  • si ce n'est pas en mode conception, le Localisateur renvoie un modèle de vue qu'il résout à partir du conteneur DI, comme expliqué ci-dessus
  • si en mode de conception, le Localisateur renvoie un "mannequin" fixe en utilisant sa propre logique (rappelez-vous: il n'y a pas de conteneur dans le temps de conception!); Ce modèle est typiquement pré-peuplé de 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 garder les avantages de DI dans votre application MVVM tout en permettant à votre code de bien jouer avec les concepteurs visuels. C'est ce qu'on appelle parfois le "blendability" de votre application (en référence à Expression Blend).

après avoir digéré ce qui précède, voir 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 de vues/modèles de vues explicites pour certaines parties de votre interface utilisateur. Souvent vous pouvez trouver qu'il n'y a pas besoin de définir une vue pour un modèle de vue parce que vous pouvez utiliser un modèle de données à la place.

175
répondu Jon 2012-11-13 14:03:22

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

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 attribuer sur ma vue. Je peux vérifier si le code fonctionne en mode de conception ou n'utilise pas DesignerProperties.GetIsInDesignMode . Cela me permet d'utiliser un modèle simulé pendant le temps de 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 de connecter votre vue (ex: MainView.xaml) à votre viewmodel:

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
7
répondu BrunoLM 2017-05-23 10:31:30

Je ne comprends pas pourquoi les autres réponses de cette question s'enroulent autour du concepteur.

le but du Localisateur de modèle de vue est de permettre à votre vue d'instancier ceci (Oui, Localisateur de modèle de vue = vue en premier):

public void MyWindowViewModel(IService someService)
{
}

au lieu de juste ceci:

public void MyWindowViewModel()
{
}

en déclarant ceci:

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

ViewModelLocator est la classe, ce qui fait référence à un CIO et c'est comme ça qu'il résout le problème. MainWindowModel biens qu'il expose.

cela n'a rien à voir avec le fait de fournir des modèles de vues simulées à votre vue. Si vous le voulez, il suffit de faire

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

le Localisateur de modèle de vue est une enveloppe autour d'une certaine (quelconque) Inversion du conteneur de contrôle, comme Unity par exemple.

se référer à:

2
répondu Hristo Yankov 2017-05-23 10:31:29