.NET MAUI - MVVM, DataBinding e a interface ICommand - I


  Neste artigo vou apresentar os principais conceitos sobre MVVM, DataBinding e da interface ICommand : Apresentando o cenário e criando o projeto

Quando trabalhamos com o .NET MAUI em aplicações de negócios geralmente definimos um modelo de domínio que representam as classes da nossa aplicação. Estamos assim definindo o Model que é constituido de classes C#, e, geralmente essas classes são classes POCO contendo apenas propriedades.(o que é conhecido como um modelo anêmico)

Outro componente essencial de uma aplicação .NET MAUI são as páginas que contém layouts e outras views e representam o componente visual da nossa aplicação conhecido como Views.

Para separar a lógica de negócio da parte visual usamos o padrão MVVM - Model-View-ViewModel e criamos para isso as classes que vão conter todo o código responsável por gerenciar a dar a vida às Views. Essas classes são conhecidas como o ViewModel é possuem o objetivo de reunir toda a lógica de atualização, acesso e conversão de dados.

Temos assim o tripé : Model, View e ViewModel.

O recurso DataBinding atua de forma crucial para que a aplicação do padrão MVVM funcione. Vamos ver um pouco sobre ele...

O famigerado DataBinding e a interface ICommand

Se você procurar pela definição de DataBinding na Wikipédia vai encontrar :

"Ligação de dados, do inglês Data binding, é uma técnica geral que une duas fontes de dados/informações e as mantém em sincronia em um processo que estabelece uma conexão entre UI (interface de usuário) da aplicação e a logica de negocio."

Uma forma de fazer a ligação de dados no .NET MAUI é fazer a ligação entre o Code-Behind, representado pelo código C#, e o código XAML que define a interface do usuário. É assim que declaramos um evento para uma View no código XAML e fazemos o tratamento do evento no Code-Behind com C#.

Essa abordagem funciona mas nos trás muito problemas quando precisamos testar nossas aplicações. Esse é um dos motivos da utilização do padrão MVVM. Então para contornar esse problema usamos a abordagem MVVM onde o DataBinding é feito praticamente no código XAML usando as propriedades BindingContext  e Binding.

Nesta abordagem o DataBinding ou vinculação de dados é usado para conectar as propriedades dos elementos visuais na View com as propriedades dos dados na ViewModel permitindo a manipulação direta dos dados através da interface do usúário.

Mas diante da complexidade das aplicações de negócios nem tudo são propriedades, e, muitas vezes a ViewModel expõe métodos públicos que precisam se chamados a partir da View com base em uma interação do usuário.

Sem usar MVVM, teríamos que fazer a chamada dos métodos a partir de um evento, como um evento Clicked de um Button ou Tapped de um TapGestureRecognizer.

Para tornar um elemento de interface do usuário clicável com o gesto de toque, criamos uma instância de TapGestureRecognizer, manipulamos o evento Tapped e adicionamos o novo reconhecimento de gestos à coleção GestureRecognizers no elemento de interface do usuário.

Mas como podemos fazer a chamada de métodos acionados pela interação do usuário em uma View a partir de uma ViewModel ?

A boa notícia é que o .NET MAUI fornece um recurso que permite que a ligação de dados ou databinding realize chamada de métodos na ViewModel diretamente a partir de um Button ou TapGestureRecognizer e alguns outros elementos.

Esse recurso é a interface ICommand que permite definir e implementar um comando o que chamamos de commanding. Usando comandos, o databinding pode fazer chamadas de método diretamente de uma ViewModel a partir das seguinte classes:

Nota: Podemos também implementar comandos em classes customizadas.

Implementando um Comando

Afim de implementar um Command, a ViewModel deverá definir uma ou mais propriedades do tipo ICommand, e para isso a interface ICommand define dois métodos e um evento:

public interface ICommand
{
    void Execute(object arg);
    bool CanExecute(object arg)
    event EventHandler CanExecuteChanged;   
}

As classes Command e Command<T> fornecidas pelo .NET MAUI implementam a interface ICommand, onde T é o tipo dos argumentos para Execute e CanExecute.

