O que é MVVM?

Concluído

Os aplicativos .NET MAUI que não usam MVVM geralmente têm mais código em seus arquivos code-behind . Os arquivos code-behind no .NET MAUI seguem este padrão: {something}.xaml.cs. A maioria do código no arquivo code-behind geralmente controla o comportamento da interface do usuário (UI). O comportamento da interface do usuário pode incluir qualquer coisa que aconteça com a interface do usuário, como alterar uma cor ou algum texto. E pode incluir qualquer coisa que aconteça por causa da interface do usuário, incluindo manipuladores de clique de botão.

Um problema com essa abordagem é que é difícil escrever testes de unidade em arquivos code-behind. Os arquivos code-behind geralmente assumem um estado de aplicativo criado pela análise de XAML ou até mesmo por outras páginas. Essas condições são difíceis de lidar em um executor de teste de unidade que pode nem estar sendo executado em um dispositivo móvel, muito menos com uma interface de usuário. Portanto, os testes de unidade raramente são capazes de testar os comportamentos da interface do usuário nesses arquivos.

Mas é aqui que o padrão MVVM é útil. Quando usado corretamente, o padrão MVVM resolve esses problemas movendo a maior parte da lógica de comportamento da interface do usuário para classes testáveis por unidade que são chamadas viewmodels. O padrão MVVM é mais comumente usado com estruturas que suportam vinculação de dados. Isso porque, com o .NET MAUI, você pode vincular cada elemento da interface do usuário a um viewmodel e eliminar ou quase eliminar o código em um modo de exibição ou code-behind.

Quais são as partes de um aplicativo MVVM?

Embora o viewmodel seja a parte exclusiva do padrão MVVM, o padrão também define uma parte do modelo e uma parte da exibição . As definições dessas partes são consistentes com alguns outros padrões comuns, como um Model-View-Controller (MVC).

O que é um modelo?

Em um aplicativo MVVM, o termo modelo é usado para denotar seus dados e operações de negócios. O modelo não se envolve com a apresentação do usuário do aplicativo.

Uma regra útil para determinar qual código pertence ao modelo é que ele deve ser portátil em diferentes plataformas. De um aplicativo móvel para uma interface web ou até mesmo um programa de linha de comando, usando o mesmo modelo em todas as instâncias. Não está relacionado com a forma como a informação é apresentada ao utilizador.

Quando você pensa no aplicativo HR do nosso cenário, o modelo pode incluir uma Employee classe e uma Department classe que contêm dados e lógica sobre essas entidades. O modelo também pode incluir coisas como uma EmployeeRepository classe que mantém a lógica de persistência. Alguns outros padrões de design de software considerariam coisas como repositórios como separadas do modelo. Mas, no contexto do MVVM, muitas vezes nos referimos a qualquer lógica de negócios ou dados de negócios como parte do modelo.

Aqui estão dois exemplos de um modelo em C#:

public class Employee
{
    public int Id { get; }
    public string Name { get; set; }
    public Employee Supervisor { get; set; }
    public DateTime HireDate { get; set; }
    public void ClockIn() { ... }
}

public class EmployeeRepository
{
    public IList<Employee> QueryEmployees() { ... }
    ...
}

O que é uma vista?

O código de exibição controla coisas que interagem diretamente com o usuário, como controles como botões e campos de entrada, bem como outros elementos puramente visuais, como temas, estilos e fontes.

No .NET MAUI, você não precisa escrever nenhum código C# para gerar uma exibição por conta própria. Em vez disso, você geralmente define suas exibições por arquivos XAML. Claro, há situações que exigem um controle de usuário personalizado, no qual você cria sua própria exibição através do código.

O que é um viewmodel?

Isso nos leva de volta ao viewmodel. O viewmodel é o intermediário entre nossa lógica de negócios (modelo) e nossas visões (UI).

Um diagrama que ilustra como um modelo de exibição é um intermediário entre um modelo e um modo de exibição.

Pense no que um viewmodel pode fazer pela aplicação de RH. Digamos que há uma visualização que exibe o tempo de férias disponível de um funcionário e você deseja que o saldo de férias seja exibido como "2 semanas, 3 dias, 4 horas". Mas a lógica de negócios no modelo fornece esse mesmo valor que 13,5 dias, um número decimal que representa o total de dias em um dia de trabalho de 8 horas. O modelo de objeto pode se parecer com a seguinte lista:

  • Modelo – A Employee classe, que inclui um método:

    public decimal GetVacationBalanceInDays()
    {
        //Some math that calculates current vacation balance
        ...
    }
    
  • ViewModel – Uma EmployeeViewModel classe que tem uma propriedade como esta:

    public class EmployeeViewModel
    {
        private Employee _model;
    
        public string FormattedVacationBalance
        {
            get
            {
                decimal vacationBalance = _model.GetVacationBalanceInDays();
                ... // Some logic to format and return the string as "X weeks, Y days, Z hours"
            }
        }
    }
    
  • View – Uma página XAML que contém um único rótulo e um botão fechar. O rótulo tem uma ligação com a viewmodelpropriedade do :

    <Label Text="{Binding FormattedVacationBalance}" />
    

    Em seguida, você só precisa do BindingContext conjunto de páginas para uma instância de EmployeeViewModel.

Neste exemplo, o modelo contém a lógica de negócios. Essa lógica não está vinculada a um monitor ou dispositivo visual. Você pode usar a mesma lógica para um dispositivo portátil ou computador desktop. A visão não conhece nada da lógica do negócio. Os controles de exibição, como o rótulo, sabem como obter texto na tela, mas não se importam se é um saldo de férias ou uma cadeia de caracteres aleatória. O viewmodel conhece um pouco dos dois mundos, por isso pode atuar como intermediário.

O que é interessante é como o viewmodel consegue ser um intermediário: expõe propriedades às quais uma visão pode se ligar. As propriedades públicas são a única forma de viewmodel fornecer dados. Isso nos leva ao motivo pelo qual é chamado de viewmodel. O "modelo" no MVVM representa a estrutura, os dados e a lógica dos processos de negócios, representa a viewmodel estrutura, os dados e a lógica que a exibição exige.

Como funciona a vista com o viewmodel?

Quando você olha para a relação que tem viewmodel com o modelo, é uma relação padrão de classe para classe. O viewmodel tem uma instância do modelo e expõe aspetos do modelo para a exibição através de propriedades. Mas, como é que uma vista obtém e define propriedades no viewmodel? Quando as viewmodel alterações, como o modo de exibição atualiza os controles visuais com novos valores? A resposta é a vinculação de dados.

As viewmodelpropriedades do são lidas no momento em que o objeto é vinculado à exibição. Mas, a associação não tem como saber se as viewmodelpropriedades do ' mudam depois que a associação foi aplicada à exibição. Alterar o viewmodel não propaga automaticamente o novo valor por meio da associação ao modo de exibição. Para atualizar a viewmodel partir do para o modo de exibição, o viewmodel deve implementar a System.ComponentModel.INotifyPropertyChanged interface.

A INotifyPropertyChanged interface declara um único evento chamado PropertyChanged. Ele usa um único parâmetro, o nome da propriedade que alterou seu valor. O sistema de vinculação usado no .NET MAUI entende essa interface e escuta esse evento. Quando uma propriedade é alterada no viewmodel e gera o evento, a associação notifica o destino da alteração.

Pense em como isso funciona no aplicativo de RH com um funcionário viewmodel. O viewmodel tem propriedades que representam um funcionário, como o nome do funcionário. O viewmodel implementa a INotifyPropertyChanged interface e quando a Name propriedade muda, gera o PropertyChanged evento, assim:

using System.ComponentModel;

public class EmployeeViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler? PropertyChanged;
    private Employee _model;

    public string Name
    {
        get {...}
        set
        {
            _model.Name = value;
            OnPropertyChanged(nameof(Name))
        }
    }

    protected void OnPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

O modo de exibição que descreve os detalhes do funcionário contém um controle de rótulo vinculado à viewmodelpropriedade do :Name

<Label Text="{Binding Name}" />

Quando a Name propriedade é alterada no viewmodel, o PropertyChanged evento é gerado com o nome dessa propriedade. A associação escuta o evento e, em seguida, notifica o rótulo de que a Name propriedade foi alterada. Em seguida, a propriedade do Text rótulo é atualizada com o valor mais recente.

Verifique o seu conhecimento

1.

Um desenvolvedor está trabalhando em um aplicativo .NET MAUI e deseja implementar o padrão MVVM. Eles criaram um modelo para dados e operações de negócios e uma exibição para a interação do usuário. O que eles devem criar a seguir para atuar como intermediário entre o modelo e a visão?

2.

Uma equipe está desenvolvendo um aplicativo móvel usando o .NET MAUI e quer garantir que sua lógica de negócios seja portátil em diferentes plataformas. Onde eles devem colocar essa lógica de negócios no padrão MVVM?