.NET 
MAUI - Usando o banco de dados SQLite - II
    
    ![]()  | 
    Neste artigo vamos criar uma aplicação .NET MAUI para gerenciar um pequena biblioteca de livros pessoal realizando a persistência dos dados no SQLite. | 
Continuando a primeira parte do artigo vamos criar as views , fazer as vinculações e registro dos serviços e preparar nossa aplicação para ser executada.
Criando as Views
Vamos agora criar na pasta MVVM/Views as respectivas views definindo o leiaute da interface com o usuário e vinculando cada view à sua view model. Todas as views são do tipo Content Page.
1- LivrosPage.xaml
		<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MeusLivros.MVVM.Views.LivrosPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:model="clr-namespace:MeusLivros.MVVM.Models"
    xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
    xmlns:viewmodel="clr-namespace:MeusLivros.MVVM.ViewModels"
    Title="Meus Livros"
    x:DataType="viewmodel:LivrosViewModel">
		    <ContentPage.Resources>
        <toolkit:BoolToObjectConverter
            x:Key="BoolToObjectConverter"
            FalseObject="Leitura ❌"
            TrueObject="Concluída ✔" />
    </ContentPage.Resources>
		    <ContentPage.Behaviors>
        <toolkit:EventToCommandBehavior Command="{Binding GetLivrosCommand}" EventName="Appearing" />
    </ContentPage.Behaviors>
		    <Grid
        Margin="20"
        RowDefinitions="Auto,*"
        RowSpacing="10">
        <Grid Grid.Row="0" ColumnDefinitions="*,*">
            <SearchBar Grid.Column="0"
                 Placeholder="Localizar Livro"
                 TextChanged="SearchBar_TextChanged"/>
            <Button
                Grid.Column="1"
                Background="gold"
                Command="{Binding AddLivroCommand}"
                FontAttributes="Bold"
                HorizontalOptions="End"
                Text="Novo Livro"
                TextColor="Black" />
        </Grid>
              <CollectionView x:Name="ColView1" Grid.Row="1" ItemsSource="{Binding MeusLivros}">
            <CollectionView.ItemsLayout>
                <LinearItemsLayout ItemSpacing="4" Orientation="Vertical" />
            </CollectionView.ItemsLayout>
            <CollectionView.ItemTemplate>
                <DataTemplate x:DataType="model:Livro">
                    <Border
                        Padding="15"
                        Background="lightgray"
                        Stroke="Dimgray"
                        StrokeThickness="2">
                        <Border.StrokeShape>
                            <RoundRectangle CornerRadius="10,10,10,10" />
                        </Border.StrokeShape>
                        <Grid RowDefinitions="Auto,*" RowSpacing="4">
                            <Image
                                Grid.Row="0"
                                Aspect="AspectFill"
                                HeightRequest="200"
                                HorizontalOptions="Center"
                                Source="{Binding ImagemUrl}"
                                VerticalOptions="Center" />
		                            <Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto,Auto">
                                <Label
                                    Grid.Row="0"
                                    FontAttributes="Bold"
                                    FontSize="Medium"
                                    Text="{Binding Titulo}" />
                                <Label
                                    Grid.Row="1"
                                    Margin="0,2"
                                    FontSize="Small"
                                    Text="{Binding Autor}" />
                                <Label
                                    Grid.Row="2"
                                    Margin="0,2"
                                    FontSize="Small"
                                    Text="{Binding Paginas,  StringFormat='{0:F0} páginas'}" />
                                <Grid
                                    Grid.Row="3"
                                    Margin="0,5"
                                    ColumnDefinitions="Auto,Auto,*">
                                    <Button
                                        Grid.Column="0"
                                        BackgroundColor="#4A88DA"
                                        Command="{Binding Source={RelativeSource 
                                         AncestorType={x:Type viewmodel:LivrosViewModel}}, Path=UpdateLivroCommand}"
                                        CommandParameter="{Binding .}"
                                        FontAttributes="Bold"
                                        Text="Atualizar"
                                        TextColor="#eff5f3" />
                                    <Button
                                        Grid.Column="1"
                                        Margin="8,0"
                                        BackgroundColor="#F44336"
                                        Command="{Binding Source={RelativeSource AncestorType={x:Type 
                                        viewmodel:LivrosViewModel}}, Path=DeleteLivroCommand}"
                                        CommandParameter="{Binding .}"
                                        FontAttributes="Bold"
                                        Text="Deletar"
                                        TextColor="#eff5f3" />
                                    <Label
                                        Grid.Column="2"
                                        HorizontalOptions="End"
                                        LineBreakMode="TailTruncation"
                                        Text="{Binding LeituraConcluida, Converter={StaticResource BoolToObjectConverter}}"
                                        TextColor="Blue"
                                        VerticalOptions="Center" />
                                </Grid>
                            </Grid>
                        </Grid>
                    </Border>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </Grid>