Nota: Use Command<T> quando você usar a CommandParameter propriedade para distinguir entre várias exibições associadas à mesma ICommand propriedade e a Command classe quando isso não for um requisito.

Bem como implementar a interface ICommand, essas classes também incluem o método ChangeCanExecute, que faz com que o objeto Command dispare o evento CanExecuteChanged.

Dentro de um ViewModel, deve haver um objeto do tipo Command ou Command<T> para cada propriedade pública na ViewModel do tipo ICommand.

O construtor de Command requer um objeto Action de retorno, que é chamado quando o botão chama o método ICommand.Execute.

O método CanExecute é um parâmetro de construtor opcional, e toma a forma de um Func que retorna um booleano.

Vamos ver uma aplicação prática desse recurso em um exemplo bem simples para entendermos melhor o seu funcionamento.

Recursos usados:

Criando um projeto no VS 2022

Abra o Visual Studio Community e clique em New Project;

Selecione Visual C#, o template .NET MAUI App e Informe o nome MauiBoasVindas ;

Selecione o .NET 7.0 e clique no botão Create;

Ao clicar no botão Create, será criada uma solução com um único projeto conforme mostra a figura a seguir:

Vamos criar no projeto a pasta Mvvm e nesta pasta vamos criar as pastas : Views, Models e ViewModels para organizar o código que iremos criar.

Criando a view SaudacaoView

Vamos criar na pasta Views dentro da pasta Mvvm uma Content Page chamada SaudacaoView .

Clique com o botão direito do mouse sobre a pasta e selecione Add-> New Item

Selecione .NET MAUI e o template .NET MAUI ContentPage(XAML), informe o nome e clique em Add;

Inclua o código XAML abaixo na Content Page :

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiBoasVindas.Mvvm.Views.SaudacaoView"
             Title="Saudação">  

    <VerticalStackLayout Spacing="20">

        <Image Source="dotnet_bot.png" Aspect="AspectFit"
               HeightRequest="200"
               WidthRequest="200"/>

        <Label Text=".NET MAUI - MVVM"
               TextColor="Navy"
               HorizontalOptions="Center"
               FontAttributes="Bold"
               FontSize="20"/>

        <Entry x:Name="txtNome" Placeholder="Informe o nome"
               FontSize="20" />

        <Button x:Name="btnSaudacao"
                Text="Boas Vindas" TextColor="White"
                FontSize="20"
                BackgroundColor="Navy"
                HorizontalOptions="Center"
                Clicked="btnSaudacao_Clicked" />

        <Label x:Name="lblMensagem" FontSize="20"
               TextColor="Red"
               HorizontalOptions="Center"
               FontAttributes="Bold" />

    </VerticalStackLayout>   
</ContentPage>

Antes de prosseguir abra o arquivo App.xaml.cs e altere o código do construtor conforme abaixo:

public partial class App : Application
{
    public App()
    {
InitializeComponent();
MainPage = new NavigationPage(new SaudacaoView());
    }
}

Assim estamos definindo a nossa view SaudacaoView como a página principal da aplicação.

No arquivo code-behind SaudacaoView.xaml.cs vamos definir o tratamento do evento Clicked conforme abaixo:

public partial class SaudacaoView : ContentPage
{
     public SaudacaoView()
     {
InitializeComponent();
     }

    private void btnSaudacao_Clicked(object sender, EventArgs e)
    {
        var nome = txtNome.Text;
        lblMensagem.Text = "Bem-Vindo " + nome;
    }
}

Neste código quando o usuário clicar no botão o nome informado será exibido na Label - lblMensagem - com o texto : "Bem-Vindo nome_digitado"

Tudo bem a aplicação funciona, mas essa é a abordagem tradicional sem usar o padrão MVVM onde não temos uma ViewModel e onde a lógica da apresentação esta contida na própria View.

Vamos melhorar a nossa aplicação aplicando o padrão MVVM na segunda parte do artigo.

"Louvai ao SENHOR todas as nações, louvai-o todos os povos.
Porque a sua benignidade é grande para conosco, e a verdade do Senhor dura para sempre. Louvai ao Senhor."
Salmos 117:1,2

Referências:


José Carlos Macoratti