André Carlucci

Skeptic .net development

MVVM – Model – View – ViewModel

Hoje comecei a desenvolver um novo jogo para o Windows 8 e o Windows Phone. Como quero abranger as duas plataformas e reaproveitar o máximo de código possível, vou usar o padrão MVVM junto com portable libraries para atingir este objetivo.

Antes de começar, queria falar um pouco sobre o MVVM. MVVM vem de “Model-View-ViewModel” e nada mais é do que uma adaptação do padrão “Presentation Model” do Martin Fowler feita pelo John Gossman para separação de responsabilidades entre camadas de aplicações utilizando XAML como representação de interface visual.

Já que estamos falando de XAML, você pode usar este padrão em qualquer aplicação WPF, Silverlight, Windows Phone 7, 8 e Windows 8 da mesma forma.

A famosa trindade do MVVM

View

A View é a interface visual, é o que usuário vê. No nosso caso, é o arquivo .xaml. Sendo assim, a View não deve ter nenhuma outra responsabilidade ou qualquer regra de negócio.

Model

O Model é onde está sua lógica de negócio. Cálculos, acesso a dados, etc.

ViewModel

O ViewModel é um objeto preparado especificamente para conter todas as informações que a View precisa. Estas informações são atualizadas via “DataBinding” e uma interface específica chamada INotifyPropertyChanged. Vamos falar mais sobre ela adiante.

Passando informações

Data Binding

Cada View deve estar sempre associada a um ViewModel através de uma propriedade chamada “DataContext”. Quando essa associação acontece, a View busca dele todas as propriedades definidas em “Bindings” no XAML.

[xml]
<TextBlock Text=”{Binding Title}” />
[/xml]

Por exemplo, no xaml acima, a View irá procurar uma propriedade pública chamada Title no objeto associado em seu DataContext e setar seu valor na propriedade Text do controle TextBlock com o valor retornado.

INotifyPropertyChanged

Até agora vimos como uma View carrega seus dados quando seu DataContext é associado, mas e se uma propriedade de um ViewModel muda depois disso e a View precisa ser atualizada? Como ela fica sabendo que deve atualizar aquele valor?

Para isso, existe uma interface chamada INotifyPropertyChanged.

Todo ViewModel que deseja notificar a View que alguma propriedade mudou deve implementar esta interface. Ela expõe um único evento chamado PropertyChanged, que deve ser invocado com o nome da propriedade em questão a cada alteração. A View vai estar sempre escutando por este evento e vai se atualizar automaticamente com o novo valor.

Comandos

Já sabemos como o ViewModel atualiza a View com novos valores, mas e quando a View quer passar uma mensagem para o Model? Um exemplo seria o usuário apertar algum botão onde alguma ação deva ser tomada.

Uma maneira de fazer isso é utilizando comandos. Comandos são ações de usuário que são implementadas em uma classe específica que deve implementar a interface ICommand, apresentada abaixo:

Ao implementar seu comando, você coloca na propriedade CanExecute se o comando pode ser executado no momento (por exemplo, o usuário só pode salvar o formulário se todos os campos obrigatórios estão preenchidos). Quando essa condição muda, você pode avisar a interface de usuário invocando o evento CanExecuteChanged.

A ação propriamente dita do comando é implementada no método Execute. Muitos controles do XAML já possuem bindings específicos para comandos e este método será chamado assim que o usuário realizar a ação padrão do mesmo.

[xml]
<Button Command=”{Binding SalvarCommand}” Content=”Salvar” />
[/xml]

Para associar um comando a um controle, você cria uma propriedade pública em seu ViewModel que expõe esse commando para a View e faz um binding normalmente como visto acima.

Após a execução de um comando, as propriedades do ViewModel que por ventura tenham sido alteradas avisam a View para que esta se atualize via o evento PropertyChanged normalmente.

Vantagens e Desvantagens

O MVVM traz de cara todas as vantagens que separar bem uma aplicação em camadas traz. Temos uma ótima abstração da View e raramente vamos precisar usar o code-behind. Não usando code-behind temos uma aplicação bem mais testável, visto que os ViewModels são classes como outras qualquer e podemos facilmente escrever testes de unidade para elas.

Isso por si só já justifica seu uso, mas claro que tudo depende do seu contexto. Para uma aplicação com pouquíssima complexidade, talvez a quantidade de código a mais que você vai ter que escrever possa diminuir sua produtividade.

Outra coisa importante é que usando ViewModels como fonte de dados para View fica bem mais fácil de um desenvolvedor trabalhar em conjunto com um designer. Você pode criar um ViewModel que é usado apenas em tempo de design (populando a View com dados “fake”) e outro para quando estamos em execução.

Enfim…

Bom, essa é a teoria. A ideia do MVVM é simples e bem curta. Todo o resto são helpers para conseguirmos colocar isso em prática. Você vai encontrar por aí todo tipo de purismo como “ViewModels não devem ter métodos”, “Deve haver zero linhas de códigos no code-behind sempre” e outros. Apesar de boas metas, siga-as apenas até onde elas te trazem benefícios.

  • Excelente artigo!

  • Anon

    Muito bom artigo. Fiquei com uma duvida, vamos supor que tenha uma aplicacao com um controle de navegacao, imagine seta para esquerda e seta para a direita. Quando essas setas sao clicadas, o Grid da aplicacao deve atualizar com novas informacoes. Nesse caso, entendo que existiria uma view/viewmodel para o controle de navegacao e uma view/viewmodel para o Grid (considerando que quero usa-los em outros contextos, entao sao empacotados de forma separada, como controles). Minha pergunta e’: como o controle de navegacao (seta para esquerda e seta para a direita) mandaria a notificacao de evento para o controle de conteudo (Grid)? Em outras palavras como um view/viewmodel se comunica com outro view/viewmodel? Abs!

    • Anonymous

      Olá Anon,

      Eu faço a comunicação entre viewmodels sempre de maneira desacoplada. Dê uma olhada no Messenger do MVVMLight que vai te ajudar bastante. https://mvvmlight.codeplex.com/

      []’s!

  • Rodrigo

    E a desvantagem é ficar suas entidades/regra negócio visiveis, já que é javascript

    Estou certo ou não? rs :)

    • andrecarlucci

      Oi Rodrigo, neste caso estamos falando de Xaml e não Javascript, mas o modelo se aplica em ambos sem problemas.
      Só não entendi como isso faria suas regras de negócio visíveis, pode explicar?

  • Erich

    Ótimo artigo! Ajudou bastante no esclarecimento do conceito.

    • andrecarlucci

      Obrigado!