</ContentPage>
		 | 
	
Destaques do código :
x:DataType é usado 
	para especificar o tipo de dados associado a esta página. Ele está vinculado 
	ao ViewModel LivrosViewModel, o 
	que significa que o DataContext da página será definido como uma instância 
	de LivrosViewModel.BoolToObjectConverter. Este recurso é usado para 
	converter valores booleanos em texto ("Leitura ❌" ou "Concluída ✔") e é 
	usado posteriormente em um Label. Para isso estamos usando o 
	pacote CommunityToolkit.Maui.ContentPage.Behaviors define comportamentos 
	associados à página. Um comportamento 
	EventToCommandBehavior está associado ao evento "Appearing" 
	da página. Ele está vinculado a um comando chamado 
	GetLivrosCommand no ViewModel, que será acionado quando 
	a página aparecer.Neste código definidos nos botões de comando para 
Atualizar e Deletar :
 
Command="{Binding Source={RelativeSource 
AncestorType={x:Type viewmodel:LivrosViewModel}}, Path=UpdateLivroCommand}": 
Este atributo associa um comando ao botão sendo que o comando é definido no 
ViewModel e é acionado quando o botão é pressionado:Command="{Binding ...}": Isso 
	define o comando a ser acionado quando o botão for pressionado.Source={RelativeSource AncestorType={x:Type 
	viewmodel:LivrosViewModel}}: Isso especifica que o comando 
	será procurado no ViewModel do tipo 
	LivrosViewModel na hierarquia de elementos pai da página 
	atual.Path=UpdateLivroCommand: 
	Especifica que o caminho para o comando é 
	UpdateLivroCommand, que é um comando definido no 
	LivrosViewModel.2- AddLivroPage.xaml
		<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MeusLivros.MVVM.Views.AddLivroPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodel="clr-namespace:MeusLivros.MVVM.ViewModels"
    Title="Incluir Livro">
		    <VerticalStackLayout Margin="20">
        <Entry Placeholder="Titulo" Text="{Binding LivroTitulo}" />
        <Entry Placeholder="Autor" Text="{Binding LivroAutor}" />
        <Entry Placeholder="Imagem" Text="{Binding LivroImagemUrl}" />
        <Entry Placeholder="No. de Páginas" Text="{Binding LivroPaginas}" />
        <Entry Placeholder="Emprestado para..." Text="{Binding LivroEmprestadoPara}" />
        <HorizontalStackLayout>
            <CheckBox IsChecked="{Binding LivroLeituraConcluida}" />
            <Label Text="Você concluiu a leitura deste livro ?" VerticalOptions="Center" />
        </HorizontalStackLayout>
        <Button
            Background="gold"
            Command="{Binding AddLivroCommand}"
            FontAttributes="Bold"
            Text="Novo Livro"
            TextColor="Black" />
    </VerticalStackLayout>
		</ContentPage>  | 
	
Vamos entender o código:
xmlns:viewmodel: Este 
atributo xmlns define um namespace para o namespace de
ViewModels (MeusLivros.MVVM.ViewModels). 
Isso permite que você associe elementos da interface do usuário a propriedades e 
comandos definidos nos ViewModels.
A seguir temos as seguintes vinculações:
 
