C# - Vinculando uma fonte de dados XML a um controle TreeView
Imagine o seguinte cenário:
Você trabalha em uma grande empresa que recebe dados das filiais para serem consolidados. Os dados sempre estiveram em arquivos texto que você tratava e consolidava.
A partir do mês que vem os dados passarão a vir no formato XML e você terá que acessar e exibir estas informações.
Você receberá dois arquivos : um arquivo XML contendo os dados propriamente ditos e um arquivo XSD usado para validar o arquivo XML.
Não
devemos confundir métodos para validar um documento XML
com esquemas usados para esta finalidade. Atualmente
existem três tipos de schemas usados para validar XML: DTD
(Document Type Definition), XDR Schemas (XML-Data
Reduced) e XSD Schemas (XML-Schema
Definition)
|
O arquivo XML chamado de estoque.xml possui a seguinte estrutura:
<?xml
version="1.0" standalone="yes"?> <NewDataSet> <Produtos> <ProdutoID>355</ProdutoID> <CategoriaID>16</CategoriaID> <NumeroModelo>RU007</NumeroModelo> <NomeModelo>Rain Racer 2000</NomeModelo> <ImagemProduto>image.gif</ImagemProduto> <CustoUnitario>1499.99</CustoUnitario> <Descricao>Looks like an ordinary bumbershoot, but don't be fooled! Simply place Rain Racer's tip on the ground and press the release latch.</Descricao> </Produtos> ................. <Produtos> </Produtos> <Categorias> <CategoriaID>14</CategoriaID> <NomeCategoria>Communications</NomeCategoria> </Categorias> ....................... <Categorias> <CategoriaID>20</CategoriaID> <NomeCategoria>General</NomeCategoria> </Categorias> </NewDataSet> |
Este arquivo contém informações sobre produtos e categorias e o arquivo estoque.xsd que irá validar este arquivo e definir a sua estrutura e o relacionamento entre as tabelas possui o seguinte conteúdo:
<?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="Produtos"> <xs:complexType> <xs:sequence> <xs:element name="ProdutoID" msdata:ReadOnly="true" msdata:AutoIncrement="true" type="xs:int" /> <xs:element name="CategoriaID" type="xs:int" /> <xs:element name="NumeroModelo" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="50" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="NomeModelo" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="50" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ImagemProduto" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="50" /> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="CustoUnitario" type="xs:decimal" /> <xs:element name="Descricao" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="3800" /> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Categorias"> <xs:complexType> <xs:sequence> <xs:element name="CategoriaID" msdata:ReadOnly="true" msdata:AutoIncrement="true" type="xs:int" /> <xs:element name="NomeCategoria" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="50" /> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//Produtos" /> <xs:field xpath="ProdutoID" /> </xs:unique> <xs:unique name="Categorias_Constraint1" msdata:ConstraintName="Constraint1" msdata:PrimaryKey="true"> <xs:selector xpath=".//Categorias" /> <xs:field xpath="CategoriaID" /> </xs:unique> </xs:element> </xs:schema> |
Seu objetivo será 'destrinchar' estes arquivos, obter as informações e exibi-las em uma controle TreeView em uma aplicação Windows Forms.
Elementar não é mesmo ???
No arquivo estoque.xsd temos a definição de um dataset contendo as tabelas Categorias e Produtos e do relacionamento entre elas enquanto que no arquivo estoque.xml temos os dados.
A aplicação Windows Forms deverá exibir os dados conforme a figura abaixo:
Em um controle TreeView temos
exibidos as categorias e os respectivos produtos
Ao selecionar um produto é exibido em um controle Label a direita a sua descrição. |
E para terminar a fase de definições, você deve usar a linguagem C#.
Eu vou usar o Visual Studio 2010 beta 2 (estou usando e abusando) e criar um projeto Windows Forms Application (Menu File -> New Project) usando a linguagem C# com o nome TreeViewDataBinding;
No formulário padrão form1.cs defina o leiaute conforme mostrado na figura abaixo:
Agora no formulário form1.cs defina o namespace System.Data pois vamos trabalhar com objetos Table, DataSet, DataRow, etc.;
using System.Data;
No formulário vamos criar também algumas classes para gerenciar as informações que serão obtidas a partir do arquivo XML e XSD.
Eu poderia ter criado as classes em um arquivo separado (seria mais aconselhável) mas resolvi criar no formulário mesmo para mostrar que podemos usar este recurso.
A seguir temos o código das classes:
public class ProdutoDataBase { public class Tabelas { //define as tabelas que iremos usas public const string Produto = "Produtos"; public const string Categoria = "Categorias"; } public class ProdutoCampo { //define os campos dos produtos que serão exibidos public const string Nome = "NomeModelo"; public const string Descricao = "Descricao"; } public class CategoriaCampo { //define o campo da categoria que será exibido public const string Nome = "NomeCategoria"; } //define o dataSet e o DataRelation para o relacionamento das tabelas private DataSet dsEstoque; DataRelation relCategoriaProduto; public ProdutoDataBase() { //cria uma instância do DataSet dsEstoque = new DataSet(); try { //lê o esquema e o arquivo XML que é a fonte de dados dsEstoque.ReadXmlSchema(Application.StartupPath + "\\estoque.xsd"); dsEstoque.ReadXml(Application.StartupPath + "\\estoque.xml"); // Define o relacionamento entre Categorias e Produtos relCategoriaProduto = new DataRelation("Prod_Cat", dsEstoque.Tables["Categorias"].Columns["CategoriaID"], dsEstoque.Tables["Produtos"].Columns["CategoriaID"]); dsEstoque.Relations.Add(relCategoriaProduto); } catch (Exception ex) { MessageBox.Show(" Erro - A aplicação será encerrada : " + ex.Message); Application.Exit(); } } //obtem a tabela Categorias public DataTable getCategorias() { return dsEstoque.Tables["Categorias"]; } //obtem o produto relacionado com a categoria public DataRow[] getProdutosNaCategoria(DataRow rowParent) { return rowParent.GetChildRows(relCategoriaProduto); } //exibe a descrição do produto selecionado public string getExibeTexto(DataRow row) { string text = ""; switch (row.Table.TableName) { case Tabelas.Produto: text = "ID: " + row[0] + "\n"; text += "Nome: " + row[ProdutoCampo.Nome] + "\n\n"; text += row[ProdutoCampo.Descricao]; break; } return text; } } |
Na classe ProdutoDataBase temos definidos as seguintes classes:
Nesta classe estamos acessando os arquivos XML e XSD usando do método ReadXML do objeto DataSet além de dar o suporte para acessar os dados do arquivo XML.
Agora no início do formulário vamos criar uma instância dessa classe para usar no acesso e exibição do dados.
private ProdutoDataBase DataClass = new ProdutoDataBase();
A seguir no evento Load do formulário temos o código que acessa os dados no XML da tabela Categorias e as exibe no controle TreeView;
private void Form1_Load(object sender, System.EventArgs e) { TreeNode noPai; foreach (DataRow row in DataClass.getCategorias().Rows) { // Incluir o Nó Categoria noPai = treeDB.Nodes.Add(row[ProdutoDataBase.CategoriaCampo.Nome].ToString()); noPai.ImageIndex = 0; // Armazena a informação sobre a Categoria noPai.Tag = row; // Inclui um Nó noPai.Nodes.Add("*"); } } |
A seguir no evento BeforeExpand do controle TreeView temos o código que armazena a informação sobre o produto:
private void treeDB_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) { TreeNode nodeSelected, nodeChild; nodeSelected = e.Node; if (nodeSelected.Nodes[0].Text == "*") { // Limpa o Nó * nodeSelected.Nodes.Clear(); foreach (DataRow row in DataClass.getProdutosNaCategoria((DataRow)nodeSelected.Tag)) { nodeChild = nodeSelected.Nodes.Add(row[ProdutoDataBase.ProdutoCampo.Nome].ToString()); // Armazena a informação sobre Produto nodeChild.Tag = row; nodeChild.ImageIndex = 1; nodeChild.SelectedImageIndex = 1; } } } |
No evento AfterSelect do TreeView temos o código que exibe a informação sobre o produto no controle Label - lblinfo:
private void treeDB_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e) { lblInfo.Text = DataClass.getExibeTexto((DataRow)e.Node.Tag); } |
O código a seguir fecha a aplicação:
private void cmdClose_Click(object sender, System.EventArgs e) { this.Close(); } |
Dessa forma exibimos os dados de um arquivo XML em um controle TreeView.
Pegue o projeto completo aqui : TreeViewDataBinding.zip
Eu sei é apenas C#, mas eu gosto...
Referências: