Introdução
No MVVM, a prática usual é fazer com que as Views encontrem seus ViewModels resolvendo-os a partir de um contêiner de injeção de dependência (DI). Isso acontece automaticamente quando o contêiner é solicitado a fornecer (resolver) uma instância da classe View. O contêiner injeta ViewModel em View chamando um construtor de View que aceita um parâmetro ViewModel; este esquema é denominado inversão de controle (IoC).
Benefícios do DI
O principal benefício aqui é que o contêiner pode ser configurado em tempo de execução com instruções sobre como resolver os tipos que solicitamos dele. Isso permite maior testabilidade, instruindo-o a resolver os tipos (Views e ViewModels) que usamos quando nosso aplicativo realmente é executado, mas instruindo-o de forma diferente ao executar os testes de unidade para o aplicativo. No último caso, o aplicativo nem mesmo terá uma IU (não está em execução; apenas os testes estão), portanto, o contêiner resolverá simulações no lugar dos tipos "normais" usados quando o aplicativo é executado.
Problemas decorrentes de DI
Até agora, vimos que a abordagem de DI permite fácil testabilidade para o aplicativo, adicionando uma camada de abstração sobre a criação de componentes do aplicativo. Há um problema com essa abordagem: ela não funciona bem com designers visuais como o Microsoft Expression Blend.
O problema é que, tanto na execução normal do aplicativo quanto na execução do teste de unidade, alguém precisa configurar o contêiner com instruções sobre quais tipos resolver; além disso, alguém tem que pedir ao contêiner para resolver as visualizações para que os ViewModels possam ser injetados nelas.
No entanto, em tempo de design não há nenhum código nosso rodando . O designer tenta usar reflexão para criar instâncias de nossas visualizações, o que significa que:
- Se o construtor de View requer uma instância de ViewModel, o designer não será capaz de instanciar a View - ocorrerá um erro de alguma maneira controlada
- Se a View tem um construtor sem parâmetros, a View será instanciada, mas assim
DataContext
será null
, teremos uma view "vazia" no designer - o que não é muito útil
Insira ViewModelLocator
O ViewModelLocator é uma abstração adicional usada assim:
- O próprio View instancia um ViewModelLocator como parte de seus recursos e vincula seu DataContext à propriedade ViewModel do localizador
- O localizador de alguma forma detecta se estamos no modo de design
- Se não estiver no modo de design, o localizador retorna um ViewModel que ele resolve do contêiner DI, conforme explicado acima
- Se estiver no modo de design, o localizador retorna um ViewModel "fictício" fixo usando sua própria lógica (lembre-se: não há contêiner em tempo de design!); este ViewModel normalmente vem pré-preenchido com dados fictícios
Claro, isso significa que a View deve ter um construtor sem parâmetros para começar (caso contrário, o designer não será capaz de instanciá-lo).
Resumo
ViewModelLocator é um idioma que permite manter os benefícios do DI em seu aplicativo MVVM enquanto também permite que seu código funcione bem com designers visuais. Isso às vezes é chamado de "capacidade de mesclagem" de seu aplicativo (referindo-se ao Expression Blend).
Depois de digerir o acima, veja um exemplo prático aqui .
Finalmente, usar modelos de dados não é uma alternativa ao uso de ViewModelLocator, mas uma alternativa ao uso de pares View / ViewModel explícitos para partes de sua IU. Freqüentemente, você pode descobrir que não há necessidade de definir um View para um ViewModel porque você pode usar um modelo de dados em seu lugar.
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
. O propósito do Locator é realmente habilitar DI nas Views, porque WPF é muito ruim em fornecê-lo. Exemplo: você tem uma janela principal que abre uma janela de diálogo. Para resolver a DI na janela de diálogo da maneira usual, você precisa passá-la como uma dependência da janela principal! Isso é evitado com o View Locator.Um exemplo de implementação da resposta de @Jon
Eu tenho uma classe de localizador de modelo de exibição. Cada propriedade será uma instância do modelo de visão que alocarei em minha visão. Posso verificar se o código está rodando em modo de design ou não usando
DesignerProperties.GetIsInDesignMode
. Isso me permite usar um modelo de simulação durante o tempo de design e o objeto real quando estou executando o aplicativo.E para usá-lo, posso adicionar meu localizador aos
App.xaml
recursos:E, em seguida, para conectar sua visualização (ex: MainView.xaml) ao seu modelo de visualização:
fonte
this
vez dedummy
?Não entendo por que as outras respostas desta pergunta envolvem o Designer.
O objetivo do View Model Locator é permitir que seu View instancie isso (sim, View Model Locator = View First):
em vez de apenas isso:
declarando isto:
Onde
ViewModelLocator
está a classe, que faz referência a um IoC e é assim que resolve aMainWindowModel
propriedade que expõe.Não tem nada a ver com fornecer modelos de visualização Mock para sua visualização. Se você quiser isso, basta fazer
O View Model Locator é um invólucro em torno de algum (qualquer) container Inversion of Control, como o Unity, por exemplo.
Referir-se:
fonte