Text="{Binding LivroTitulo}": 
	Isso liga o texto do Entry à propriedade LivroTitulo 
	no ViewModel. Quando o usuário insere um título, ele é armazenado na 
	propriedade LivroTitulo.IsChecked="{Binding LivroLeituraConcluida}": 
	Isso liga o estado do CheckBox à propriedade 
	LivroLeituraConcluida no ViewModel. Quando o usuário marca ou 
	desmarca o CheckBox, a propriedade 
	LivroLeituraConcluida reflete esse estado.Command="{Binding AddLivroCommand}": 
	Isso liga o comando do botão Button ao comando 
	AddLivroCommand no ViewModel. Quando o botão é pressionado, o comando
	AddLivroCommand é acionado no 
	ViewModel.3- UpdateLivroPage.xaml
		<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MeusLivros.MVVM.Views.UpdateLivroPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:viewmodel="clr-namespace:MeusLivros.MVVM.ViewModels"
    Title="Atualizar Livro"
    x:DataType="viewmodel:UpdateLivroViewModel">
		    <VerticalStackLayout Margin="20">
        <Entry Placeholder="Titulo" Text="{Binding Livro.Titulo}" />
        <Entry Placeholder="Autor" Text="{Binding Livro.Autor}" />
        <Entry Placeholder="Imagem" Text="{Binding Livro.ImagemUrl}" />
        <Entry Placeholder="No. de Páginas" Text="{Binding Livro.Paginas}" />
        <Entry Placeholder="Emprestado para..." Text="{Binding Livro.EmprestadoPara}" />
        <HorizontalStackLayout>
            <CheckBox IsChecked="{Binding Livro.LeituraConcluida}" />
            <Label Text="Já concluiu a leitura deste livro ?" VerticalOptions="Center" />
        </HorizontalStackLayout>
        <Button
            Background="#4A88DA"
            Command="{Binding UpdateLivroCommand}"
            Text="Atualizar Livro"
            TextColor="#eff5f3" />
    </VerticalStackLayout>
		</ContentPage>  | 
	
A lógica desta view é idêntica à anterior, a diferença é que aqui estamos vinculando a ação ao comando UpdateLivroCommand.
A seguir temos o código que faz a vinculação de cada view com a respectiva view model no arquivo code-behind:
1- LivrosPages.xaml.cs
		public partial class LivrosPage : ContentPage
{
    private readonly ILivroService _livroService;
    public LivrosPage(LivrosViewModel livrosViewModel, 
                      ILivroService livroService)
    {
        InitializeComponent();
        BindingContext = livrosViewModel;
        _livroService = livroService;
    }
		    private async void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
    {
        var livros = await _livroService.GetLivroTituloAsync(((SearchBar)sender).Text);
        ColView1.ItemsSource = livros;
    }
}
		 | 
	
2- AddLivroPage.xaml.cs
		public partial class AddLivroPage : ContentPage
{
    public AddLivroPage(AddLivroViewModel addLivroViewModel)
    {
	InitializeComponent();
             BindingContext = addLivroViewModel;
    }
}
		 | 
	
3- UpdateLivroPage.xaml.cs
		public partial class UpdateLivroPage : ContentPage
{
	public UpdateLivroPage(UpdateLivroViewModel updateLivroViewModel)
	{
		InitializeComponent();
		BindingContext = updateLivroViewModel;
	}
}
		 | 
	
Não podemos esquecer de registrar os serviços no contêiner DI na classe MauiProgram:
		public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });
		#if DEBUG
		builder.Logging.AddDebug();
#endif
        // ViewModels
        builder.Services.AddSingleton<LivrosViewModel>();
        builder.Services.AddTransient<AddLivroViewModel>();
        builder.Services.AddTransient<UpdateLivroViewModel>();
		        // Views
        builder.Services.AddSingleton<LivrosPage>();
        builder.Services.AddTransient<AddLivroPage>();
        builder.Services.AddTransient<UpdateLivroPage>();
		        // Service
        builder.Services.AddSingleton<ILivroService, LivroService>();
		        return builder.Build();
    }
}
		 | 
	
Neste código destacamos o seguinte:
.UseMauiCommunityToolkit(): 
Este método configura o aplicativo para usar o community toolkit maui(CommunityToolkit) 
que fornece funcionalidades e controles adicionais para a construção de 
aplicativos.
 
builder.Services.AddSingleton<LivrosViewModel>();: Aqui, o 
construtor está configurando a injeção de dependência para o ViewModel 
LivrosViewModel, registrando-o como um serviço Singleton. Isso significa 
que uma única instância do LivrosViewModel será compartilhada em 
todo o aplicativo.
builder.Services.AddTransient<AddLivroViewModel>(); e 
builder.Services.AddTransient<UpdateLivroViewModel>();: Da 
mesma forma, os ViewModels AddLivroViewModel e 
UpdateLivroViewModel são configurados como serviços transientes. Isso 
significa que uma nova instância desses ViewModels será criada sempre que for 
solicitada.builder.Services.AddSingleton<LivrosPage>();,
builder.Services.AddTransient<AddLivroPage>();, e
builder.Services.AddTransient<UpdateLivroPage>();: 
Os tipos de página correspondentes aos ViewModels também são configurados como 
serviços. LivrosPage é registrado como
Singleton, enquanto 
AddLivroPage e UpdateLivroPage são registrados como
transientes.builder.Services.AddSingleton<ILivroService, 
LivroService>();: Aqui, o serviço 
ILivroService é configurado para usar a implementação
LivroService como implementação 
concreta. Isso permite que outros componentes do aplicativo dependam de
ILivroService e usem a implementação
LivroService para acessar 
funcionalidades relacionadas a livros.Tipos de vida usados nos serviços:
 
