Módulo 6 · Aplicações Desktop — Capítulo 02

Padrão MVVM

O "MVC das aplicações desktop": como separar a tela (View) da lógica que a alimenta (ViewModel), conectadas por data binding em vez de chamadas diretas de método.

1. As três peças do MVVM

PeçaResponsabilidadeEquivalente no Módulo 3 (MVC)
ModelDados e regra de negócioModel (idêntico)
ViewXAML — só estrutura visual, sem lógicaView (Razor)
ViewModelEstado da tela + comandos, conectado à View via data bindingController + ViewModel (Módulo 3, capítulo 4), fundidos numa única peça

A diferença estrutural mais importante em relação ao MVC: a View nunca chama o ViewModel diretamente (sem BotaoSalvar_Click no code-behind) — a conexão acontece via data binding, aprofundado no próximo capítulo. O ViewModel nem sabe que uma View existe.

View (XAML) só estrutura visual Data Binding ViewModel estado + comandos Model / Repository

Fig. 1 — A View nunca conhece o Model diretamente; a comunicação View↔ViewModel é sempre via data binding, nunca chamada de método direta.

2. INotifyPropertyChanged — como o ViewModel "avisa" a View

Para a View atualizar automaticamente quando um dado do ViewModel muda, o ViewModel implementa INotifyPropertyChanged — o mecanismo de notificação que sustenta todo data binding no WPF:

C# ViewModelBase.cs — reaproveitável em todo ViewModel
public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string? nomePropriedade = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nomePropriedade));

    protected bool DefinirCampo<T>(ref T campo, T valor, [CallerMemberName] string? nomePropriedade = null)
    {
        if (EqualityComparer<T>.Default.Equals(campo, valor)) return false;
        campo = valor;
        OnPropertyChanged(nomePropriedade);
        return true;
    }
}
Conectando com o Módulo 1

Isso é o evento (event, capítulo 11 do Módulo 1) aplicado a um caso de uso concreto: toda vez que uma propriedade muda, o ViewModel dispara PropertyChanged, e o WPF (que está "assinando" esse evento por trás do data binding) atualiza a tela automaticamente. [CallerMemberName] captura o nome da propriedade chamadora automaticamente, sem precisar digitá-lo manualmente toda vez.

3. Um ViewModel completo

C# ClienteCadastroViewModel.cs
public class ClienteCadastroViewModel : ViewModelBase
{
    private string _nome = string.Empty;
    public string Nome
    {
        get => _nome;
        set => DefinirCampo(ref _nome, value);
    }

    private string _email = string.Empty;
    public string Email
    {
        get => _email;
        set => DefinirCampo(ref _email, value);
    }

    private string _mensagem = string.Empty;
    public string Mensagem
    {
        get => _mensagem;
        set => DefinirCampo(ref _mensagem, value);
    }
}

Repare a semelhança com o ClienteCadastroViewModel do Módulo 3 (capítulo 4) — o conceito de "modelo feito sob medida para uma tela" é o mesmo; só a mecânica de notificação de mudança (DefinirCampo) é específica do desktop, porque aqui não existe um ciclo de requisição/resposta reiniciando o estado a cada interação.

4. Onde isso te leva

Com a estrutura MVVM estabelecida, o próximo capítulo aprofunda o mecanismo que conecta tudo isso à View de fato: data binding em XAML, e Commands — o equivalente MVVM de uma Action de Controller.

📌 Resumo do capítulo

  • MVVM separa View (XAML puro), ViewModel (estado + comandos) e Model — a View nunca chama o ViewModel diretamente.
  • INotifyPropertyChanged é o mecanismo que permite à View reagir automaticamente a mudanças no ViewModel.
  • Uma classe base (ViewModelBase) com DefinirCampo evita repetir a lógica de notificação em cada propriedade.

✏️ Praticando

  1. Implemente ViewModelBase e ClienteCadastroViewModel como nos exemplos.
  2. Explique, em suas próprias palavras, por que a View "nunca conhecer" o ViewModel diretamente (ao contrário do code-behind do capítulo anterior) facilita testes automatizados do ViewModel sem precisar abrir uma janela de verdade.