WPF - Realizando as operações CRUD em uma fonte de dados XML (C#)
Neste artigo vou mostrar como criar uma aplicação WPF realiza a manutenção de uma fonte de dados XML através das CRUD : incluir, excluir e atualizar.
Este artigo foi adaptado do original em : CRUD Operation on XML
O objetivo é mostrar como usar os recursos da WPF para tratar arquivos XML em uma aplicação simples mas funcional.
Recursos usados:
A nossa fonte de dados será o arquivo XML matricula.xml cuja estrutura podemos ver a seguir:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Alunos> <Aluno> <Nome>Macoratti</Nome> <Curso>Quimica</Curso> <Email>macoratti@yahoo.com</Email> <Matricula>2011</Idade> </Aluno> <Aluno> <Nome>Marcia Soares</Nome> <Curso>Biologia</Curso> <Email>marciasoraes@ig.com.br</Email> <Matricula>2011</Idade> </Aluno> </Alunos> |
O nosso arquivo
matricula.xml estará localizado na pasta c:\dados (você pode colocá-lo
em qualquer outro local (como a pasta bin)
desde que altere o |
Criando o projeto WPF
Abra o Visual C# 2010 Express Edition e crie um novo projeto (File-> New Project) do tipo WPF Application com o nome CRUDXmlDBWPF;
Vamos iniciar definido uma classe com o nome Alunos.cs (Project->Add Class) com o seguinte conteúdo:
namespace CRUDXmlDbWPF { class Alunos { public string Nome { get; set; } public string Curso { get; set; } public string Email { get; set; } public string Matricula { get; set; } } } |
Esta classe representa o nosso domínio e possui 4 propriedades que refletem as tags do arquivo matricula.xml.
Vamos iniciar definindo a interface da aplicação, para isso abra o arquivo Window1.xaml e inclua um controle TabControl a partir da ToolBox definindo 3 TabItens : Ver Todos, Incluir Novo e Atualizar conforme o leiaute da figura abaixo (à direita):
A seguir inclua os seguintes controles em cada TabItem:
Conforme o leiaute das figuras a seguir
No Grid deste TabItem
usamos os seguintes controles:
No controle DataGrid definimos:
|
|
No Grid deste TabItem
usamos os seguintes controles:
|
|
No Grid deste TabItem usamos os seguintes controles:
|
|
Leiaute |
O código XAML do arquivo Window1.xaml é visto a seguir:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Custom="http://schemas.microsoft.com/wpf/2008/toolkit" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="CRUDXmlDbWPF.Window1" Title="Alunos" Height="400" Width="640" mc:Ignorable="d" ResizeMode="CanMinimize"> <Grid> <Grid.Background> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FF7C51E1" Offset="1"/> <GradientStop Color="White"/> </LinearGradientBrush> </Grid.Background> <TabControl Background="{x:Null}"> <TabItem Header="Ver Todos"> <Grid> <Custom:DataGrid x:Name="ViewDataGrid" IsReadOnly="True" GridLinesVisibility="Horizontal" AutoGenerateColumns="False" d:LayoutOverrides="Width, Height" Background="{x:Null}"> <Custom:DataGrid.Columns> <Custom:DataGridTextColumn Header="Nome" Binding="{Binding Path=Nome}" Width="200"/> <Custom:DataGridTextColumn Header="Curso" Binding="{Binding Path=Curso}" Width="100"/> <Custom:DataGridTextColumn Header="Email" Binding="{Binding Path=Email}" Width="250"/> <Custom:DataGridTextColumn Header="Matricula" Binding="{Binding Path=Matricula}" Width="70"/> </Custom:DataGrid.Columns> </Custom:DataGrid> </Grid> </TabItem> <TabItem Header="Incluir Novo"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.217*"/> <ColumnDefinition Width="0.783*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="0.083*"/> <RowDefinition Height="0.086*"/> <RowDefinition Height="0.147*"/> <RowDefinition Height="0.146*"/> <RowDefinition Height="0.09*"/> <RowDefinition Height="0.095*"/> <RowDefinition Height="0.353*"/> </Grid.RowDefinitions> <TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Text="Nome :" TextWrapping="Wrap" Margin="0,0,5,0" Grid.Row="1"/> <TextBlock HorizontalAlignment="Right" Margin="0,0,5,0" VerticalAlignment="Center" Text="Curso:" TextWrapping="Wrap" Grid.Row="2"/> <TextBlock HorizontalAlignment="Right" Margin="0,0,5,0" VerticalAlignment="Center" Grid.Row="3" Text="Email:" TextWrapping="Wrap"/> <TextBlock HorizontalAlignment="Right" Margin="0,0,5,0" VerticalAlignment="Center" Text="Matricula :" TextWrapping="Wrap" Grid.Row="4"/> <TextBox x:Name="txtNome" Margin="0,0,5,0" Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Height="23"/> <TextBox x:Name="txtCurso" Margin="0,1,5,1" Grid.Column="1" Grid.Row="2" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> <TextBox x:Name="txtEmail" Margin="0,1,5,1" Grid.Column="1" Grid.Row="3" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> <ComboBox x:Name="cmbMatricula" Margin="0" HorizontalAlignment="Left" Width="75" Grid.Column="1" Grid.Row="4" Height="20" VerticalAlignment="Center"/> <Button x:Name="btnIncluir" Click="btnIncluir_Click" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Center" Width="100" Height="25" Content="Incluir " Grid.Column="1" Grid.Row="5"/> </Grid> </TabItem> <TabItem Header="Atualizar"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="109"/> <ColumnDefinition Width="495"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="0.083*"/> <RowDefinition Height="0.086*"/> <RowDefinition Height="0.147*"/> <RowDefinition Height="0.146*"/> <RowDefinition Height="0.09*"/> <RowDefinition Height="0.095*"/> <RowDefinition Height="0.353*"/> </Grid.RowDefinitions> <TextBlock Margin="36,0,5,0" VerticalAlignment="Center" Grid.Row="1" Text="Nome:" TextWrapping="Wrap" Grid.Column="1" d:LayoutOverrides="Width" Width="68" /> <TextBlock Margin="37,0,5,0" VerticalAlignment="Center" Text="Curso:" TextWrapping="Wrap" Grid.Row="2" Grid.Column="1" d:LayoutOverrides="Width" Width="67" /> <TextBlock Margin="6,0,5,0" VerticalAlignment="Center" Grid.Row="3" Text="Email:" TextWrapping="Wrap" Grid.Column="1" d:LayoutOverrides="Width" Width="36" /> <TextBlock Margin="36,5,5,8" VerticalAlignment="Center" Text="Matrícula" TextWrapping="Wrap" Grid.Row="4" Grid.Column="1" d:LayoutOverrides="Width" Width="68" Height="17" /> <TextBox x:Name="txtNomeAtualiza" Margin="0,0,5,0" VerticalAlignment="Center" Height="23" Grid.Column="2" Grid.Row="1"/> <TextBox x:Name="txtCursoAtualiza" Margin="0,1,5,1" Grid.Column="2" Grid.Row="2" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> <TextBox x:Name="txtEmailAtualiza" Margin="0,1,5,1" Grid.Column="2" Grid.Row="3" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible"/> <ComboBox x:Name="cmbMatriculaAtualiza" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Center" Width="75" Height="20" Grid.Column="2" Grid.Row="4"/> <Button x:Name="btnAtualizar" Click="btnAtualizar_Click" HorizontalAlignment="Left" Margin="0" VerticalAlignment="Center" Width="100" Height="25" Content="Atualizar" Grid.Column="2" Grid.Row="5"/> <Button x:Name="btnDeletar" Click="btnDeletar_Click" Margin="108,0,188.819,0" VerticalAlignment="Center" Height="25" Content="Deletar" Grid.Column="2" Grid.Row="5" Width="100"/> <ListBox x:Name="lbAlunos" SelectionChanged="lbAlunos_SelectionChanged" Margin="0,8" Grid.RowSpan="7"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Nome}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </TabItem> </TabControl> </Grid> </Window> |
Definindo o código da aplicação
No arquivo Window1.xaml.cs vamos definir o código usado pela nossa aplicação.
Iniciamos com a declaração dos namespaces das classes usadas pela aplicação no início do arquivo:
using
System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Xml.Linq; using System.Collections.ObjectModel; using System.IO; using System.Xml; |
A seguir, logo após a declaração da janela Window definimos as variáveis globais usadas pela aplicação:
ObservableCollection<Alunos>
selectedList = new ObservableCollection<Alunos>(); List<Alunos> listaAlunos; List<string> listaAnos; Alunos alunosDel; string caminhoArquivoXML = @"c:\dados\Matricula.xml"; |
A classe ObservableCollection<T>
que fica no namespace System.Collections.ObjectModel, que
fornece notificações, quando a coleção é modificada, incluindo, alterando ou
mesmo excluindo algum item.
Logo a seguir temos a
inicialização das variáveis , a definição dos dados da
combobox e a carga dos dados:
public Window1() { InitializeComponent(); btnAtualizar.IsEnabled = false; btnDeletar.IsEnabled = false; listaAnos = new List<string> { "2005", "2006", "2007", "2008", "2009", "2010", "2011" }; cmbMatricula.ItemsSource = listaAnos; cmbMatriculaAtualiza.ItemsSource = listaAnos; carregaDados(); } |
A rotina carregaDados() tem o seguinte código:
void carregaDados() { try { XDocument doc = XDocument.Load(caminhoArquivoXML); listaAlunos = (from aluno in doc.Descendants("Aluno") orderby aluno.Element("Nome").Value select new Alunos { Nome = aluno.Element("Nome").Value, Curso = aluno.Element("Curso").Value, Email = aluno.Element("Email").Value, Matricula = aluno.Element("Matricula").Value, }).ToList(); lbAlunos.ItemsSource = listaAlunos; ViewDataGrid.ItemsSource = listaAlunos; } catch { MessageBox.Show("Erro ao acessar dados"); } } |
Neste código usamos uma consulta para obter os valores do arquivo XML e exibi-los no controle ListBox e no DataGrid via propriedade ItemsSource.
No evento Click do botão Incluir temos o código que inclui uma informação no arquivo XML:
private void btnIncluir_Click(object sender, RoutedEventArgs e) { string nome = txtNome.Text.Trim(); string matricula; if (cmbMatricula.SelectedIndex != -1) { matricula = cmbMatricula.SelectedValue.ToString(); } else { matricula = "2010"; } string curso = txtCurso.Text.Trim(); string email = txtEmail.Text.Trim(); bool isUpdate = false; if (nome.Equals(string.Empty)) nome = "não informado"; if (matricula.Equals(string.Empty)) matricula = "2011"; if (curso.Equals(string.Empty)) curso = "indefinido"; if (email.Equals(string.Empty)) email = "não informado"; Alunos novoAluno = new Alunos { Nome = nome, Curso = curso, Email = email, Matricula = matricula, }; WriteToXmlFile(novoAluno, isUpdate); txtNome.Text = string.Empty; txtCurso.Text = string.Empty; txtEmail.Text = string.Empty; cmbMatricula.SelectedIndex = -1; carregaDados(); } |
Neste código atribuímos os valores para as propriedades do objeto novoAluno que é uma instância da classe Alunos e chamamos o método WriteToXmlFIle passando o objeto novoAluno para ser persistido no arquivo XML e em seguida limpamos os controles e carregamos os dados novamente.
No evento Click do botão Atualizar temos o código que permite alterar uma informação no arquivo XML:
private void btnAtualizar_Click(object sender, RoutedEventArgs e) { if (lbAlunos.SelectedIndex != -1) { string nome = txtNomeAtualiza.Text; string curso = txtCursoAtualiza.Text; string email = txtEmailAtualiza.Text; string matricula = cmbMatriculaAtualiza.SelectedValue.ToString(); bool isUpdate = true; if (nome.Equals(string.Empty)) nome = "não informado"; if (matricula.Equals(string.Empty)) matricula = "2009"; if (curso.Equals(string.Empty)) curso = "indefinido"; if (email.Equals(string.Empty)) email = "não informado"; Alunos atualizaAluno = new Alunos { Nome = nome, Curso = curso, Email = email, Matricula = matricula, }; WriteToXmlFile(atualizaAluno, isUpdate); lbAlunos.SelectedIndex = -1; btnAtualizar.IsEnabled = false; btnDeletar.IsEnabled = false; carregaDados(); } } |
O procedimento é o mesmo do código anterior, a diferença é que definimos a variável IsUpdate como false para realizar uma atualização nos dados.
No evento Click do botão Deletar temos o código que exclui uma informação do arquivo XML:
private void btnDeletar_Click(object sender, RoutedEventArgs e) { if (alunosDel != null) { if (System.Windows.MessageBox.Show("Deseja excluir este aluno ?", "Confirmar Exclusão", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { XDocument doc = XDocument.Load(caminhoArquivoXML); foreach (var item in doc.Descendants("Aluno")) { if (item.Element("Nome").Value == alunosDel.Nome) { ((XElement)item.Element("Nome")).Parent.Remove(); doc.Save(caminhoArquivoXML); break; } } carregaDados(); alunosDel = null; lbAlunos.SelectedIndex = -1; btnDeletar.IsEnabled = false; } else { alunosDel = null; lbAlunos.SelectedIndex = -1; btnDeletar.IsEnabled = false; } } } |
A rotina WriteToXmlFile é quem realiza a persistência das operações no arquivo XML e tem o seguinte código:
void WriteToXmlFile(Alunos alunos, bool isUpdate) { if (!isUpdate) { FileStream fs = new FileStream(caminhoArquivoXML, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(fs); fs.Close(); XmlElement novoAluno = xmlDoc.CreateElement("Aluno"); XmlElement nome = xmlDoc.CreateElement("Nome"); nome.InnerText = alunos.Nome; novoAluno.AppendChild(nome); XmlElement curso = xmlDoc.CreateElement("Curso"); curso.InnerText = alunos.Curso; novoAluno.AppendChild(curso); XmlElement email = xmlDoc.CreateElement("Email"); email.InnerText = alunos.Email; novoAluno.AppendChild(email); XmlElement matricula = xmlDoc.CreateElement("Matricula"); matricula.InnerText = alunos.Matricula; novoAluno.AppendChild(matricula); xmlDoc.DocumentElement.InsertAfter(novoAluno,xmlDoc.DocumentElement.LastChild); FileStream fsxml = new FileStream(caminhoArquivoXML, FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite); xmlDoc.Save(fsxml); fsxml.Close(); } else { XDocument doc = XDocument.Load(caminhoArquivoXML); foreach (var item in doc.Descendants("Aluno")) { if (item.Element("Nome").Value == alunosDel.Nome) { item.Element("Nome").SetValue(alunos.Nome); item.Element("Curso").SetValue(alunos.Curso); item.Element("Email").SetValue(alunos.Email); item.Element("Matricula").SetValue(alunos.Matricula); doc.Save(caminhoArquivoXML); break; } } } } |
O evento SelectionChanged do controle ListBox é exibido a seguir:
private void lbAlunos_SelectionChanged(object sender, SelectionChangedEventArgs e) { selectedList.Clear(); if (this.lbAlunos.SelectedItem is Alunos) { selectedList.Add(((Alunos)this.lbAlunos.SelectedItem)); alunosDel = (Alunos)this.lbAlunos.SelectedItem; } foreach (var item in selectedList) { txtNomeAtualiza.Text = item.Nome; txtCursoAtualiza.Text = item.Curso; txtEmailAtualiza.Text = item.Email; cmbMatriculaAtualiza.SelectedValue = item.Matricula; } btnAtualizar.IsEnabled = true; btnDeletar.IsEnabled = true; } |
Ele limpa a lista e a seguir preenche a lista com os dados do aluno.
Executando o projeto podemos ver nas figuras abaixo cada uma das opções sendo usada na aplicação:
1- Exibição dos dados no DataGrid:
2- Inclusão de dados
3- Alteração de dados
E assim vimos que a WPF possui poderosos recursos para tratar arquivo XML usando o recurso do DataBinding.
Pegue o projeto completo aqui: CRUDXmlDbWPF.zip
Eu sei é apenas WPF, mas eu gosto...
"Passará o céu e a terra, mas as minhas palavras jamais passarão." (Mateus 24:35)
Referências: