Hoje veremos como criar uma aplicação WPF e realizar um CRUD básico usando o SQLite. O WPF (Windows Presentation Foundation) é um framework de desenvolvimento de interface de usuário da Microsoft para a criação de aplicativos desktop Windows. Ele faz parte do conjunto de tecnologias do .NET Framework/.NET Core e fornece uma abordagem moderna e poderosa para a criação de interfaces gráficas ricas e interativas.
O WPF utiliza a linguagem de marcação XAML (eXtensible Application Markup Language) para definir a interface do usuário de forma declarativa, separando a lógica de apresentação da lógica de negócios. Isso permite que os desenvolvedores criem interfaces complexas e visualmente atraentes usando um modelo de programação orientado a objetos.
Neste artigo vamos criar uma aplicação WPF para gerenciar informações sobre produtos usando o SQLite.
Recursos usados:
-
VS 2022
-
.NET 7.0
Criando o projeto
No VS 2022 Community vamos criar um projeto usando o template e nomeá-lo como WpfProdutos :
Vamos incluir no projeto os seguintes pacotes nugets:
1- Microsoft.EntityFrameworkCore.Sqlite
2- Microsoft.Extensions.DependencyInjection
3- Microsoft.Extensions.DependencyInjection.Abstractions
A seguir vamos criar no projeto a pasta Data e nesta pasta criar a classe Produto e a classe ProdutoContext :
1- Produto – representa o modelo de domínio
public class Produto
{
public int Id { get; set; }
public string? Nome { get; set; }
public string? Descricao { get; set; }
public double Preco { get; set; }
public int Quantidade { get; set; }
}
2- ProdutoContext – representa a classe de contexto que herda de DbContext e faz o mapeamento ORM.
public class ProdutoContext : DbContext
{
public ProdutoContext(DbContextOptions<ProdutoContext> options): base(options)
{
Database.EnsureCreated();
}
public DbSet<Produto> Produto { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Produto>().HasData(GetProdutos());
base.OnModelCreating(modelBuilder);
}
private List<Produto> GetProdutos()
{
return new List<Produto>
{
new Produto { Id = 1001, Nome = "Laptop", Preco = 20.02, Quantidade = 10,
Descricao ="O melhor laptop para jogos"},
new Produto { Id = 1002, Nome = "Microsoft Office", Preco = 20.99, Quantidade = 50,
Descricao ="Aplicação Office"},
new Produto { Id = 1003, Nome = "Lazer Mouse", Preco = 12.02, Quantidade = 20,
Descricao ="Um mouse decente"},
new Produto { Id = 1004, Nome = "USB Storage", Preco = 5.00, Quantidade = 20,
Descricao ="Armazena ate 256GB de dados"}
};
}
}
Neste código, no construtor, estamos usando o o método Database.EnsureCreated() que verifica se o banco de dados foi criado e, se não, o cria com base no modelo definido pelas classes de entidade. Isso garante que o banco de dados esteja criado antes de ser usado.
O método HasData() recebe os dados retornados pelo método GetProdutos() e os insere no banco de dados quando o modelo for criado.
No arquivo App.xaml vamos alterar o código conforme a seguir:
<Application x:Class="WpfProdutos.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfProdutos"
Startup="OnStartup">
<Application.Resources>
</Application.Resources>
</Application>
Neste código estamos especificando um evento chamado “OnStartup” que será tratado na classe App quando a aplicação for iniciada.
Agora no arquivo App.xaml.cs vamos registrar o serviço do contexto e definir o provedor do banco de dados e sua configuração:
using WpfProdutos.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Windows;
namespace WpfProdutos;
public partial class App : Application
{
private readonly ServiceProvider serviceProvider;
public App()
{
ServiceCollection services = new ServiceCollection();
services.AddDbContext<ProdutoContext>(options =>
{
options.UseSqlite("Data Source = ProdutosDB.db");
});
services.AddSingleton<MainWindow>();
serviceProvider = services.BuildServiceProvider();
}
private void OnStartup(object s, StartupEventArgs e)
{
var mainWindow = serviceProvider.GetService<MainWindow>();
mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
mainWindow.Show();
}
}
Neste código temos o construtor da classe App onde estão sendo configurados os serviços necessários para a aplicação.
- ServiceCollection services = new ServiceCollection();: Cria uma instância de ServiceCollection, que é um container para registrar serviços.
- services.AddDbContext<ProductDBcontext>(option => …);: Registra um serviço de contexto de banco de dados ProductDBcontext usando o SQLite como provedor. A conexão com o banco de dados é especificada como “Data Source = ProdutosDB.db“. Isso indica que a aplicação usará um banco de dados SQLite chamado “ProdutosDB.db”.
- services.AddSingleton<MainWindow>();: Registra um serviço de MainWindow como um serviço Singleton, o que significa que haverá apenas uma instância desse serviço em toda a aplicação.
- serviceProvider = services.BuildServiceProvider();: Constrói o provedor de serviços com base nas configurações fornecidas. Agora, o serviceProvider contém todos os serviços configurados.
- O método OnStartup obtemos o serviço , centralizamos a janela e a exibimos;
Vamos definir o código para criar a interface com usuário usando um DataGrid no arquivo MainWindow.xaml:
<Window x:Class="WpfProdutos.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfProdutos"
mc:Ignorable="d"
Title="MainWindow" Height="550" Width="800">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="45"/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label FontSize="18" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5"
Grid.Row="0" Content="Produtos - CRUD "/>
<DataGrid x:Name="ProdutoDG" AutoGenerateColumns="False" CanUserAddRows="False" IsReadOnly="True"
Grid.Row="1" ColumnWidth="*" Margin="5" IsSynchronizedWithCurrentItem="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding Id}"/>
<DataGridTextColumn Header="Nome" Binding="{Binding Nome }"/>
<DataGridTextColumn Header="Descrição" Binding="{Binding Descricao}"/>
<DataGridTextColumn Header="Preço" Binding="{Binding Path=Preco,
ConverterCulture='pt-BR',StringFormat=C}" />
<DataGridTextColumn Header="Quantidade" Binding="{Binding Path=Quantidade}"/>
<DataGridTemplateColumn Header="Editar">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Edita" Click="SelectProdutoToEdit" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Deletar">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Deleta" Click="DeleteProduto"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="5" BorderThickness="1" BorderBrush="Black">
<StackPanel Margin="5">
<Label Content="Novo Produto" FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="5"/>
<Grid Name="NovoProdutoGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Nome"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Nome}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Descrição"/>
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Descricao}"/>
<Label Grid.Row="2" Grid.Column="0" Content="Preço"/>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding Preco}"/>
<Label Grid.Row="3" Grid.Column="0" Content="Quantidade"/>
<TextBox Grid.Row="3" Grid.Column="4" Text="{Binding Quantidade}"/>
<Button Grid.Row="4" Grid.ColumnSpan="2" Width="150" Content="Adicionar"
Margin="5" Click="AddItem"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</Border>
<Border Grid.Column="1" Margin="5" BorderThickness="1" BorderBrush="Black">
<StackPanel Margin="5">
<Label Content="Editar" FontWeight="Bold"
HorizontalAlignment="Center"
VerticalAlignment="Center" Margin="5"/>
<Grid Name="UpdateProdutoGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Nome"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Nome}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Descrição"/>
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Descricao}"/>
<Label Grid.Row="2" Grid.Column="0" Content="Preço"/>
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding Preco}"/>
<Label Grid.Row="3" Grid.Column="0" Content="Quantidade"/>
<TextBox Grid.Row="3" Grid.Column="4" Text="{Binding Quantidade}"/>
<Button Grid.Row="4" Grid.ColumnSpan="2" Width="150" Click="UpdateItem"
Content="Editar" Margin="5"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</Border>
</Grid>
</Grid>
</Window>
A interface gerada tem a seguinte aparência:
Agora vamos definir o código no arquivo code-behind MainWindow.xaml.cs :
using System.Linq;
using System.Windows;
using WpfProdutos.Data;
namespace WpfProdutos;
public partial class MainWindow : Window
{
ProdutoContext context;
Produto NovoProduto = new Produto();
Produto selectedProduto = new Produto();
public MainWindow(ProdutoContext context)
{
this.context = context;
InitializeComponent();
GetProdutos();
NovoProdutoGrid.DataContext = NovoProduto;
}
private void GetProdutos()
{
ProdutoDG.ItemsSource = context.Produtos.ToList();
}
private void AddItem(object s, RoutedEventArgs e)
{
if (ValidaDados(NovoProduto))
{
context.Produtos.Add(NovoProduto);
context.SaveChanges();
GetProdutos();
NovoProduto = new Produto();
NovoProdutoGrid.DataContext = NovoProduto;
}
else
{
MessageBox.Show("Dados informados não são válidos", "Novo Produto - Erro",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void UpdateItem(object s, RoutedEventArgs e)
{
if (ValidaDados(selectedProduto))
{
context.Update(selectedProduto);
context.SaveChanges();
GetProdutos();
}
else
{
MessageBox.Show("Dados informados não são válidos", "Atualiza Produto - Erro",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void SelectProdutoToEdit(object s, RoutedEventArgs e)
{
selectedProduto = (s as FrameworkElement).DataContext as Produto;
UpdateProdutoGrid.DataContext = selectedProduto;
}
private void DeleteProduto(object s, RoutedEventArgs e)
{
var produtoToDelete = (s as FrameworkElement).DataContext as Produto;
context.Produtos.Remove(produtoToDelete);
context.SaveChanges();
GetProdutos();
}
private bool ValidaDados(Produto produto)
{
if (produto.Id == 0) return false;
if (produto.Nome == null) return false;
if (produto.Descricao == null) return false;
if (produto.Quantidade == 0) return false;
return true;
}
}
Neste código temos a lógica para realizar a inclusão e alteração dos dados de produtos usando o EF Core.
Pegue o código do projeto aqui: WpfProdutos.zip