C# - Operações Básicas com XML
Neste artigo eu vou mostrar as operações básicas usando arquivos XML em aplicações Windows Forms usando a linguagem C#.
Conceitos básicos - Teoria
O esquema de um DataSet (suas tabelas, colunas, relações e restrições) pode ser definido por meio de programação, criada pelos métodos Fill ou FillSchema de um DataAdapter, ou carregado a partir de um documento XML.
Para carregar as informações do esquema do DataSet a partir de um documento XML, você pode usar tanto o método ReadXmlSchema como o método InferXmlSchema do DataSet.
Para carregar o esquema de um DataSet a partir de um documento XML, sem carregar todos os dados, você pode usar o método ReadXmlSchema do DataSet. O método ReadXmlSchema cria um esquema DataSet definido usando o esquema - XML Schema Definition(XSD).
O método ReadXmlSchema recebe um único argumento de um nome de arquivo, um stream, ou um XmlReader que contém o documento XML a ser carregado. O documento XML pode conter apenas o esquema, ou pode conter o esquema inline com elementos XML que contêm dados.
O conteúdo de um DataSet pode ser criado a partir de um documento ou stream XML.
Para preencher um DataSet com dados de XML, usamos o método ReadXml do objeto DataSet. O método ReadXml vai ler um arquivo, um stream, ou um XmlReader, e toma como argumentos a fonte do XML mais um argumento opcional XmlReadMode.
O método ReadXml lê o conteúdo do documento ou stream XML e carrega o DataSet com dados. Ele também irá criar o esquema relacional do DataSet dependendo do XmlReadMode especificado e se um esquema relacional já existe ou não.
Com base neste conhecimento vamos mostrar alguns exemplos de aplicações Windows Forms usando a linguagem C#.
Nos exemplos usados neste artigo eu vou utilizar como fonte de dados um arquivo XML e um arquivo XSD.
Obs: XML Schema é uma alternativa ao DTD baseada em XML. Um esquema XML descreve a estrutura de um documento XML. A linguagem XML Schema também é chamada de XML Schema Definition (XSD).
Estes arquivos estão localizados na pasta bin/Debug da aplicação para facilitar o acesso e distribuição em tempo de testes.
Apenas para clarear o entendimento exibo a seguir uma parte do conteúdo de cada arquivo :
<?xml version="1.0" standalone="yes"?> <NewDataSet> <Products> <ProductID>355</ProductID> <CategoryID>16</CategoryID> <ModelNumber>RU007</ModelNumber> <ModelName>Rain Racer 2000</ModelName> <ProductImage>image.gif</ProductImage> <UnitCost>1499.99</UnitCost> <Description>Looks like an ordinary bumbershoot, but don't be fooled! Simply place Rain Racer's tip on the ground and press the release latch. Within seconds, this ordinary rain umbrella converts into a two-wheeled gas-powered mini-scooter. Goes from 0 to 60 in 7.5 seconds - even in a driving rain! Comes in black, blue, and candy-apple red.</Description> </Products> <Products> <ProductID>356</ProductID> <CategoryID>20</CategoryID> .......... .......... <Categories> <CategoryID>19</CategoryID> <CategoryName>Tools</CategoryName> </Categories> <Categories> <CategoryID>20</CategoryID> <CategoryName>General</CategoryName> </Categories> </NewDataSet> |
Arquivo store.xml |
<?xml version="1.0" standalone="yes"?> <xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="NewDataSet" msdata:IsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Products"> <xs:complexType> <xs:sequence> <xs:element name="ProductID" msdata:ReadOnly="true" msdata:AutoIncrement="true" type="xs:int" /> <xs:element name="CategoryID" type="xs:int" /> <xs:element name="ModelNumber" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="50" /> </xs:restriction> </xs:simpleType> </xs:element> ........... ........... <xs:unique name="Categories_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//Categories" /> <xs:field xpath="CategoryID" /> </xs:unique> </xs:element> </xs:schema> |
Arquivo
store.xsd Arquivos XSD (XML Schema
Definition) são usados para descrever o formato/padrão
que um arquivo XML deve seguir, ou seja, ele tem que
indicar quais nodes (<node1><subnode1/></node1>)
ele pode conter, quais subnodes e atributos esses nodes
podem ter, e muito mais. |
Da Teoria para a Prática
Vamos agora à parte prática usando os conceitos apresentados.
Em todos os exemplos irei usar o Visual C# 2010 Express Edition criando uma solução (File-> New Project) com o nome AcessoXML;
1- Preenchendo um ListBox com a fonte de dados XML
Vamos preencher um controle ListBox com as informações XML exibindo a informação ModelName da tabela Products.
Altere o nome do formulário form1.cs para frmListBox.cs e inclua no formulário, a partir da ToolBox, um controle ListBox (name=lstDadosXML) e um controle Button (name= btnPreencherListBox) conforme o leiaute da figura 1.0 abaixo:
Figura 1.0 |
Figura 2.0 |
No evento Click do botão de comando btnPreencherListBox digite o código a seguir:
private void btnPreencherListBox_Click(object sender, EventArgs e) { DataSet dsStore = new DataSet(); dsStore.ReadXmlSchema(Application.StartupPath + "\\store.xsd"); dsStore.ReadXml(Application.StartupPath + "\\store.xml"); lstDadosXML.DataSource = dsStore.Tables["Products"]; lstDadosXML.DisplayMember = "ModelName"; } |
No código acima estamos definindo um novo DataSet e usando os métodos ReadXmlSchema e ReadXml para ler as informações da tabela Products e exibir o nome da tag ModelName;
O resultado obtido é o da figura 2.0 acima.
2- Preenchendo dois ListBoxes com a fonte de dados XML e visualização Master Detail
Vamos agora preencher dois controles ListBox onde em um vamos exibir as informações da tabela Categorias (Categories) e no outro as informações da tabela Produtos(Products) relacionados;
Vamos incluir um novo formulário no projeto, menu Project-> Add Windows Forms com onome frmMestreDetalhes.cs;
A seguir vamos incluir dois controles ListBox no formulário um para exibir as categorias (name=lstCategorias) e outro para exibir os produtos relacionados (name=lstProdutos);
Vamos incluir também um controle Button (name=btnCarregarXML) conforme o leiaute abaixo:
No início do formulário vamos declarar as variáveis para a BindingManagerBase e para o DataSet que iremos usar para preencher os controles;
private
BindingManagerBase categoryBinding;
private DataSet dsStore = new DataSet();
Cada objeto Binding se comunica com um CurrencyManager ou PropertyManager. As classes CurrencyManager e PropertyManager são derivadas da classe base BindingManagerBase.
O objetivo da classe BindingManagerBase é manter a concorrência entre a fonte de dados e o controle. Das duas classes a classe CurrencyManager é usada quando a fonte de dados implementa a interface IList ( DataView, DataSet, ArrayList,etc.)
Após isso vamos incluir o código abaixo no evento Click do botão de comando - btnCarregarXML:
private void btnCarregarXML_Click(object sender, EventArgs e) { //acessa os arquivos XML e XSD na basta bin\Debug dsStore.ReadXmlSchema(Application.StartupPath + "\\store.xsd"); dsStore.ReadXml(Application.StartupPath + "\\store.xml"); //carrega os dados da tabela Categories ,tag CategoryName lstCategorias.DataSource = dsStore.Tables["Categories"]; lstCategorias.DisplayMember = "CategoryName"; //carrega os dados da tabela Products ,tag ModelName lstProdutos.DataSource = dsStore.Tables["Products"]; lstProdutos.DisplayMember = "ModelName"; categoryBinding = this.BindingContext[dsStore.Tables["Categories"]]; //define o delegate categoryBinding.PositionChanged += new EventHandler(Binding_PositionChanged); // Invoca o método para atualizar a tabela filha na inicialização Binding_PositionChanged(null, null); } |
A seguir vamos definir o código do evento delegate que irá filtrar os produtos pela categoria selecionada:
private void Binding_PositionChanged(object sender, System.EventArgs e) { string filtro; DataRow selectedRow; // Encontra a linha da categoria atual selectedRow = dsStore.Tables["Categories"].Rows[categoryBinding.Position]; // Cria um filtro usando o codigo da categoria - CategoryID. filtro = "CategoryID='" + selectedRow["CategoryID"].ToString() + "'"; // Modifica a view na tabela product dsStore.Tables["Products"].DefaultView.RowFilter = filtro; } |
Executando o projeto temos o resultado abaixo:
Obs: Para executar o formulário frmMestreDetalhes altere no programa Program.cs linha que chama o formulário para: Application.Run(new frmMestreDetalhes());
3- DataBinding com Edição de dados XML
Vamos agora mostrar como podemos realizar a vinculação dos dados XML em controles de formulário Windows Forms e permitir a edição de dados de forma a alterar os dados das fontes XML.
No menu Project clique em Add Windows Forms e inclua um novo formulário Windows com o nome igual a frmDataBindingEditavel.cs;
A seguir vamos incluir neste formulário os seguintes controles:
- 1
Controle Combobox - name = cboModeloNome;
- 1 Controle GroupBox - usado apenas para agrupar os controles
TextBox;
- 4 Controles TextBox : txtModeloNome, txtModeloNumero,
txtCustoUnitario e txtDescricao
- 1 Controle Button - btnCarregarXML
O leiaute do formulário deve estar conforme a figura abaixo:
No evento Click do botão de comando btnCarregarXML inclua o código a seguir:
private void btnCarregarXML_Click(object sender, EventArgs e) { DataSet dsStore = new DataSet(); dsStore.ReadXmlSchema(Application.StartupPath + "\\store.xsd"); dsStore.ReadXml(Application.StartupPath + "\\store.xml"); cboModeloNome.DataSource = dsStore.Tables["Products"]; cboModeloNome.DisplayMember = "ModelName"; txtModeloNome.DataBindings.Add("Text", dsStore.Tables["Products"], "ModelName"); txtModeloNumero.DataBindings.Add("Text", dsStore.Tables["Products"], "ModelNumber"); txtCustoUnitario.DataBindings.Add("Text", dsStore.Tables["Products"], "UnitCost"); txtDescricao.DataBindings.Add("Text", dsStore.Tables["Products"], "Description"); } |
O código vincula os campos Texto("Text") usando a minha fonte de dados (dsStore) a cada campo da tabela que desejamos exibir no formulário.
Executando o projeto teremos o resultado abaixo:
Obs: Para executar o formulário frmDataBindingEditavel.cs altere no programa Program.cs linha que chama o formulário para: Application.Run(new frmDataBindingEditavel.cs());
Você notará que poderemos selecionar um registro e os dados exibidos nos controles serão sincronizados.
Qualquer alteração de dados feita no formulário será propagada para o XML.
4- Múltiplos DataBinding com Navegação
Agora vamos acessar a fonte de dados XML e realizar múltiplos binding e permitir a navegação.
No menu Project clique em Add Windows Forms e inclua um novo formulário Windows com o nome igual a frmNavegacao.cs;
Inclua os seguintes controles no formulário:
O leiaute do formulário é mostrado a seguir:
Vamos declarar a variável do tipo BindingManagerBase no início do formulário:
private BindingManagerBase storeBinding;
Agora no evento Load do formulário vamos incluir o código para acessar, carregar e vincular os dados XML aos controles do formulário:
private void frmNavegacao_Load(object sender, EventArgs e) { DataSet dsStore = new DataSet(); dsStore.ReadXmlSchema(Application.StartupPath + "\\store.xsd"); dsStore.ReadXml(Application.StartupPath + "\\store.xml"); cboNomeModelo.DataSource = dsStore.Tables["Products"]; cboNomeModelo.DisplayMember = "ModelName"; lblNumeroModelo.DataBindings.Add("Text",dsStore.Tables["Products"], "ModelNumber"); lblCustoUnitario.DataBindings.Add("Text",dsStore.Tables["Products"], "UnitCost"); lblDescricao.DataBindings.Add("Text", dsStore.Tables["Products"], "Description"); storeBinding = this.BindingContext[dsStore.Tables["Products"]]; storeBinding.PositionChanged += new EventHandler(Binding_PositionChanged); } |
Precisamos defnir o evento Binding_PositionChanged que controla a navegação conforme abaixo:
private void Binding_PositionChanged(object sender, System.EventArgs e) { if (storeBinding.Position == storeBinding.Count - 1) { btnProximo.Enabled = false; } else { btnProximo.Enabled = true; } if (storeBinding.Position == 0) { btnAnterior.Enabled = false; } else { btnAnterior.Enabled = true; } } |
Para concluir basta incluir o código nos botões de comando para navegar pelos dados:
1- Botão - btnProximo
private void btnProximo_Click(object sender, EventArgs e) { storeBinding.Position++; } |
2- Botão - btnAnterior
private void btnAnterior_Click(object sender, EventArgs e) { storeBinding.Position--; } |
Executando o projeto iremos obter o resultado a seguir:
Dessa forma temos a vinculação dos dados XML aos controles e permitimos também a navegação pelos registros;
Com isso mostrei como podemos acessar uma fonte de dados XML e realizar algumas tarefas com formulários Windows Forms usando o C#.
Pegue o projeto completo aqui: AcessoXML.zip
João 2:13
Estando próxima a páscoa dos judeus, Jesus subiu a Jerusalém.Referências:
Desvendando os segredos do Data Binding no VB.NET - Macoratti.net
VB.NET - Alterando , excluindo e atualizando dados - Macoratti.net