1. As três peças do MVVM
| Peça | Responsabilidade | Equivalente no Módulo 3 (MVC) |
|---|---|---|
| Model | Dados e regra de negócio | Model (idêntico) |
| View | XAML — só estrutura visual, sem lógica | View (Razor) |
| ViewModel | Estado da tela + comandos, conectado à View via data binding | Controller + 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.
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:
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;
}
}
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
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.