Exemplo # 1: Tenho uma visualização exibida no meu aplicativo MVVM (vamos usar o Silverlight para os fins da discussão) e clico em um botão que deve me levar a uma nova página.
Exemplo 2: Essa mesma visualização possui outro botão que, quando clicado, deve abrir uma visualização de detalhes em uma janela filho (caixa de diálogo).
Sabemos que haverá objetos de comando expostos pelo nosso ViewModel vinculados aos botões com métodos que respondem ao clique do usuário. Mas o que então? Como concluímos a ação? Mesmo se usarmos o chamado NavigationService, o que estamos dizendo?
Para ser mais específico, em um modelo tradicional de exibição primeiro (como esquemas de navegação baseados em URL, como na web ou na estrutura de navegação interna do SL), os objetos de comando precisariam saber qual exibição exibir a seguir. Isso parece ultrapassar os limites quando se trata da separação de preocupações promovidas pelo padrão.
Por outro lado, se o botão não fosse conectado a um objeto Command e se comportasse como um hiperlink, as regras de navegação poderiam ser definidas na marcação. Mas queremos que os modos de exibição controlem o fluxo de aplicativos e a navegação não é apenas outro tipo de lógica de negócios? (Posso dizer sim em alguns casos e não em outros.)
Para mim, a implementação utópica do padrão MVVM (e já ouvi outras pessoas afirmarem isso) seria ter o ViewModel conectado de forma que o aplicativo possa ser executado sem cabeça (ou seja, sem exibições). Isso fornece a maior área de superfície para testes baseados em código e torna o Views uma aparência verdadeira no aplicativo. E meu ViewModel não deve se importar se for exibido na janela principal, em um painel flutuante ou em uma janela filho, deveria?
De acordo com essa abordagem, depende de algum outro mecanismo em tempo de execução "vincular" o que o View deve ser exibido para cada ViewModel. Mas e se quisermos compartilhar uma View com vários ViewModels ou vice-versa?
Portanto, dada a necessidade de gerenciar o relacionamento View-ViewModel para que saibamos o que exibir quando juntamente com a necessidade de navegar entre as visualizações, incluindo a exibição de janelas / caixas de diálogo filho, como podemos realmente fazer isso no padrão MVVM?
fonte
DataTemplateSelector
, que é o que eu costumo usar para aplicativos Silverlight. 2) Eu já usei isso em muitas situações antes. Por exemplo, um ViewModel pode ter várias Views ou uma View pode ser associada a múltiplos ViewModels. Para um exemplo do primeiro, consulte rachel53461.wordpress.com/2011/05/28/… . Para o posterior, você só precisa especificar que vários ViewModels mapeiam para a mesma exibição no seu DataTemplateSelector.CurrentPages
4) Mais uma vez, esse era apenas um exemplo básico. Na realidade, meus PageViewModels são todos baseados em alguma classe base, portanto meu ShellViewModel funciona apenas com a classe ou interface base, comoIPageViewModel
. Realmente, a maior parte confusa do mapeamento é o DataTemplateSelector, que precisaria mapear 40 Views para 40 ViewModels.Para encerrar, pensei em publicar a direção que finalmente escolhi para resolver esse problema.
A primeira decisão foi alavancar a estrutura do Silverlight Page Navigation fornecida imediatamente. Essa decisão foi baseada em vários fatores, incluindo o conhecimento de que esse tipo de navegação está sendo transportado pela Microsoft para os aplicativos Windows 8 Metro e é consistente com a navegação nos aplicativos Phone 7.
Para fazê-lo funcionar, examinei o trabalho que o ASP.NET MVC fez com a navegação baseada em convenções. O controle Frame usa URIs para localizar a 'página' a ser exibida. A semelhança proporcionou uma oportunidade de usar uma abordagem semelhante baseada em convenções no aplicativo Silverlight. O truque era fazer com que tudo funcionasse juntos de uma maneira MVVM.
A solução é o NavigationService. Este serviço expõe vários métodos, como NavigateTo e Back, que o ViewModels pode usar para iniciar uma alteração de página. Quando uma nova página é solicitada, o NavigationService envia um CurrentPageChangedMessage usando o recurso MVVMLight Messenger.
A exibição que contém o controle Frame possui seu próprio ViewModel definido como o DataContext que está atendendo a esta mensagem. Quando recebido, o nome da nova visualização é colocado através de uma função de mapeamento que aplica nossas regras de convenções e é definida como a propriedade CurrentPage. A propriedade Source do controle Frame está vinculada à propriedade CurrentPage. Como resultado, a configuração da propriedade atualiza a Origem e aciona a navegação.
Voltando ao NavigationService. O método NavigateTo aceita o nome da página de destino. Para garantir que os ViewModels não tenham preocupações com a interface do usuário, o nome usado é o nome do ViewModel a ser exibido. Na verdade, criei uma enumeração que possui um campo para cada ViewModel navegável como auxiliar e para eliminar seqüências de caracteres mágicas em todo o aplicativo. A função de mapeamento que mencionei acima removerá o sufixo "ViewModel" do nome, anexará "Página" ao nome e definirá o nome completo como "Exibições {Nome} Page.xaml".
Assim, por exemplo, para navegar para a exibição de detalhes do cliente, posso ligar para:
O valor de CustomerDetails é "CustomerDetailsViewModel", que é mapeado para "Views \ CustomerDetailsPage.xaml".
A vantagem dessa abordagem é que a interface do usuário é completamente dissociada dos modelos de exibição, mas temos suporte completo à navegação. Agora posso refazer meu aplicativo, no entanto e sempre que achar necessário, sem alterações no código.
Espero que a explicação ajude.
fonte
Semelhante ao que Rachel disse, meu aplicativo principalmente MVVM tem
Presenter
que lidar com alternâncias entre janelas ou páginas. Rachel chama isso deApplicationViewModel
, mas, na minha experiência, geralmente tem que fazer mais do que apenas ser um destino obrigatório (como receber mensagens, criar Windows etc.), para que seja tecnicamente mais parecido com umPresenter
ou tradicionalController
.No meu aplicativo, meu
Presenter
início com aCurrentViewModel
. OPresenter
intercepta toda a comunicação entre oView
e oViewModel
. Uma das coisas que oViewModel
pode fazer durante uma interação é retornar um novoViewModel
, o que significa que uma nova página ou um novoWindow
deve ser exibido. ElePresenter
cuida da criação ou substituiçãoView
do novoViewModel
e da configuração do novoDataContext
.O resultado de uma ação também pode ser que a
ViewModel
esteja "completa"; nesse caso, oPresenter
detecta e fecha a janela ou aViewModel
retira da pilha da VM e volta a exibir a página anterior.fonte
Presenter
apenas cola o retornadoViewModel
na árvore visual e o WPF pega o apropriadoView
, conecta oDataContext
e coloca na árvore visual. Você pode fazer isso usandoDataTemplate
s que declaram qualViewModel
tipo eles processam ou pode criar um seletor de modelo de dados personalizado. Isso ainda está dentro do domínio dos recursos do WPF.