LivrosPage é a página 
		principal do aplicativo que exibe uma lista de livros. Ela pode ser 
		usada em toda a vida do aplicativo, e é comum manter as páginas 
		principais como instâncias Singleton, pois 
		elas geralmente não mudam ao longo da sessão do usuário.ILivroService é o serviço 
		responsável por interagir com a camada de dados, neste caso, 
		ILivroService, é frequentemente registrado como
		Singleton para garantir que haja uma única 
		instância compartilhada em todo o aplicativo. Isso é útil para manter um 
		único estado de conexão com o banco de dados ou gerenciar recursos 
		compartilhados, economizando recursos e garantindo consistência em toda 
		a aplicação.AddLivroViewModel e 
		UpdateLivroViewModel são ViewModels usadas para controlar 
		as operações de adição e atualização de livros. Essas ViewModels podem 
		ser usadas temporariamente durante a adição ou atualização de um 
		livro específico e não precisam ser compartilhados entre várias 
		partes do aplicativo. Portanto, eles são registrados como
		Transient, o que significa que uma nova 
		instância será criada sempre que necessário e será descartada quando não 
		for mais usada. Isso evita o acúmulo de estado desnecessário.Agora vamos configurar as rotas usadas no projeto no arquivo AppShell.xaml e AppShell.xaml.cs .
1- AppShell.xaml
		<?xml version="1.0" encoding="UTF-8" ?>
<Shell
    x:Class="MeusLivros.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MeusLivros"
    xmlns:views="clr-namespace:MeusLivros.MVVM.Views"
    Shell.FlyoutBehavior="Disabled">
		    <ShellContent ContentTemplate="{DataTemplate views:LivrosPage}" Route="LivrosPage" />
		</Shell>  | 
	
Este código define a estrutura básica do Shell do aplicativo .NET MAUI, 
desativando o menu de navegação lateral (flyout) e 
configurando LivrosPage como a página 
principal exibida quando o aplicativo é iniciado. 
<ShellContent>: Este é um 
elemento dentro do Shell que define o conteúdo principal da página. Ele está 
associado a um modelo de conteúdo (ContentTemplate) 
que especifica qual página será exibida como conteúdo principal. Neste caso, a 
página LivrosPage será exibida como 
conteúdo principal quando o aplicativo for iniciado. O atributo
Route especifica o rótulo ou 
identificador da página.
2- AppShell.xaml.cs
		public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
        RegisterForRoute<AddLivroPage>();
        RegisterForRoute<UpdateLivroPage>();
    }
		    protected void RegisterForRoute<T>()
    {
        Routing.RegisterRoute(typeof(T).Name, typeof(T));
    }
}
		 | 
	
Vamos entender o código usado:
 
InitializeComponent(): 
	Este método é gerado automaticamente e é usado para inicializar os 
	componentes do layout XAML associados à classe AppShell. Essa 
	chamada garante que o layout definido no arquivo XAML seja carregado e 
	configurado corretamente.RegisterForRoute<AddLivroPage>(); 
	e RegisterForRoute<UpdateLivroPage>();: Esses 
	métodos são chamados no construtor para registrar páginas específicas que 
	podem ser navegadas usando rotas no aplicativo. Eles usam o método
	Routing.RegisterRoute para 
	associar o nome da classe da página (AddLivroPage 
	e UpdateLivroPage) com a classe real que representa a 
	página.protected void RegisterForRoute<T>(): 
	Este é um método genérico que permite registrar páginas para navegação com 
	base no tipo de página. Ele usa reflection para 
	obter o nome da classe do tipo T e, em seguida, registra uma 
	rota com esse nome.Com isso temos tudo pronto para por o nosso projeto para funcionar.
![]()
Executando o projeto em um emulador Android teremos o seguinte resultado:
1- A tela inicial

2- Incluindo um novo livro

3- Atualizando um livro

4- Excluindo um livro

Pegue o código do projeto aqui: 
 
MeusLivrosApp.zip
![]()
"['Senhor'] O teu reino é um reino eterno; o teu domínio dura em todas 
as gerações."
Salmos 
145:13
Referências: