apostila c#
TRANSCRIPT
Programa de Formação .NET
Apostila Treinamento C#
2
Índice
Capítulo 1 – Introdução 9
Capítulo 2 – Visão Geral do .NET 9
Estratégia .NET ......................................................................................................................9
Tecnologias ............................................................................................................................11
Vantagens do .NET ................................................................................................................12
Desvantagens do .NET ..........................................................................................................13
Versões do Framework ..........................................................................................................13
Framework .NET Versão 1.0 (1.0.3705) 14
Framework .NET Versão 1.1 (1.1.4322) 14
Framework .NET Versão 2.0 (2.0.50727.42) 14
Funcionamento do Framework ......................................................................................15
A Máquina Virtual ...................................................................................................................15
Esquema de funcionamento do .NET. 16
Coleta de lixo (Garbage Collector) .........................................................................................17
Capítulo 3 – Visual Studio 2005 19
Objetivos..............................................................................................................................19
Conceitos de Solução e Projeto ....................................................................................19
Breve Introdução aos Diferentes Tipos de Projeto .....................................................20
Explorando as Janelas......................................................................................................22
Solution Explorer ....................................................................................................................22
Toolbox...................................................................................................................................23
Properties ...............................................................................................................................23
Server Explorer.......................................................................................................................24
Task List .................................................................................................................................24
Output .....................................................................................................................................25
Error List .................................................................................................................................25
Lab: Navegando na IDE ..................................................................................................25
Revisão.................................................................................................................................28
Capítulo 4 – Linguagem C# 29
Declaração de Variáveis.................................................................................................29
Apostila Treinamento C#
3
Case Sensitive.....................................................................................................................29
Tipos de variáveis...............................................................................................................29
Marcadores de bloco e finalizadores...........................................................................32
Símbolos e operadores lógico-aritméticos ..................................................................32
If...else...................................................................................................................................33
Laços While .........................................................................................................................33
Laços for ..............................................................................................................................33
Laços do...while .................................................................................................................34
Switch..Case .......................................................................................................................34
Loop foreach......................................................................................................................34
Vetores (arrays) ..................................................................................................................35
Funções................................................................................................................................35
Estrutura de um programa C# .......................................................................................36
Conversão de tipos (cast) ...............................................................................................36
Strings....................................................................................................................................37
Revisão.................................................................................................................................37
Capítulo 5 – Orientação a Objetos com C# 38
Objetivos..............................................................................................................................38
Visão Geral..........................................................................................................................38
Classes e Objetos...............................................................................................................39
Agora que criamos a classe porta, como fazemos para criar um objeto do tipo
Porta? 40
Atributos e Propriedades .................................................................................................40
Métodos...............................................................................................................................41
New Keyword .....................................................................................................................42
Construtores e Destrutores...............................................................................................43
Lab: Trabalhando com Classes ......................................................................................44
Níveis de Acesso e Visibilidade.......................................................................................47
Public ......................................................................................................................................48
Private.....................................................................................................................................48
Protected ................................................................................................................................48
Internal....................................................................................................................................49
Protected Internal ...................................................................................................................49
Apostila Treinamento C#
4
Resumo dos Níveis ................................................................................................................49
Encapsulamento................................................................................................................50
Notação UML .....................................................................................................................50
Herança...............................................................................................................................51
Classe Abstrata e Classe Selada...........................................................................................53
Sobrescrita de Métodos ...................................................................................................54
Sobrecarga de Métodos .................................................................................................55
Acessando a classe pai – base e this ....................................................................................55
Polimorfismo........................................................................................................................55
Lab: Trabalhando com Herança ...................................................................................57
Interface ..............................................................................................................................57
Métodos, Atributos e Propriedades Estáticas..............................................................58
Classes Parciais ..................................................................................................................59
Revisão.................................................................................................................................60
Capítulo 6 – Tópicos Avançados 61
Objetivos..............................................................................................................................61
Namespaces ......................................................................................................................61
Outro uso para Using .............................................................................................................63
São idênticas! 63
Referências .........................................................................................................................64
Lab: Trabalhando com Namespace e Referências..................................................65
Bibliotecas do Framework .NET 2.0 ................................................................................67
O namespace System ............................................................................................................67
Nota 68
O namespace System.Text ....................................................................................................68
O namespace System.Collections .........................................................................................68
Trabalhando com HashTables 69
O namespace System.IO .......................................................................................................70
Escrevendo um arquivo 70
Lendo um arquivo 70
Tarefas recorrentes............................................................................................................70
Acessando o diretório da aplicação .......................................................................................70
Verificando o nome do computador .......................................................................................70
Apostila Treinamento C#
5
string NomeComp = System.Environment.MachineName; 70
string nDNS = System.Net.Dns.GetHostByName("LocalHost").HostName; 71
Verificando a versão do sistema operacional ........................................................................71
Verificando o usuário que está rodando o programa.............................................................71
string usr = System.Environment.UserName; 71
Tratamento de Erros – Uso de Try/Catch/Finally .........................................................71
Tratamento estruturado de erros – try/catch..........................................................................71
Exceções personalizadas.......................................................................................................74
Disparando exceptions...........................................................................................................74
Finally .....................................................................................................................................74
Revisão.................................................................................................................................75
Capítulo 7 – XML 76
Objetivos..............................................................................................................................76
O que é XML?.....................................................................................................................76
Elementos de um Documento XML...............................................................................77
Declaração .............................................................................................................................77
Tags........................................................................................................................................77
Atributos .................................................................................................................................79
Comentários ...........................................................................................................................79
XML Bem Formado ................................................................................................................79
Definindo a Estrutura do Documento ...........................................................................79
Revisão.................................................................................................................................81
Capítulo 8 – ADO.NET 82
Objetivos..............................................................................................................................82
O que é o ADO.NET...........................................................................................................82
Providers do .NET................................................................................................................82
Modelo ADO.NET ...............................................................................................................83
Connection .............................................................................................................................83
Command ...............................................................................................................................83
DataReader ............................................................................................................................84
DataAdapter ...........................................................................................................................85
Criando comandos automaticamente: o CommandBuilder....................................................86
DataSet................................................................................................................................87
Nota 87
Apostila Treinamento C#
6
Populando e iterando por um DataSet ...................................................................................88
Filtrando dados em um DataSet.............................................................................................88
Procurando por uma informação em um DataSet..................................................................89
DataViews ..............................................................................................................................89
Nota 89
Atualizando o banco com informações do DataSet ...............................................................90
Acessando arquivos XML.................................................................................................91
Gravando arquivos XML a partir de um DataSet ...................................................................91
Lendo arquivos XML em um Dataset .....................................................................................92
Trabalhando com nulos ...................................................................................................93
Revisão.................................................................................................................................93
Capítulo 9 – Trabalhando com Windows Forms 94
Objetivos..............................................................................................................................94
Formulários MDI ..................................................................................................................94
Herança de formulários ..........................................................................................................95
Nota 95
User Controls .......................................................................................................................96
Adicionando um controle programaticamente........................................................................96
Disparando eventos de um controle.......................................................................................96
Lab: Criando um User Control.........................................................................................97
Respondendo a eventos de teclado .........................................................................100
Data Binding.....................................................................................................................100
DataSource...........................................................................................................................100
DataBinding ..........................................................................................................................102
BindingNavigator ..................................................................................................................102
Lab: Data Binding............................................................................................................103
DataGridView...................................................................................................................107
Populando um DataGridView ...............................................................................................108
Ativando a ordenação automática........................................................................................108
Ativando o auto-ajuste de linhas e colunas..........................................................................108
Renomeando as colunas......................................................................................................109
Formatando colunas.............................................................................................................109
Mudando o estilo de acordo com uma condição..................................................................109
Fazendo um DataGridView “zebrado”..................................................................................110
Lendo eventos de seleção ...................................................................................................110
Apostila Treinamento C#
7
Oferecendo uma lista de opções em um ListBox.................................................................111
Formulários Master/Detail ..............................................................................................112
DataRelation.........................................................................................................................112
Estratégia do Master/Detail ..................................................................................................113
Lab: Relacionamentos e Master-Detail ......................................................................113
Revisão...............................................................................................................................117
Capítulo 10 – Web Services 118
Objetivos............................................................................................................................118
Conceito: O que é um Web Service?.........................................................................118
Criando um Web Service...............................................................................................120
Consumindo um Web Service ......................................................................................125
Distribuindo um Web Service ........................................................................................127
Revisão...............................................................................................................................129
Capítulo 11 – Depuração, Debug e Trace 130
Objetivos............................................................................................................................130
Depurando uma aplicação..........................................................................................130
Breakpoints e condições ......................................................................................................132
Watch Window......................................................................................................................133
O QuickWatch ......................................................................................................................133
A janela Output.....................................................................................................................134
A janela Immediate...............................................................................................................134
As janelas Locals e Auto ......................................................................................................135
Debug e Trace .................................................................................................................135
Métodos do Debug e do Trace.............................................................................................135
Listeners ...............................................................................................................................136
Revisão...............................................................................................................................137
Capítulo 12 – Distribuição 138
Objetivos............................................................................................................................138
Tipos de setup suportados .............................................................................................138
Criando um projeto de setup .......................................................................................138
Personalizando o setup ..................................................................................................141
Seção File System................................................................................................................143
Seção Registry .....................................................................................................................144
Seção File Types..................................................................................................................144
Apostila Treinamento C#
8
Seção User Interface............................................................................................................145
Seções Custom Actions e Launch Conditions .....................................................................145
Criando um projeto de atualização ...........................................................................146
Click-once deploy...........................................................................................................147
Revisão...............................................................................................................................149
Apêndice A – Referências 150
Livros e Revistas ................................................................................................................150
Sites .....................................................................................................................................150
.NET e Visual C# ..................................................................................................................150
Microsoft ASP.NET – Site oficial da Microsoft sobre ASP.NET 150
MSDN Brasil – Outro site official da Microsoft, trata das plataformas de
desenvolvimento Microsoft 150
Visual C# Walkthroughs 150
Code Project 150
C# Reference 150
Windows Forms....................................................................................................................151
Introducing a New Data Grid 151
Windows Forms Demos 151
XML ......................................................................................................................................151
XML Tutorial 151
XML – Introdução 151
DTD Tutorial 151
XML Schema Tutorial 151
System.Xml Namespace 151
Acessando XML remoto e buscando informações com o Namespace
System.Xml.XPath 151
Migrando arquivos Textos delimitados para XML 151
Distribuição...........................................................................................................................152
Apostila Treinamento C#
9
Capítulo 1 – Introdução
Com este intuito, estão sendo desenvolvidos treinamentos, para preparar os
profissionais para este o novo conceito de desenvolvimento, que surge junto com o
.NET.
Para que os profissionais tenham condição de compreender esse novo universo
introduzido pelo .NET, esse Adoption Lab irá discutir os principais conceitos que
estão por trás deste. Faremos um tour pelo Visual Studio, e criaremos algumas
aplicações usando o C# como base. Terminaremos mostrando como distribuir as
aplicações desenvolvidas, e como planejar estratégias de migração.
Como a plataforma .NET é extremamente rica, e o tempo do curso é limitado, não
será possível cobrir tudo o que o .NET têm a oferecer. Como essa migração é uma
mudança de paradigmas, é necessário cobrir alguns dos aspectos mais
importantes da linguagem e do framework – como orientação a objetos, acesso a
dados através do ADO.NET, XML, Web Services. Procuramos, no material teórico,
dar um embasamento maior do que o que será visto em sala, para que o aluno
possa por iniciativa própria complementar o conhecimento adquirido em sala.
Por fim, esperamos com esse treinamento plantar uma semente, que instigue os
profissionais a buscar conhecer mais sobre esse assunto. Para auxiliá-los,
indicamos algumas referências aonde é possível iniciar a sua pesquisa.
Capítulo 2 – Visão Geral do .NET
Estratégia .NET A Microsoft vem constantemente evoluindo as tecnologias de desenvolvimento,
buscando integrar aplicações e tornar o desenvolvedor mais produtivo.
Com o aparecimento do DDE e OLE, a Microsoft permitiu a integração fácil entre
aplicações Office e programas desenvolvidos dentro do ambiente Windows.
Apostila Treinamento C#
10
O ActiveX veio no bojo da Internet, oferecendo para os programadores os
conceitos de componentização. A tecnologia COM trouxe maior liberdade de
desenvolvimento, e a COM+ introduziu um framework que permite escalabilidade,
transações e segurança.
Apesar dessas mudanças, ainda existia um grade vazio a ser preenchido. Era
custoso para um programador Visual Basic desenvolver componentes que
usassem todos os recursos da tecnologia COM, bem como fazer uso da API: a
documentação disponível era voltada a programadores C++, e a principal fonte de
informação eram livros que “traduziam” as interfaces da API para que os
programadores VB pudessem utilizar. Além disso, ainda havia o problema de tipos
de dados que as interfaces usavam e que não estavam disponíveis no VB.
Mesmo com os avanços trazidos pelas tecnologias citadas, os programadores
Windows ainda enfrentavam outro problema: o famigerado “DLL Hell” -
sobreposição de versões de DLLs em cujas novas versões haviam chamadas de
funções diferentes das anteriores, o que fazia com que programas que usavam a
versão mais antiga da DLL deixassem de funcionar.
Outra característica que foi perdida foi a capacidade de instalar uma aplicação
apenas com a cópia dos arquivos: tornou-se necessário o uso de instaladores que,
além de copiar os arquivos, ainda precisavam registrar os componentes no
Registro do Windows.
O .NET não só resolve tais problemas, mas também unifica a plataforma de
desenvolvimento e adiciona novas funcionalidades que são ou serão essenciais
para o desenvolvimento corporativo, como XML, Web Services, threading,
SmartClients e outros. Ele permite que diversas linguagens trabalhem juntas, de
forma transparente, para criar aplicações que são mais fáceis de fazer, gerenciar,
distribuir e integrar com outros sistemas.
Entre suas características, temos:
• Interoperabilidade – Como diversas bibliotecas COM já haviam sido
criadas, o .NET Framework provê meios de permitir interoperabilidade entre
o novo código e bibliotecas existentes.
Apostila Treinamento C#
11
• Common Runtime Engine – As linguagens de programação no .NET
Framework compilam o código em uma linguagem intermediária conhecida
com Common Intermediate Language (CIL). Durante a execução, essa o
arquivo no formato CIL é compilada pelo Just In Time Compiler (JIT) em
código nativo. A combinação desses conceitos é chamada Common
Language Runtime (CLR).
• Independência de Linguagem – O .NET Framework suporta o
desenvolvimento em múltiplas linguagens de programação. Isso é possível
porque todas as linguagens devem converter seu código em um código que
atenda aos requisitos da MSIL.
• Base Class Library (BCL) – A BCL (também conhecida como Framework
Class Library - FCL), é uma biblioteca de classes disponível a todas as
linguagens que utilizam o .NET Framework. Ele prove um conjunto de
classes que encapsulam funções comuns, como: acesso a arquivo,
interação com banco de dados, manipulaçãp XML, etc.
• Distribuição Simplificada – Instalação e distribuição de aplicações
Windows foi simplificada. Manipulação de Registry, distribuição de arquivos,
registro de DLLs foram quase completamente eliminadas pelos novos
mecanismos de distribuição do .NET.
• Segurança – O Framework .NET permite ao código rodar com diferentes
níveis de confiabilidade.
Tecnologias O .NET engloba diversas tecnologias:
• Windows Forms – Permite o desenvolvimento de aplicações para
Windows, incluindo elementos comuns de interface com o usuário;
• Windows Services – Permite o desenvolvimento de serviços para
Windows.
Apostila Treinamento C#
12
• ASP.NET – Foi a tecnologia escolhida pela Microsoft para substituir as
antigas páginas ASP. Permite ao desenvolvedor desenvolver aplicações
web, usando todas facilidades do BCL, além de diversos controles que
reduzem drásticamente o tempo de desenvolvimento de qualquer aplicação
Web.
• ADO.NET – O ADO.NET é a nova versão o ActiveX Data Objects (ADO)
para .NET. Ele simplifica o acesso a dados, e permite o acesso
desconectado.
• .NET Remoting – Corresponde a uma nova abordagem de comunicação
entre processos. Provê um rico e extensível framework para comunicação
entre diversas aplicações, rodando em diferentes domínios de aplicação.
• Web Services – Utilizando SOAP, XML, e os conceitos de Service
Oriented Architecture (SOA), um web services permite conexão entre
aplicações através da internet.
• Mobille Applications – Utilizando-se do Compact Framework, é possível
desenvolver de forma transparente aplicações para Pocket, SmartPhone, e
outros dispositivos compactos.
• Visual Studio Tools for Office (VSTO) – Com o VSTO, é possível
desenvolver aplicações que utilizem a riqueza da interface com o usuário
do Office, e o poder e a robustez das aplicações .NET.
Vantagens do .NET A plataforma .NET traz vantagens interessantes, tais como:
• Conjunto rico de bibliotecas com os mais variados usos;
• Controle de versão: fim do “DLL Hell”;
• Facilidade de desenvolvimento de aplicações desde as simples até as mais
complexas;
• Facilidade na instalação e na distribuição de aplicações;
Apostila Treinamento C#
13
• Orientada a objetos;
• ADO.NET trabalha com dados desconectados;
• Alta escalabilidade para ambientes de missão crítica;
• Interoperabilidade entre plataformas e componentes desenvolvidos em
outras linguagens .NET;
• Sintonizado com as últimas tecnologias;
• Solução sendo mundialmente adotada;
• Tecnologia baseada em máquina virtual;
• Rotina automática de “coleta de lixo” que permite remoção de variáveis e
objetos que não são mais utilizados;
• Novo ambiente de desenvolvimento acelerado (RAD).
As vantagens não acabam por aqui, seriam necessárias páginas e páginas
para conseguir chegar a uma lista mais completa. Mas a lista acima já é um
tanto agradável.
Desvantagens do .NET As maiores desvantagens do .NET, que devem ser vistas para se ter uma idéia do
esforço de migração:
• É um novo paradigma, e requer aprendizado de novas técnicas para fazer o
melhor uso da ferramenta;
• Requer a distribuição do framework;
• Em alguns casos requer reengenharia ou reescrita completa do código.
Versões do Framework Existem diferentes versões do Framework:
Apostila Treinamento C#
14
Framework .NET Versão 1.0 (1.0.3705)
Esta foi a primeira versão do Framework, liberado em 2002. Ele está disponível
como um pacote de distribuição, como um kit de desenvolvimento de software
(SDK), ou junto com o Visual Studio 2002.
Framework .NET Versão 1.1 (1.1.4322)
Este foi o primeiro grande upgrade, liberado em 2003. Ele está disponível como um
pacote de distribuição, como um SDK ou junto com o Visual Studio 2003. Além
disso, ele acompanha o Windows Server 2003.
Mudanças da versão 1.0
• Suporte nativo a aplicações mobile (na versão 1.0, era disponível como um
Add-On).
• Mudanças em Segurança – permite a assemblies Windows Form
executarem em um modo semi-confiável
• Suporte nativo a bancos ODBC e Oracle (na versão 1.0, era disponível
como um Add-On).
• .NET Compact Framework – Uma versão de Framework para aparelhos
como Pocket e SmartPhone.
• Suporte ao Internet Protocol v6 (IPv6).
• Numerosas mudanças em APIs.
Framework .NET Versão 2.0 (2.0.50727.42)
Nesta versão, liberada em Outubro de 2005, houveram alterações não só de
tecnologia, como de estratégia. Ele está disponível como um pacote de
distribuição, como um SDK ou junto com o Visual Studio 2005 ou o SQL Server
2005.
Mudanças da Versão 1.1
• Numerosas mudanças em APIs.
Apostila Treinamento C#
15
• Novos controles ASP.NET.
• Versão interna de IIS, permitindo desenvolver aplicações ASP.NET ou
Webservices sem a necessidade de ter o IIS instalado na máquina de
desenvolvimento.
• Suporte completo a 64-bits para as plataformas x64 e IA64.
• Suporte de linguagem para Generics diretamente na CLR.
Funcionamento do Framework
A Máquina Virtual O .NET baseia-se no conceito de máquina virtual, que serve como uma camada
que fica entre o código e o sistema operacional.
No conceito de máquina virtual, um programa pode ser portado entre várias
plataformas, desde que exista para elas uma máquina virtual capaz de compilar o
código. Além do pacote de instalação comum para Windows, a Microsoft provê o
Shared Source Common Language Infraestructure, que roda em Windows,
FreeBSD e Mac OS X; e como o CLI é um padrão aberto, existem diversos projetos
open source que surgiram para prover suporte para plataformas adicionais, sendo
o mais conhecido o Mono.
Todo código escrito em .NET (usando Visual Basic, C#, J# ou qualquer outra
linguagem disponível) é compilado para uma linguagem intermediária, chamada
CIL (ou MSIL). O código CIL é então distribuído e executado pelos clientes e
usuários da aplicação.
Os leitores mais atentos podem estar pensando: - Mas é idêntico ao que o VB 6 já
fazia: o código é “traduzido” em “tokens” que são interpretados. Aí é que reside a
grande diferença: o código .NET é compilado “just-in-time” pela máquina virtual, ou
seja, é gerado de fato código de máquina que é executado com extrema rapidez.
No VB 6, o código era interpretado pelo VBRun: a cada instrução o interpretador
comandava instruções para o processador mas se, por exemplo, uma função for
chamada repetidas vezes, ela serão reinterpretada a cada chamada que for feita.
Apostila Treinamento C#
16
As grandes vantagens de se fazer a compilação “just-in-time” são a compilação
específica para o hardware em que a Máquina Virtual roda, e a portabilidade, já
mencionada.
Como todo o código é “traduzido” para a linguagem intermediária, tornou-se fácil
padronizar tipos de dados, bibliotecas, classes, componentes, que passam agora a
ser especificamente .NET e facilmente utilizáveis em qualquer linguagem .NET,
seja ela C++, Visual Basic ou C#.
À esse conjunto de bibliotecas, deu-se o nome de Base Class Library (BCL) -
também conhecida como Framework Class Library (FCL). A BCL prove um
conjunto de classes que encapsulam funções comuns, como acesso a arquivo,
interação com banco de dados, manipulaçãp XML, etc.
O esquema abaixo detalha as camadas da Máquina Virtual:
Esquema de funcionamento do .NET.
As caixas superiores (C# e VB.NET) representam o código que é escrito por
programadores, como por exemplo MeuPrograma.cs (em C#) ou MeuPrograma.vb
(em Visual Basic . NET).
Apostila Treinamento C#
17
Para cada linguagem há um compilador específico, que “traduz” o código escrito
para a linguagem intermediária (CIL). O compilador específico do Visual Basic é o
vbc.exe (de Visual Basic Compiler). O código CIL gerado é então armazenado,
junto com outras informações, em um arquivo .exe ou .dll, dependendo do que for
parametrizado na chamada do vbc.exe. O Visual Studio já faz essa tarefa de
chamar o vbc.exe com os parâmetros corretos ao se usar qualquer uma das
opções de Build e Run.
A caixa CLR representa a Máquina Virtual (CLR de Common Language Runtime),
que é responsável pelo gerenciamento dos objetos .NET e pela chamada do
compilator “just-in-time” (JIT), que compilará o código em linguagem de máquina.
O código compilado ficará então em “cache” até que o Windows seja desligado ou
reiniciado, ou ainda quando a Máquina Virtual necessitar de recursos.
Coleta de lixo (Garbage Collector) O .NET possui um mecanismo interno de coleta de lixo, capaz de desalocar a
memória ocupada por objetos que já não estão mais sendo usados.
Além de retirar do programador a preocupação de limpeza de recursos, a coleta de
lixo também resolve os problemas de desalocação de referências circulares e de
dependência de objetos que esporadicamente aconteciam no COM. A limpeza era
feita atribuindo-se Nothing à uma variável de referência mas, se essa variável
apontasse para um objeto que, internamente, também tivesse referência a outros
objetos, estes últimos não seriam liberados se o programador não tomasse os
cuidados necessários.
A coleta de lixo é feita sem que o usuário tenha que intervir, e o framework decide
qual o melhor momento em que ela ocorrerá, usando parâmetros como
escasseamento de recursos (caso o sistema passe por situações de falta de
memória) ou ociosidade de CPU (quando o .NET usa ciclos ociosos para alocar
suas threads de limpeza).
A coleta de lixo é baseada em um contador de referências que é uma característica
de cada objeto. Quando o .NET detecta um objeto cujo marcador de referências
Apostila Treinamento C#
18
contém zero, isto é, não existe nenhum outro objeto que o referencia, ele é
colocado em uma fila e será posteriormente eliminado.
Há meios de se lidar com o mecanismo de coleta de lixo, como o método
GC.Collect(), mas é usada em casos específicos aonde se termina de usar objetos
muito grandes que, no entender do programador, devem ser liberados
rapidamente. No geral, deve se deixar o mecanismo de coleta de lixo realizar a sua
tarefa automaticamente.
Apostila Treinamento C#
19
Capítulo 3 – Visual Studio 2005
Objetivos O objetivo deste capítulo é familiarizar o leitor com o ambiente de desenvolvimento
integrado (IDE) do Visual Studio 2005.
Conceitos de Solução e Projeto O projeto é o ponto de partida para o desenvolvimento de aplicações, componentes
e serviços no Visual Studio .NET. Ele age como um container, que gerencia seu
código fonte, conexões de dados, arquivos e referências. Um projeto é organizado
como parte de uma solução, a qual pode conter múltiplos projetos, que são
interdependentes entre si.
O Visual Studio usa um modelo baseado em pastas – todos os itens do projeto são
colocados na hierarquia da pasta do projeto. Quando você adiciona um arquivo
Apostila Treinamento C#
20
texto, uma cópia do arquivo é adicionada à pasta do projeto. Além disso, quando
você remove um arquivo, você exclui o arquivo fisicamente.
Os projetos são agrupados em soluções, que podem conter até projetos de
linguagens diferentes. No Visual Studio .NET, os arquivos de projeto (.vbproj,
.csproj, etc) e os arquivos de solução (.sln) estão no formato XML.
Breve Introdução aos Diferentes Tipos de Projeto Na tela inicial do Visual Studio, quando você seleciona File > New, você já possui
alguns tipos diferentes de opções a seguir:
• Project
• Web Site
Ambos referem-se a projetos. Entretanto, o primeiro grupo corresponde aos
projetos aplicados a soluções desktop, e o segundo grupo aos projetos
desenvolvidos para Internet. Essa separação foi introduzida apenas na versão
2005.
Ao selecionarmos uma das opções (Project ou Web Site), será exibida uma tela na
qual poderemos visualizar os outros tipos de projetos disponíveis.
Apostila Treinamento C#
21
Ao selecionarmos File > New > Project, visualizamos a tela acima. Em Project
types, podemos ver os tipos de projeto disponíveis agrupados por categoria (por
exemplo, Linguagem, ou se é aplicação Windows ou para Smart Devices).
Se quisermos criar uma solução em branco, devemos selecionar Other Project
Types > Visual Studio Solutions > Blank Solution. Isso irá criar uma solução em
branco. A partir desta, poderemos adicionar novos projetos no futuro.
Entretanto, quando criamos um novo projeto, uma solução é automaticamente
criada, com o mesmo nome da solução que você criou.
Alguns tipos de projeto disponíveis:
• Blank Solution – Como o nome diz, cria uma solução em branco.
• Windows Application – Cria uma aplicação executável, que usa como
interface formulários Windows (Windows Forms).
• Console Application – Cria uma aplicação executável, que usa como
interface a linha de comando.
• Class Library – Cria um projeto que será compilado em uma biblioteca
(DLL) de classes.
Apostila Treinamento C#
22
• Windows Control Library – Cria um projeto que abriga uma biblioteca (DLL)
de controles que podem ser adicionados aos formulários Windows.
• Windows Service – Cria uma aplicação executável que roda como um
serviço no Windows.
• Device Application – Cria uma aplicação executável, desenvolvida para
dispositivos compactos.
• Setup Project – Cria um instalador para outras aplicações.
• Setup Wizard – Cria um instalador para outras aplicações, utilizando um
Wizard de aplicações.
• Visual Studio Add-In – Permite desenvolver aplicativos que irão customizar
o ambiente do Visual Studio.
• Test Project – Cria um projeto que executa testes na sua aplicação.
Além disso, em File > New > Web Site, temos os seguintes projetos:
• ASP.NET Web Site – Cria um projeto de um web site, utilizando ASP.NET.
• ASP.NET Web Service – Cria um projeto de um web service, utilizando
ASP.NET.
Estes são apenas alguns exemplos de projetos disponíveis. Além disso, alguns
plug-ins para o Visual Studio instalam outros templates de projeto.
Explorando as Janelas
Solution Explorer A janela Solution Explorer permite visualizar a estrutura de arquivos de nossa
solução, os projetos contidos nesta, e os arquivos contidos em cada projeto.
Para facilitar a programação, ela agrupa arquivos similares (como, por exemplo, o
arquivo que representa a planilha e os arquivos de código por trás desta) e oculta
os que não fazem parte da solução.
Apostila Treinamento C#
23
Toolbox Esta janela é utilizada em modo de design, e agrupa todos os controles que podem
ser adicionados ao seu projeto. Basta arrastar um controle para o design, para que
o código produzido pela inserção desse controle seja automaticamente gerado.
Properties Nesta janela, você pode alterar as propriedades de controles, formulários, páginas
etc, em modo de Design. Além disso, você pode verificar os eventos acionados por
cada controle.
Apostila Treinamento C#
24
Server Explorer Esta janela permite gerenciar diversos recursos, como conexões de dados, o event
log do Windows, filas de mensagem, lista de serviços, etc.
Como a ToolBox possui uma abordagem Drag-and-Drop, permite você inserir
objetos em modo de design, inserindo em seu projeto objetos que permitem se
comunicar com os recursos do sistema.
Task List Permite ao desenvolvedor visualizar comentários e tarefas, deixados por ele
mesmo ou por outro desenvolvedor.
Para criar um comentário, basta usar a seguinte sintaxe:
// TODO: Implementar acesso de usuário.
Todos os desenvolvedores que abrirem a Task List, verão que na linha x do
arquivo y, existe este comentário.
Apostila Treinamento C#
25
Output Na janela Output é mostrada a saída do console. Ali é possível ver não só o
progresso da compilação, mas também todas as mensagens que são enviadas ao
console como, por exemplo, System.Console.Write().
Error List Nesta janela, é possível verificar erros, warnings e mensagens geradas pelo
compilador durante a compilação de nosso código.
Lab: Navegando na IDE Vamos começar a explorar a IDE do Visual Studio, criando um novo projeto e uma
solução.
Abra o Visual Studio 2005. Em File > New, selecione a opção “Project”. Em “Project
Types”, selecione “Visual C#” > “Office”. Em “Project Templates”, selecione
“Windows Application”.
Apostila Treinamento C#
26
Devemos dar um nome para a nossa aplicação.
Na caixa “Name”, escreva “WindowsApplicationCS”, em “Location”, digite
“C:\LabVS”, e em “Solution Name” deixe o nome proposto.
Como não estaremos trabalhando com controle de versão, deixe a caixa “Add to
Source Control” desativada. Entretanto, deixe a caixa “Create directory for Solution”
ativada (ele irá criar uma pasta para a Solução, separada da pasta do projeto).
Clique em “OK”.
A estrutura criada pelo projeto no disco ficou da seguinte forma:
Voltando agora ao Visual Studio, abra a janela ToolBox, expanda “All Windows
Forms”, e arraste um controle do tipo “Button” da ToolBox para a planilha.
Apostila Treinamento C#
27
Clique com o botão direito no botão, e selecione “Propriedades”. Na janela de
propriedades, busque e altere os seguintes campos:
Campo Valor
(Name) btnHelloWorld
Text Hello World!
Feito isso, clique 2 vezes no botão. No evento que trata o click do botão, escreva o
seguinte trecho de código:
MessageBox.Show("Hello World!");
Agora, você deve ter o seguinte trecho de código:
namespace WindowsApplicationCS { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnHelloWorld_Click(object sender, EventArgs e) { MessageBox.Show("Hello World"); } } }
Rode sua aplicação, clicando no ícone . A sua aplicação será executada, e você
verá o formulário. Clique no botão.
Grave as alterações efetuadas, e feche o Visual Studio.
Apostila Treinamento C#
28
Revisão Esperamos, neste ponto, que o leitor tenha se familiarizado com a interface do
Visual Studio 2005, e seja capaz de criar um novo projeto. O projeto criado nessa
sessão será utilizado como base nas sessões seguintes.
Apostila Treinamento C#
29
Capítulo 4 – Linguagem C#
Declaração de Variáveis No C# as variáveis são declaradas ao longo do código e o tipo vem antes do nome
da variável.
Dessa forma, temos:
C#: int a; string b;
Case Sensitive O C# é case sensitive. O que isso significa? Vejamos um exemplo:
int teste = 0; int Teste = 0;
...neste caso, as variáveis teste e Teste são duas variáveis diferentes!
Além disso, supondo que temos uma variável carro...
string carro;
...não podemos acessá-la como “Carro”, “CARRO”, etc. O único modo de acessá-
la é através de:
carro = 2;
Tipos de variáveis O Common Type System (CTS) define como os tipos são declarados, utilizados e
gerenciados em tempo de execução, e também é uma parte importante do suporte
do runtime de intregração entre linguagens.
O CTS realiza as seguintes funções:
• Estabelece um framework que auxilia a integração entre linguagens,
segurança de tipos, e alta performance de execução de dados;
Apostila Treinamento C#
30
• Provê um modelo de orientação de objetos que suporta a implementação
completa de muitas linguagens de programação.
• Define as regras que as linguagens devem seguir, o que ajuda a garantir
que objetos escritos em diferentes linguagens possam interagir entre si.
Os principais tipos existentes no C# estão contidos na tabela abaixo. Na tabela, os
valores entre parênteses representam as classes bases do tipo. Quando não
houver um valor entre parênteses, indica que o nome da classe é o mesmo do
nome do tipo do C#.
Categoria Tipo do C# Alocação Memória
Range valores
Booleano Bool Depende plataforma
True ou False.
byte 1 byte 0 a 255 (sem sinal).
sbyte 1 byte -128 a 127 (com sinal). Não é compatível com a CLS.
short (Int16) 2 bytes -32.768 a 32.767 (com sinal).
int (Int32) 4 bytes -2.147.483.648 a 2.147.483.647 (com sinal).
long (Int64) 8 bytes -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 (com sinal).
ushort (UInt16) 2 bytes 0 a 65.535 (sem sinal).
uint (UInt32) 4 bytes 0 a 4.294.967.295 (sem sinal).
Inteiro
ulong (UInt64) 8 bytes 0 a 18.446.744.073.709.551.615 (sem sinal).
Ponto Flutuante float 4 bytes -3.4028235x1038 a -
1.401298x10-45 para valores
negativos;
1.401298x10-45 a
Apostila Treinamento C#
31
3.4028235x1038 para valores
positivos.
decimal 16 bytes Um decimal de 128-bits, representando valores variando de 1.0x10-28 a 7.9x1028, com 28-29 dígitos significantes.
double 8 bytes -1.79769313486231570x10308 a -4.94065645841246544x10-
324 para valores negativos;
4.94065645841246544x10-
324 a 1.79769313486231570 x10308 para valores positivos.
char 2 bytes Um caracter unicode de 16-bits.
DateTime 8 bytes Um tipo que representa um valor de data e hora. Ele armazena os valores em incrementos de 100 nanosegundos de tempo passado desde 12:00 AM de 1/1/1 do calendário Gregoriano.
IntPtr Um inteiro com sinal cujo tamanho varia de acordo com o sistema (32-bits em um plataforma 32-bits, e 64-bits, em uma plataforma de 64-bits).
Outros
UIntPtr Um inteiro sem sinal cujo tamanho varia de acordo com o sistema (32-bits em um plataforma 32-bits, e 64-bits, em uma plataforma de 64-bits). Não é compatível com CLS.
Objetos Object 4-bytes em plataforma 32-
bits;
8-bytes em
A raiz da hierarquia de objetos, qualquer tipo pode ser adicionado em um tipo objeto.
Apostila Treinamento C#
32
plataforma 64-bits.
string Varia Uma string de tamanho fixo de caracteres unicode.
Os tipos básicos estão contidos na biblioteca System (veremos bibliotecas nos
capítulos seguintes).
Marcadores de bloco e finalizadores No C#, o marcador de bloco são as chaves ( { e } ) e as sentenças são terminadas
com ponto-e-vírgula.
C#: { a = 10; b = 11; c = a + b; }
Símbolos e operadores lógico-aritméticos Como pode ser observado no exemplo acima, o operador de atribuição do C# é o
sinal de igual. A tabela abaixo lista símbolos e operadores:
Símbolo/operador C#
Atribuição =
Igual (Comparação) ==
Diferente (Comparação) !=
And lógico &&
Or lógico ||
Not lógico !
Incremento x++
Apostila Treinamento C#
33
Decremento x--
If...else No C#, a condição comparada sempre deve vir dentro de parênteses e, por isso,
existe um delimitador que informa aonde começa uma condição e aonde ela
termina.
Assim sendo:
C#: if (x > 7) y = x – 6; else { y = x; }
Laços While O while, seguindo a mesma idéia de colocar a condição dentro de parênteses:
C#: while (x > 7) x++;
Laços for Os laços for nada mais são um laço while aonde é possível:
• declarar/inicializar uma variável contadora;
• verificar uma condição de saída;
• incrementar/decrementar a variável contadora.
Como exemplo de cada uma dessas funcionalidades, temos:
for (int i =0 ; i <= 10 ; i++)
Temos aí uma inicialização (int i =0) e uma condição de parada (i <= 10), ao final
de cada interação é executado incremento (i++).
Apostila Treinamento C#
34
Laços do...while O laço do..while, vale para a mesma regra para a condição de loop do while: a
condição deve estar entre parênteses.
C#: exit = false; do { a = a + 1; if (a > 99) exit = true; } while (! exit);
Switch..Case A instrução Switch..Case do C#, agrega várias comparações simples, poupando
o desenvolvedor de usar vários if encadeados:
C#: switch (i) { case 1: Opcao = "1 prestação"; break; case 2: Opcao = "2 prestações";break; case 3: Opcao = "3 prestações";break; default Opcao = "Pagamento no ato";break; }
Algumas observações importantes sobre o switch:
– todas as opções devem terminar com break ou goto;
– não é possível trabalhar com intervalos;
– o switch aceita usar strings no case.
Loop foreach É uma alternativa interessante e muito usada para iterar por listas, coleções ou
vetores: com o foreach não é necessário buscar dados de tamanho e índice inicial
para que possa ser feito um laço for trivial. O foreach se encarrega de controlar
Apostila Treinamento C#
35
esses dados, deixando o desenvolvedor livre para implementar outras
funcionalidade sem se preocupar com o controle desse loop.
O exemplo abaixo ilustra o seu uso:
static void Main(string[] args) { foreach (string str in args) Console.WriteLine(str); }
A declaração static void Main é usada em C# para indicar que aquela é a função a
ser chamada quando o programa for iniciado. string[] args é o vetor dos
argumentos de linha de comando.
A função acima itera por cada argumento de string[] args. A cada iteração, o valor
correspondente do vetor é armazenado na variável str e é impressa na saída do
console.
Vetores (arrays) Os vetores no C# são declarados junto com a variável e têm sempre índice inicial
zero. As diferentes formas de declarar são:
C#: int[] pontos; int[10] outrosPontos; int[,] plano;
Funções No C# tanto procedures como functions são funções, e são diferenciadas pelo tipo
do retorno: se forem void, as funções são tratadas como procedures, se tiverem
qualquer outro tipo, são tratadas como functions. Por exemplo:
C#: void Executa(int codigo); double Calcula(int Codigo, double passo);
Apostila Treinamento C#
36
Estrutura de um programa C# No C# o desenvolvedor não fica restrito às áreas de declaração: variáveis e
métodos podem ser declarados ao longo do código, e não em uma seção
específica. O desenvolvedor pode declarar no início as variáveis e se disciplinar
para isso, mas a linguagem não o obriga a tal.
A seção “using” do C#, deve vir sempre no início do código.
using System; public class MinhaClasse { public int MinhaFuncao(int Entrada); // só a assinatura, implementada abaixo public void MinhaProcedure() { // implementação } public int MinhaFuncao(int Entrada) { // implementação } }
Conversão de tipos (cast) No C# deve ser usada a notação abaixo para a convesão:
(<tipo de destino>) variável
Sendo assim:
public int SomaInteiros(Double par1, par2) { return (int)par1 + (int)par2; }
Para converter para strings, pode ser usado o método ToString:
public string SomaInteiros(Double par1, par2) { int soma soma; soma = (int)par1 + (int)par2 return soma.ToString(); }
Apostila Treinamento C#
37
Strings As Strings do .NET merecem atenção especial. As novas strings são Unicode, e
ocupam 2 bytes a cada caractere.
Ao concatenar uma string com outra, obtemos uma nova string. Por conta disso, o
.NET foi aparelhado com a classe StringBuilder, contida na biblioteca System.Text.
(falaremos mais sobre classes e bibliotecas nos próximos capítulos).
A classe StringBuilder deve sempre ser usada em casos na qual existam múltiplas
concatenações. Por exemplo:
StringBuilder sb = new StringBuilder(); string strFrase; sb.Append("A "); sb.Append("ligeira "); sb.Append("raposa "); sb.Append("marrom "); sb.Append("ataca "); sb.Append("o cão preguiçoso."); strFrase = sb.ToString();
Nota
No C#, como já foi falado na seção de conversões, todos os tipos implementam um
método chamado ToString. Este método, quando executado, retorna o dado no
formato de string, de acordo com o tratamento dado pelo tipo.
int var1 = 2; string str = var1.ToString(); // O mesmo que str = “2”
Revisão Vimos nesse capítulo, as principais características na sintaxe da programação do
C#. Iremos, nos capítulos seguintes, nos aprofundar nos conceitos de Orientação a
objetos.
Apostila Treinamento C#
38
Capítulo 5 – Orientação a Objetos com C#
Objetivos A linguagem C# foi criada a partir do zero no surgimento do .NET. A Microsoft
optou por basear a sua nova linguagem nos conceitos de programação orientada a
objetos (OOP), disponíveis nas mais modernas linguagens de programação. O
objetivo deste capítulo é apresentar alguns desses conceitos para o leitor
(aplicados ao C#), para que seja possível aproveitar ao máximo o potencial dessa
linguagem.
Conhecer a Orientação a Objetos é uma das tarefas que qualquer desenvolver que
ainda não conhece deve fazer. Apesar do C# não obrigar o desenvolvedor a
programar usando OOP, ele estará limitando o seu potencial.
O assunto de Orientação a Objetos, por si só, já valeria um livro exclusivo e
dedicado. Não está no escopo desta Apostila explicar em minúcias as técnicas de
orientação a objetos, mas sim mostrar em linhas gerais o que é e como é
empregada.
A seguir veremos como são implementados os conceitos de OOP no Visual C#.
Visão Geral A Orientação a Objetos foi criada em meados da década de 70, mas só se
popularizou ao final da década de 90.
A Orientação a Objetos é um paradigma que aproxima o modo como enxergamos
o mundo real com o modo de programarmos. A programação procedural, realizada
até então, tinha como foco a codificação de problemas em uma forma de script,
com começo, meio e fim determinados, contendo em seu interior desvios, loops e
verificações condicionais.
Já a Orientação a Objetos foca na estrutura dos objetos envolvidos no problema e
sua relação entre eles. O código procedural fica confinado internamente e é
altamente fragmentado em relação à outra tecnologia.
Apostila Treinamento C#
39
As maiores vantagens da Orientação a Objetos são:
– Um sistema OO bem projetado reduz significativamente o custo de
manutenção e permite distribuir melhor os trabalhos por uma equipe.
– Permite melhor compreensão do problema por parte do programador e do
analista de negócios.
– Torna mais fácil a reutilização e a componentização do código.
Há também desvantagens que devem ser levadas em conta:
– É um novo paradigma a ser descoberto.
– Requer prática para arquitetar soluções.
Classes e Objetos Classes são “esqueletos” ou “plantas” que especificam objetos. Objetos são
entidades que representam entidades do mundo real.
Um exemplo rotineiramente estudado em livros é a classe “Carro”. Um carro pode
ter características (como cor, número de portas, tipo de pneus, potência do motor,
etc) – que chamaremos de atributos - e ações (acelerar, frear, abrir porta, acionar o
limpador de pára-brisas, etc) – que chamaremos de métodos.
Note que, apesar de terem valores diferentes (como, por exemplo, cor diferente), o
conjunto de atributos e métodos citados é comum à maioria dos automóveis. Ou
seja, existe um conjunto de características que define o que é um carro, uma
planta. A esse conjunto de características, damos o nome de “classe”.
Quando os mecânicos da fábrica de automóveis montam um carro (ou seja, fazem
uma implementação física do que está contido no papel), ele deixa de ser apenas
um modelo, apesar de ainda compartilhar características com outros carros. Ele
passa a ser um “objeto”, algo físico, no qual podemos entrar e andar por aí.
Em programação, quando criamos uma instância de uma classe em memória, é
como se estivéssemos utilizando a classe como planta para criar um objeto físico.
Apostila Treinamento C#
40
Voltando ao exemplo da classe “carro”, quando instanciamos em memória a
classe, dando-lhe atributos como cor = verde, numeroDePortas = 4, tipoDePneus =
asfaltoComum, etc, ela se tornou um objeto, que é a instância de uma classe.
Vamos começar o nosso exemplo criando uma classe que representa uma porta:
class Porta { ... }
Agora que criamos a classe porta, como fazemos para criar um objeto do tipo
Porta?
Porta porta = new Porta();
Com isso, temos que a variável “porta” contém uma referência para um novo objeto
do tipo Porta. Nas seções seguintes, veremos como criar atributos, propriedades e
métodos em uma classe.
Atributos e Propriedades Atributos são definidos em uma classe, e guardam valores ou referências.
Normalmente, são expressas por substantivos que representam os atributos. No
C#, os atributos correspondem às variáveis. Vamos mostrar o seu funcionamento
através de mais um exemplo.
class Casa { Porta porta = new Porta(); ... }
O que temos aqui? Criamos uma nova classe Casa, e dentro dela adicionamos um
atributo – uma porta! Ou seja, toda casa que gerarmos a partir de nossa classe
Casa terá uma porta – mesmo que sejam portas diferentes.
No C#, uma propriedade nada mais é do que um tipo especial de variável que deve
ser lida/escrita através de acessores. Isso é feito da seguinte forma:
Porta PortaEsquerda { get { return portaEsquerda; } set { portaEsquerda = value; } }
Apostila Treinamento C#
41
Métodos Métodos são as ações que são definidas na classe. Normalmente são expressas
por verbos que representam operações que a classe permite executar.
Como exemplo, vamos implementar alguns métodos em nossa classe Porta:
class Porta { string cor; bool fechada; bool trancada; void Abrir() { if (! trancada) { fechada = false; } } void Fechar() { if (! fechada) { fechada = true; } } void Trancar() { if (fechada) { trancada = true; } } void Destrancar() { trancada = false; } bool VerifTrancada() { return trancada; } void MudarCor(string novaCor) { cor = novaCor; } }
Apostila Treinamento C#
42
Como pode ser visto no exemplo, existe uma única forma para se declarar um
método:
[<acesso>] [<retorno>] <nome método> ([<lista de parâmetros>]) { ... }
Falaremos sobre níveis de acesso ainda neste capítulo. A lista de parâmetros deve
obeceder à seguinte estrutura:
[ref|out] <tipo> <nome parâmetro> [, <lista de parâmetros>]
A palavra chave ref, indica que o parâmetro será passado por referência. Um
argumento passado por referência precisa antes de tudo ser inicializado.
Já a palavra chave out, indica que esse parâmetro é um parâmetro de saída – o
seu valor não será utilizado no código.
Para facilitar a compreensão das diferenças entre passar um valor por parâmetro
ou por referências, veremos o exemplo de um método que recebe o comprimento e
a largura, e retorna a área do quadrado:
double CalculaArea( double comprimento, double largura ) { // Declarando variáveis locais. double area; if( comprimento == 0 || largura == 0 ) { // Se um argumento = 0, não dá para calcular a área. area = 0; } else { // Calcula a área do retangulo. area = comprimento * largura; } return area; }
New Keyword No C# quando queremos declarar uma variável que aponta para uma classe
fazemos da seguinte forma:
Util util;
Apostila Treinamento C#
43
...e quando queremos inicializar a nossa variável com uma nova instância,
utilizamos à palavra chave New:
util = new Util();
Por fim, todas as classes herdam de Object.
Construtores e Destrutores E se você precisar criar uma classe que, durante a inicialização de um novo objeto,
precise executar algum código? Ou precisar rodar comandos de limpeza, antes de
o objeto ser destruído?
No C#, como no Delphi, existe o conceito de contrutores e destrutores.
Um construtor é acionado, caso exista, quando utilizamos à palavra chave New:
util = new Util();
Vamos ver um exemplo. Imagine novamente o caso da porta:
class Porta { string cor; bool fechada; bool trancada; ... }
Vamos agora imaginar que gostaríamos de ter uma classe Porta que permitisse
que, em sua inicialização, fossem atribuídos valores às propriedades fechada e
trancada.
Para isso, vamos utilizar um construtor. O formato da declaração do construtor é
semelhante à declaração de um método, com a diferença que não aceita tipo de
retorno e que deve possuir o mesmo nome da classe. Assim sendo, em nosso caso
teríamos:
Porta( bool fechada, bool trancada ) { if( fechada ) { Fechar(); } else { Abrir(); }
Apostila Treinamento C#
44
if (trancada) { Trancar(); } else { Destrancar(); } }
Quando um objeto não é mais necessário, o Garbage Collector chama o método
Finalize para aquele objeto antes de liberar a memória. O método Finalize é
chamado destrutor, porque ele realiza tarefas de limpeza, tais como gravar
informação de estado, fechar arquivos e conexões com bancos de dados, além de
outras tarefas que precisam ser feitas antes de liberar o objeto.
No C#, os destrutores não podem ser chamados – eles são disparados
automaticamente pelo GC. Entretanto, devido à característica não-determinística
do GC, não é possível saber exatamente quando o destrutor será acionado.
Vamos agora utilizar um destrutor para mudar o valor das variáveis fechada e
trancada para false, antes de podermos destruir esse objeto da memória.
~Porta() { trancada = false; fechada = false; }
Lab: Trabalhando com Classes Vamos trabalhar com classes.
Abra o Visual Studio 2005. Abra o projeto “WindowsApplicationCS” que criamos
anteriormente.
Remova o botão “Hello World”, e adicione 6 botões:
(Name) Text
btnAbrePortaEsquerda Abre Esq.
btnFechaPortaEsquerda Fecha Esq.
btnAbrePortaDireita Abre Dir.
btnFechaPortaDireita Fecha Dir.
Apostila Treinamento C#
45
btnAcelera Acelera
btnFreia Freia
Agora, adicione 3 controles Label, com os seguintes textos:
• “Porta Esquerda:”
• “Porta Direita:”
• “Velocidade:”
Por fim, adicione mais 3 controles do tipo Label, com os seguintes IDs:
• “lblPortaEsquerda”
• “lblPortaDireita”
• “lblVelocidade”
Você deve ter algo do gênero:
Agora que a parte gráfica de nossa aplicação está pronta, vamos implementar o
código. Adicione ao seu projeto uma classe Porta (clique com o botão direito no
seu projeto, e selecione “Add”>”New Item”, selecione “Class”, e dê o nome
“Porta.cs”).
Em sua classe, implemente:
• Atributo “fechada” – indica se a porta está fechada;
• Atributo “trancada” – indica se a porta está trancada;
Apostila Treinamento C#
46
• Método Abrir – permite a abertura da porta;
• Método Fechar – permite o fechamento da porta;
• Método Trancar – permite trancar a porta, caso esta esteja fechada;
• Método Destrancar – destranca a porta, caso esteja trancada;
• Método VerifFechada – retorna indicador se a porta está ou não fechada;
• Método VerifTrancada – retorna indicador se a porta está ou não trancada;
• Construtor – recebe como parâmetro se a porta está “fechada” e
“trancada”.
Até este momento, o código utilizado é idêntico ao dos nossos exemplos. Vamos
agora mudar um pouco. Crie uma nova classe, chamada “Carro”.
Como todo carro tem pelo menos 2 portas, iremos adicionar ao nosso carro 2
atributos do tipo Porta (já criado no começo desse lab), e chamá-los de
“portaEsquerda” e “portaDireita”. Adicione também um atributo chamado
velocidade, que deve ser capaz de receber um valor inteiro.
No construtor da classe, inicialize ambas as portas como abertas e destrancadas, e
a velocidade em 0.
Agora, crie 2 propriedades, PortaEsquerda e PortaDireita, que irão prover acesso
aos atributos respectivos.
Por fim, iremos adicionar os seguintes métodos:
• Acelera(valor) – Aumenta velocidade do carro, em incrementos de 10, até
180 Km/hora. Se passar de 180, atribui 180 e retorna um indicador,
indicando que a velocidade máxima foi atingida.
• Freia(valor) – Diminui a velocidade do carro em valor, em decrementos de
10, chegando ao mínimo de 0. Se for menor que 0, retorna um indicador
que o carro já está parado.
Apostila Treinamento C#
47
• VelocidadeAtual() – Retorna um inteiro, indicando a velocidade atual do
carro.
Grave as alterações. Nesse ponto, o nosso código está pronto. Vamos agora ligar
o formulário com o código.
Clique 2 vezes sobre o formulário, em uma região aonde não haja nenhum botão
ou label. O Visual Studio irá abrir o modo de código, e criar automaticamente um
evento Form1_Load. Esse evento será executado antes do Form ser mostrado
para o usuário.
Entretanto, como queremos definir o carro como global, precisamos declará-lo fora
do método. Então, logo acima da declaração do Form1_Load, declare e inicialize
uma variável do tipo Carro.
Agora, crie um método chamado “ShowResults”, que irá atualizar as labels
“lblPortaEsquerda”, “lblPortaDireita” e “lblVelocidade” com os valores corretos. No
evento “Form1_Load”, execute o método “ShowResults”.
Volte agora para o modo de exibição. Clique em cada um dos botões, e
implemente a lógica correspondente. Não se esqueça de chamar o método
“ShowResults”, para atualizar os dados na tela para o usuário. Por fim, caso a
velocidade caia abaixo de 0, ou passe do limite, mostre uma mensagem na tela
para o usuário.
A solução para este laboratório está contida no CD.
Níveis de Acesso e Visibilidade Existem propriedades e métodos que, de alguma forma, devem ficar restritos à
classe. Por exemplo, flags que mostram se a porta está trancada ou destrancada
podem ficar ocultos ao exterior, e um usuário usaria uma função VerifTrancada()
para saber se a porta está trancada (se a função retornar True) ou se ela está
destrancada (se a função retornar False).
Para isso, “encapsula-se” partes do conteúdo de forma a permitir que outras
classes enxerguem propriedades e métodos. Fazemos isso através do controle dos
níveis de acesso.
Apostila Treinamento C#
48
O nível de acesso de um elemento determina que código possui permissão para ler
e executar o elemento. Código que não pode acessar um elemento, não pode
acessar qualquer elemento contido dentro dele, mesmo que os elementos internos
tenham um nível de permissão maior do que o elemento externo.
Public O nível de acesso Public especifica que o elemento é acessível a partir de qualquer
lugar dentro do mesmo projeto, de outros projetos que referenciam o projeto que o
contém, ou de qualquer assembly construído a partir do projeto. Exemplo:
public class Porta
Private O nível de acesso Private especifica que os elementos somente são acessíveis
dentro do mesmo contexto (módulo, classe ou estrutura) no qual foram declarados.
Exemplo:
private string cor;
Protected Você só pode utilizar Protected em nível de Classe (dentro de uma). Protected
especifica que o elemento é acessível apenas dentro da própria classe, ou por
classes derivadas desta.
public class Ambiente { protected class Animal { ... } protected class Leão : Animal { ... } }
A classe derivada de uma outra classe deve possuir um nível de acesso menor ou
igual à classe pai.
Apostila Treinamento C#
49
Internal O nível de acesso Internal especifica que os elementos serão acessíveis de dentro
do mesmo Assembly, mas não fora dele. Um exemplo de declaração:
internal string mensagem;
Protected Internal É possível utilizar ambos os níveis de acesso Protected e Internal juntos em uma
declaração para especificar que um elemento é acessível ou de classes derivadas,
ou de dentro do mesmo assembly.
protected internal string mensagem;
Resumo dos Níveis Acesso Nível de acesso Elementos a que se aplica Contexto
Public Qualquer código que pode visualizar um elemento público pode acessá-lo.
Interfaces; Módulos; Classes; Estruturas; Propriedades; Atributos (internos); Constantes; Enums; Eventos; Declarações Externas; Delegates.
Arquivo; Namespace; Interface; Módulo; Classe; Estrutura.
Private Código dentro do mesmo contexto pode acessar.
Interfaces; Módulos; Classes; Estruturas; Propriedades; Atributos (internos); Constantes; Enums; Eventos; Declarações Externas; Delegates.
Módulo; Classe; Estrutura.
Protected Código dentro da classe, ou de uma classe que herda desta podem acessar.
Interfaces; Classes; Estruturas; Propriedades; Atributos (internos); Constantes; Enums; Eventos; Declarações Externas; Delegates.
Classe.
Internal Código dentro do mesmo assembly.
Interfaces; Módulos; Classes; Estruturas; Propriedades; Atributos (internos); Constantes; Enums; Eventos; Declarações Externas; Delegates.
Arquivo; Namespace; Interface; Módulo; Classe; Estrutura.
Protected Internal
Código dentro da mesma classe ou mesmo assembly, ou qualquer classe derivada da classe aonde o elemento está contido.
Interfaces; Classes; Estruturas; Propriedades; Atributos (internos); Constantes; Enums; Eventos; Declarações Externas; Delegates.
Classe.
Apostila Treinamento C#
50
+Abrir()
+Fechar()
+Trancar()+Destrancar()
+VerifTrancada() : Boolean
+cor : Integer
-tipoTrinco : String
#fechada : Boolean
#trancada : Boolean
PortaPortaPortaPorta
Encapsulamento Existem atributos e métodos que, de alguma forma, devem ficar restritos à classe.
Por exemplo, flags que mostram se a porta está trancada ou destrancada podem
ficar ocultos ao exterior, e um usuário usaria uma função VerifTrancada() para
saber se a porta está trancada (se a função retornar True) ou se ela está
destrancada (se a função retornar False).
Para isso, “encapsula-se” partes do conteúdo de forma a permitir que outras
classes enxerguem propriedades e métodos. Fazemos isso, controlando os níveis
de acesso.
Notação UML A notação UML (de Unified Modeling Language) é um conjunto de diagramas que
permitem que um analista especifique um sistema usando modelos-padrão
adotados pelo mercado. Não é escopo deste curso explicar cada um dos
diagramas e seus componentes (isso é tarefa para um curso de pelo menos 40
horas !), mas convém aqui mostrar como uma classe é mostrada em um diagrama
de classes, que é comumente visto na literatura:
Esse desenho corresponde à representação UML da classe abaixo:
public class Porta { public int cor; private string tipoTrinco; protected bool fechada; protected bool trancada; public void Abrir() { if (! trancada) { fechada = false; }
Apostila Treinamento C#
51
} public void Fechar() { if (! fechada) { fechada = true; } } public void Trancar() { if (fechada) { trancada = true; } } public void Destrancar() { trancada = false; } public bool VerifTrancada() { return trancada; } }
Na notação UML, uma classe é representada por um retângulo dividido em três
partes. Na parte superior, ficam o nome da classe. Na parte central, as
propriedades, na parte inferior, as ações.
Propriedades e métodos públicos são indicados com um sinal de (+) na frente do
nome. Propriedades e métodos privados são representados com um sinal de (-) na
frente do nome. Por fim, propriedades e métodos protected são representados com
um sinal de (#).
Herança O conceito de herança é largamente utilizado na orientação a objetos. Através
desse conceito, uma classe pode herdar o que já é especificado em outra classe.
Diz-se então que uma classe-filha está herdando de uma classe-pai ou uma super-
classe.
Vamos supor que estamos desenvolvendo um sistema para uma empresa que
comercializa portas de todos os tipos e formas. Existem atributos e ações que são
específicas de qualquer porta:
- atributos: material, cor, tipo de fechadura, tipo de trinco, altura, largura,
profundidade, peso, etc;
Apostila Treinamento C#
52
- ações: abrir, fechar, trancar, destrancar, etc.
Essa classe atende à boa parte das portar que a empresa comercializa. Mas
existem tipos de portas especiais que, além de terem as mesmas características da
classe Porta, adicionam outras características novas. Mais ainda, existem portas
que precisam de procedimentos modificados.
Um exemplo é a porta de cofre. A porta de cofre, além de ter as características de
uma porta tradicional, ainda precisa de um segredo para ser aberta junto com a
chave e o trinco.
Ao invés de reescrever uma classe PortaDeCofre inteira, o mais fácil é fazer com
que essa classe herde todas as características de Porta, mas adicione algumas
propriedades e que sobrescreva a implementação de Destrancar(), uma vez que
essa porta em especial precisa tratar também do segredo do cofre.
O diagrama UML ficaria assim:
Dessa forma, ao criarmos uma instância de PortaDeCofre, se chamássemos
PortaDeCofre.Abrir() ou PortaDeCofre.cor, não seria gerado erro: uma vez que
PordaDeCofre herda de Porta, ao ser instanciado é criada uma área na memória
com todo o conteúdo de porta e mais o conteúdo de PortaDeCrofre.
+ D e s t r a n c a r ( )
- S e g r e d o
P o r t a D e C o f r e
+ A b r i r ( )+ F e c h a r ( )+ T r a n c a r ( )+ D e s t r a n c a r ( )+ V e r i fT r a n c a d a ( ) : B o o le a n
+ c o r : In t e g e r- t ip o T r in c o : S t r in g# fe c h a d a : B o o le a n# t r a n c a d a : B o o le a n
P o r t a
Apostila Treinamento C#
53
A implementação de herança no VB.NET é feita através da palavra-chave Inherits.
O código que representaria uma porta de cofre ficaria então:
public class PortaDeCofre : Porta
É importante notar que, no .NET, uma classe só pode herdar de 1 única classe
(existem algumas linguagens de programação que permitem o que é chamado
herança múltipla). Entretanto quando uma classe herda de outra, é como se ela
herdasse também de todas as classes pai da classe pai dela.
Ou seja, quando temos algo como:
public class Animal {} public class Mamifero : Animal { } public class Leao : Mamífero { }
A classe Leao acaba herdando da classe Animal indiretamente, na medida em que
todo Leão é um Mamífero, e todo Mamífero é um Animal.
Todas as classes, em algum nível, herdam do tipo Object, o tipo mais básico do
CTS. Quando não declaramos uma classe pai para a nossa classe, o compilador
automaticamente faz com que a nossa classe herde de Object.
Classe Abstrata e Classe Selada Uma classe abstrata é uma classe que não pode ser instanciada – ela é criada com
o único propósito de servir de pai para outras classes. Ou seja, você não pode criar
uma declaração usando New com uma classe do tipo abstrata.
No C#, o modificador abstract implementa uma classe abstrata:
public abstract class MinhaClasse { }
Uma classe abstrata pode conter métodos abstratos ou não. Entretanto, uma
classe não abstrata não pode conter métodos abstratos.
Além do conceito de classe abstrata, existe também o conceito de classe selada.
Uma classe selada é uma classe que não pode ser herdada – ou seja, nenhuma
classe pode derivar dela.
O C# implementa classes seladas através do modificador NotInheritable:
Apostila Treinamento C#
54
public sealed class MinhaClasse { }
Sobrescrita de Métodos Sobrescrevermos um método quando queremos substituir o método original por
uma outra implementação, específica de uma classe filha.
No C#, temos duas opções para sobrescrever um método: usando a palavra chave
new, ou usando a palavra chave override.
A diferença entre os dois métodos é que no primeiro caso, estamos criando um
novo método com o mesmo nome e escondendo o membro original. Esse é o
comportamento padrão, ou seja, não é necessário usar a palavra chave new, mas
o compilador irá disparar um aviso, indicando a necessidade do new.
Já no segundo caso, estamos estendendo a implementação para um membro
herdado. Para que isso seja possível, na declaração original do método precisamos
definir o método com um dos seguintes modificadores: abstract, virtual ou override
(o modificador virtual define apenas que uma classe pode ser sobrescrita).
No nosso exemplo da classe Porta, podemos sobrescrever o método Destrancar(),
uma vez que PortaDeCofre só pode ser aberta se o segredo que o usuário inseriu
for o correto. Nosso método, na classe PortaDeCofre, ficaria então:
public override void Destrancar() { if (segredo == "cges") { base.Destrancar(); } }
Enquanto na classe Porta temos:
public virtual void Destrancar() { trancada = false; }
Note que usamos a instrução override para declarar que Destrancar() sobrescreve
a implementação desse método.
Apostila Treinamento C#
55
Sobrecarga de Métodos Fazemos uma sobrecarga quando precisamos implementar um método que deve
receber um conjunto diferente de parâmetros.
No nosso exemplo, podemos escrever um método para abrir a porta, mas
passando como parâmetro o segredo da porta. O usuário então teria outra opção
para poder abrir a porta: ou ele atribui um valor à propriedade Segredo e chama
Destrancar(), ou então ele chama Destrancar passando o segredo:
public void Destrancar(string segredo) { this.segredo = segredo; Destrancar(); }
Como é possível visualizar abaixo, quando você acessa um método que possui
sobrecarga, é mostrado ao desenvolvedor uma lista, com todos as possíveis
chamadas deste método.
Acessando a classe pai – base e this Há situações em que sobrescrevemos ou ocultamos membros da classe-pai. Como
podemos indicar em nosso código se método que queremos usar é o membro
original (da classe-pai) ou a especialização (da classe filha)?
Quando estamos dentro de uma classe, o comando this permite indicar que
usaremos o membro da classe em que estamos, e o comando base permite usar o
membro a partir da classe-pai da qual estamos herdando.
Polimorfismo Vamos agora voltar a falar um pouco mais sobre classes.
Apostila Treinamento C#
56
Quando falamos sobre sobrecarga de métodos, definimos uma classe filha da
classe Porta – a classe PortaDeCofre. Além disso, mostramos como era possível à
classe filha sobrescrever um método da classe pai:
Classe PortaDeCofre:
public override void Destrancar() { if (segredo == "cges") { base.Destrancar(); } }
Classe Porta:
public virtual void Destrancar() { trancada = false; }
O que tudo isso de herança implica? Implica que a classe PortaDeCofre
corresponde a um subgrupo do tipo Porta, e como tal possui características em
comum com outras classes de porta (como PortaDeVidro). Quando estamos
falando genericamente sobre Portas, uma PortaDeCofre pode ser usada como
Porta.
A esse conceito, dá-se o nome de Polimorfismo – a capacidade de uma classe filha
se passar por uma classe pai mesmo que, internamente, tenha mecanismos
diferentes de funcionamento.
Por exemplo, podemos declarar uma variável da seguinte forma:
No exemplo acima, vemos como uma variável do tipo Porta pode receber uma
variável do tipo PortaDeCofre. Entretanto, nesse momento todas as características
Apostila Treinamento C#
57
externas que diferenciam um PortaDeCofre de uma Porta ficam ocultas – afinal,
não estamos trabalhando com uma PortaDeCofre, mas com uma Porta!
Entretanto, quando sobrescrevemos um método, a classe filha passa a ter um
funcionamento diferente da classe pai. O que irá ocorrer nesse caso?
Se pensarmos novamente na Porta e na PortaDeCofre, vemos que ambas
funcionam de forma diferente. Como o funcionamento de uma Porta é diferente do
funcionamento de uma PortaDeCofre, quando chamarmos o método Destrancar()
estaremos chamando o método da classe especializada (PortaDeCofre), ao invés
do método da classe pai. Apenas se a classe filha não tiver alterado a
implementação, é que será chamado o método da classe pai.
Lab: Trabalhando com Herança Vamos agora criar uma classe que represente um carro esportivo. Um carro
esportivo corre muito mais rápido que um carro normal, mas ainda tem 2 portas.
Abra a solução “WindowsApplicationCS”, desenvolvida anteriormente. Adicione
uma nova classe “CarroEsportivo”. Essa nova classe deve herdar da classe
“Carro”.
Na classe “Carro”, transforme a propriedade “velocidade” de “private” para
“protected”, de forma que seja possível alterar o seu valor a partir da classe filha.
Sobrescreva o método Acelera, para permitir ao condutor acelerar até 250
Km/hora, e substitua a chamada para a classe “Carro”, por uma chamada à classe
“CarroEsportivo”. Rode a sua aplicação e verifique o que acontece quando você
acelera seu carro acima de 180 km/hora.
Para ver a resposta do exercício, abra o Lab “Trabalhando com Herança”, do CD.
Interface Interfaces, como classes, definem um pacote de propriedades e métodos.
Entretanto, diferentemente de classes, interfaces não provêm implementação.
Uma interface funciona como um contrato, no qual a classe que a implementa
precisa implementar todos os aspectos definidos pela interface exatamente como
definida.
Apostila Treinamento C#
58
A grande vantagem de interfaces, é que apesar de uma classe só poder herdar de
uma única classe, ela pode implementar inúmeras interfaces diferentes.
public interface IPessoa { public string GetNome(); } public class PessoaFisica : IPessoa { private string nome; public string GetNome() { return nome; } ... }
Métodos, Atributos e Propriedades Estáticas Uma propriedade, um atributo ou um método estático podem ser vistos como uma
característica da classe e não do objeto. O que isso significa?
Lembra-se de quando falamos que, quando declaramos um objeto usando a
palavra-chave New, estamos alocando um espaço na memória onde os dados do
objeto ficarão alocados? Um atributo estático não fica armazenado nesse espaço,
mas sim fica armazenado junto com a definição da classe.
Isso significa que, todos os objetos criados a partir da classe irão acessar o mesmo
dado.
Vamos considerar, como exemplo, a classe ContadorAcessos abaixo:
public class ContadorAcessos { public int conta = 0; public void SomaUm() { conta++; } public int Total() { return conta; } }
Vamos agora utiliza a nossa classe:
Apostila Treinamento C#
59
ContadorAcessos contador1 = New ContadorAcessos(); ContadorAcessos contador2 = New ContadorAcessos(); contador1.SomaUm(); contador1.SomaUm(); contador2.SomaUm(); MessageBox.Show( contador2.Total().ToString() );
Qual será o resultado? 1.
Agora, se modificarmos um pouco a nossa classe:
public class ContadorAcessos { public static int conta = 0; public void SomaUm() { conta++; } public int Total() { return conta; } }
O que teremos como resultado? 3.
Além disso, outra propriedade de atributos, métodos e propriedades estáticas é
que não é necessário declarar uma instância da classe para podermos acessá-los.
Podemos acessá-los diretamente a partir do nome da classe, como em:
Como exemplo de um método estático no .NET, podemos citar o já mostrado
método Show(), da classe MessageBox.
Classes Parciais O C# permite que uma classe seja declarada ao longo de vários arquivos. Isso é
vantajoso em trabalho em equipe, já que programadores podem trabalhar em
fragmentos da classe em arquivos separados.
Quando o compilador for chamado, ele mesmo se encarregará de juntar as partes
de uma classe e produzir uma classe apenas.
Apostila Treinamento C#
60
A classe original deve ser implementada normalmente. Entretando, durante a
declaração da classe parcial, basta declará-la adicionando a palavra chave Partial:
public partial class ....
Revisão Vimos neste capítulo um pouco sobre os conceitos de programação orientada a
objetos, e como esses conceitos são implementados na prática no C#. Nos
capítulos seguintes, trataremos de conceitos mais avançados de programação.
Apostila Treinamento C#
61
Capítulo 6 – Tópicos Avançados
Objetivos O objetivo deste capítulo é introduzir ao leitor tópicos mais avançados de
programação no Visual C# 2.0. Falaremos sobre como classes são agrupadas em
namespaces e sobre como fazemos quando precisamos acessar classes contidas
em outros projetos. Ainda neste capítulo, falaremos sobre as bibliotecas que já vem
junto com o framework, e encapsulam funções rotineiras. Por fim, completamos
falando sobre tratamento de erros no .NET.
Namespaces Para melhor organizar o conteúdo, as classes podem ser agrupadas em
namespaces. Namespaces são unidades lógicas de códigos que agregam classes
que possuem um assunto em comum (que podem ser agrupadas juntas).
Os namespaces podem ser mais bem entendidos, se o compararmos a caminhos
de diretórios. Quando queremos, em uma máquina Windows, acessar o
Notepad.exe, o caminho que usamos é: c:\windows\notepad.exe. Analogamente,
se precisamos acessar uma classe que copia um arquivo, usamos:
System.IO.File.Copy(). O “caminho” aqui demonstrado é lido da seguinte forma: a
classe Copy(), que está dentro do namespace System, dentro de IO e dentro de
File.
É bom diferenciarmos aqui um namespace de um assembly. Quando compilamos
um projeto, todo o código fonte daquele projeto é compilado e transformado em 1
único arquivo (que pode ser um .EXE ou um .DLL, dependendo do tipo do projeto),
ou assembly. Em geral, um projeto possui um namespace único e distinto.
Entretanto, um namespace não obrigatoriamente deve estar restrito a um único
assembly. Podemos ter mais duas classes diferentes, em dois projetos diferentes,
que pertençam a um único namespace. Além disso, em um mesmo projeto
podemos ter a definição de classes de namespaces distintos.
Apostila Treinamento C#
62
As produtoras de software costumam usar essa notação para criar seus próprios
namespaces. São exemplos: empresa.utils, empresa.sistema1.calculo, e assim por
diante.
Aqui surgem algumas dúvidas. A primeira delas se refere a como fazemos com que
a nossa classe pertença a um namespace?
Por default, todas as classes que pertencem a um projeto pertencem a um mesmo
namespace, que você pode definir clicando em “My Project”, na tab “Application”. O
namespace raiz do seu projeto fica definido em “Root Namespace” (alguns tipos de
projetos não possuem essa opção – como projetos do Office). Por default, esse
namespace possui o mesmo nome do projeto.
Existem 2 modos de alterar o namespace de uma classe. A primeira, delas é
alterar o conteúdo do “Root Namespace”. Isso fará com que todas as classes de
seu projeto que forem criadas a partir de agora passem a usar este como
namespace.
Entretanto, podemos querer especificar o namespace no nível da classe. Além
disso, quando alteramos o valor aqui não estamos alterando o valor das classes já
criadas. Como fazer isso? Através do comando Namespace.
Apostila Treinamento C#
63
namespace WindowsApplicationCS.Carros { public class Carro { ... } }
No exemplo acima, definimos que a classe Carro pertence ao namespace
“WindowsApplicationCS.Carros”. Essa classe agora só estará automaticamente
visível para as classes que pertençam ao mesmo projeto e ao mesmo namespace.
E agora, como fazemos para que as outras classes enxerguem essa classe?
Fazemos isso adicionando o namespace à lista de namespaces referenciados,
usando o comando using:
Com isso, a partir de agora essa classe possui acesso aos elementos desse
namespace.
Outro uso para Using Além da forma indicada acima, existe outro modo de utilizar o comando Using.
Poderíamos utilizar o comando:
using Car = WindowsApplicationCS.Carros;
Para declarar que, a partir de agora, quando nos referirmos a Car, estamos
apontando para o namespace WindowsApplicationCS.Carros.
O impacto disso é que, a partir deste momento, as referências:
Car.Carro carro = new Car.Carro(); WindowsApplicationCS.Carros.Carro carro = new WindowsApplicationCS.Carros.Carro();
São idênticas!
Apostila Treinamento C#
64
Referências Vimos, na sessão anterior, como fazemos para referenciar uma classe que está em
um outro namespace. E se a classe não estiver apenas em um outro namespace,
mas sim em outro projeto, ou em uma biblioteca externa (como as bibliotecas do
.NET)?
Para fazer com que o seu projeto tenha uma referência para outro, clique com o
botão direito em cima do objeto “References” contido no projeto e selecione “Add
Reference...”.
Nessa tela, você verá a lista de referências guardadas pelo seu projeto. Quando
você clica no botão “Add...”, é aberta a janela “Add Reference”.
Aonde você tem as seguintes tabs:
• “.NET” – Aqui você tem acesso a todas as bibliotecas do .NET, além de
bibliotecas de componentes registradas por terceiros no respositório de
bibliotecas do .NET (também chamado Global Assembly Cache ou GAC);
Apostila Treinamento C#
65
• “COM” – Nesta tab, você tem acesso aos componentes registrados no
COM+. Quando você adiciona uma referência a uma biblioteca do COM+, o
Visual Studio automaticamente gera código que encapsula o acesso ao
componente, para que seja transparente para o desenvolvedor esse
acesso;
• “Projects” – Aqui, você pode dizer que um projeto aponta para outro contido
na mesma solução. Isso significa que o projeto que referencia outro é
sempre compilado depois, e quando o projeto referenciado é compilado, o
Visual Studio faz uma cópia do assembly gerado para a pasta de recursos
do projeto;
• “Browse” – Nesta janela você pode procurar uma biblioteca. É utilizada
quando você vai referenciar componentes que não foram registrados nem
no GAC, nem no COM+, e também não fazem parte da sua solução;
• “Recent” – Contém uma lista dos projetos mais recentemente adicionados a
qualquer projeto.
Todas as opções mostram listas de componentes. Basta selecionar um
componente da lista desejada, e clicar em “OK”. A partir de agora, o projeto já
referencia a biblioteca.
Lab: Trabalhando com Namespace e Referências Vamos agora verificar como trabalhar com namespaces e referências. Para ilustrar
o desenvolvimento, vamos extrair as classes Porta, Carro e CarroEsportivo do
projeto “WindowsApplicationCS”, criar um projeto do tipo biblioteca de classes,
colar as classes nessa biblioteca, e fazer o nosso projeto apontar para essa
biblioteca.
Abra a solução “WindowsApplicationCS”. Clique com o botão direito em cima do
nome da solução, e selecione “Add” > ”New Project”.
Apostila Treinamento C#
66
Selecione o projeto “Class Library”, e dê o nome de “ClassesDeNegocio”. Deixe
que o projeto fique na mesma estrutura da solução, e clique em “OK”.
Verifique que um novo projeto foi adicionado à sua solução:
Agora, clique com o botão direito na “Class1.cs” e remova a mesma da aplicação.
Arraste as suas 3 classes (Carro, CarroEsportivo e Porta) para o novo projeto, e
remova-os da classe original. Abra cada uma das classes e altere o Namespace
para “ClassesDeNegocio”.
Tente compilar novamente a sua solução. Você receberá a seguinte mensagem de
erro:
Apostila Treinamento C#
67
Esse erro ocorre porque o seu projeto “WindowsApplicationCS” não sabe aonde
encontrar a classe “CarroEsportivo”. Vamos agora resolver o problemas,
adicionando a referência correta.
Clique com o botão direito em “References” do projeto “WindowsApplicationCS”, e
selecione “Add Reference”. Na janela que se abre, selecione a tab “Projects”, e o
projeto “ClassesDeNegocio”. Compile sua aplicação e veja o resultado.
Engraçado, agora que eu apontei para a biblioteca correta deveria ter funcionado,
não é? A resposta é não. Eu disse apenas para o .NET incluir a biblioteca quando
for compilar o projeto, mas eu não disse para a minha classe para buscar dentro do
namespace dessa classe as bibliotecas que forem necessárias.
No seu form, adicione o seguinte Namespace:
using ClassesDeNegocio;
Rode agora o seu projeto e você verá que a compilação funcionou. Teste a
aplicação, para garantir que ela faça tudo exatamente como fazia antes.
O resultado desse lab está contido no CD em anexo.
Bibliotecas do Framework .NET 2.0 Quando falamos sobre o Framework .NET, dissemos que existe uma Base Class
Library (BCL) que já vem com diversas classes prontas para serem utilizadas no
.NET, que desempenham rotinas comumente utilizadas, e que podem ser utilizadas
independentemente da linguagem que estivermos utilizando, desde que esta se
baseie sobre o Framework.
Nesta seção falaremos um pouco sobre as bibliotecas mais utilizadas.
O namespace System O namespace System é ande reside a maior parte do Framework .NET. Ele está
contido em System.dll no GAC. Entretanto, o Visual Studio já adiciona a referência
a esta biblioteca automaticamente, independente do projeto.
Na raiz de System estão os tipos básicos do .NET, como System.String,
System.Integer, System.Double.
Apostila Treinamento C#
68
Nota
Embora String, Integer, Double, Single e outros tipos numéricos sejam primordialmente
vistos como simples variáveis, o .NET pode enxergá-los também como objetos. Para que
uma simples soma de dois inteiros não seja uma tarefa de uso intensivo de recursos, o
.NET se vale de uma técnica chamada boxing e unboxing.
Sempre que criamos uma variável, a ela é atribuído um valor e suas operações são feitas
em pilha. Dizemos então que usamos um tipo valor. Se desejarmos usar algum recurso o
objeto System.Int32, o .NET então realiza o boxing e passa a tratar a variável como um tipo
referência. Caso voltemos a fazer operações simples, o .NET realiza o unboxing, e a
variável passa a ser um tipo valor.
Em System também estão classes que agregam métodos de uma funcionalidade
específica. A classe System.Math, por exemplo, contém métodos matemáticos,
como Sin, Cos, Round. A classe System.Console contém métodos para
entrada/saída na console como WriteLine e ReadLine.
O namespace System.Text No namespace System.Text estão agrupadas as classes específicas para
tratamento de textos. Esse namespace também está contido dentro da bibliote
System.dll.
A classe mais usada é a StringBuilder, que fornece uma maneira muito mais
eficiente de fazer concatenação de várias strings.
Dentro de System.Text há um outro namespace, de grande importância para
programadores: o System.Text.RegularExpressions, que permite pesquisa, troca e
quebra de strings segundo critérios de expressões regulares.
O namespace System.Collections O namespace System.Collections contém classes prontas para tratamento de
estruturas de dados. Esse namespace também está contido dentro da bibliote
System.dll.
Essas estruturas contém métodos prontos para adição, remoção e busca interna e
são ferramentas essenciais para programadores.
São elas:
– Stack (pilha), com funcionalidade LIFO (último a entrar, primeiro a sair);
Apostila Treinamento C#
69
– Queue (file), com funcionalidade FIFO (primeiro a entrar, primeiro a sair);
– ArrayList, um array com métodos de inserir/apagar itens em operações
simples. Seus itens são acessados com índices, de modo similar a um
array. A sua grande vantagem é a flexibilidade quando não se sabe a
quantidade de elementos ou quando essa quantidade varia muito, tornando
o ReDim usual, o que é custoso em termos de desempenho da aplicação;
– HashTable, que permite o uso de dados do tipo chave=valor, de modo
similar ao que encontramos em arquivos INI. Seus itens são acessados
através de chave. Esta estrutura de dados é comum e necessária em
muitas aplicações e a sua funcionalidade vai adiantar muitas horas de
programação e correção de bugs;
– SortedList, que reúne as características de um ArrayList e um HashTable.
Seus itens são ordenados de acordo com a chave e podem ser acessados
através do índice ou de sua chave.
Trabalhando com HashTables
Conforme falado, a HashTable é uma estrutura para tratar dados do tipo
chave=valor, assim como podia ser visto em arquivos INI.
O exemplo abaixo demonstra uma classe com um método que preenche uma
HashTable (Preenche) e outra que realiza uma busca por uma chave
(ObtemValor), retornando uma string vazia se não for encontrada ou então o valor
relacionado se a chave não existir.
public class DemoHashTable { Hashtable hs = new Hashtable(); public DemoHashTable() { Preenche(); } private void Preenche(){ hs.Add("Nome", "José"); hs.Add("Sobrenome", "da Silva"); hs.Add("Endereço", "Rua das Árvores, 14"); hs.Add("Cidade", "Fernandópolis"); } public string ObtemValor(string chave){
Apostila Treinamento C#
70
string str = ""; if (hs.Contains(chave)) str = hs[chave].ToString(); return str; } }
O namespace System.IO O namespace System.IO é aonde residem as funções de entrada/saída usadas em
arquivos, em impressoras, em streaming e em aplicações derivadas.
Posteriormente teremos uma seção dedicada ao I/O de arquivos em que usaremos
parte das classes desse namespace. Esse namespace também está contido dentro
da bibliote System.dll.
Escrevendo um arquivo
FileStream fs = new FileStream(@"c:\texto.txt", FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.WriteLine("A raposa "); sw.WriteLine("correu do caçador"); sw.Close();
Lendo um arquivo
StreamReader sr = new StreamReader(@"c:\texto.txt"); StringBuilder sb = new StringBuilder(); while (!sr.EndOfStream) sb.AppendLine(sr.ReadLine()); System.Console.WriteLine(sb);
Tarefas recorrentes Usualmente temos que fazer algumas tarefas que são praxe do dia-a-dia de um
desenvolvedor. Aqui estão algumas:
Acessando o diretório da aplicação string AppDir = System.IO.Path.GetDirectoryName
(System.Reflection.Assembly.GetExecutingAssembly().Location);
Verificando o nome do computador Nome NetBIOS:
string NomeComp = System.Environment.MachineName;
Apostila Treinamento C#
71
Nome DNS:
string nDNS =
System.Net.Dns.GetHostByName("LocalHost").HostName;
Verificando a versão do sistema operacional string osVer = System.Environment.OSVersion;
Verificando o usuário que está rodando o programa string usr = System.Environment.UserName;
Tratamento de Erros – Uso de Try/Catch/Finally O uso de Try/Catch é ferramenta já conhecida de programadores Delphi. O
Try/Catch é uma ferramenta útil e de uso recorrente.
Tratamento estruturado de erros – try/catch Objetos que encontram algum problema durante a sua execução geram exceções
que notificam ao objeto que os chamou algo sobre o problema de funcionamento.
Exceções são objetos da classe System.Exception ou derivadas dela.
Um exemplo para melhor ilustrar: quando temos um vetor com 10 elementos e
tentamos acessar o 11º, é gerado um exception do tipo
IndexOutOfRangeException, que herda de System.SystemException.
Normalmente cada tipo de erro tem uma exception correspondente. Caso um erro
não tenha uma exception correspondente, pode ser usada a classe
System.Exception genérica.
Os tipos mais comuns de exceção são:
• System.Exception – Corresponde a uma exceção genérica;
• System.ApplicationException – Uma exceção que ocorreu na
aplicação;
• System.ArgumentException – Quando um dos parâmetros que
passamos para um método é de um tipo inválido;
Apostila Treinamento C#
72
• System.ArgumentNullException – Disparada quando um dos
parâmetros que você passou para um método continha null, e esse
método não suporta esse valor;
• System.ArgumentOutOfRangeException – Disparada quando um dos
valores passados a um método estoura a capacidade do método;
• System.ArithmeticException – Disparada quando ocorrem erros
aritméticos e de conversão;
• System.InvalidCastException – Disparada quando ocorre um erro de
conversão;
• System.Data.SqlClient.SqlException – Disparada quando ocorre
uma exceção em uma conexão a um banco SQL, utilizando o SqlClient;
• System.Data.OleDb.OleDbException – Similar à versão do
SqlClient, disparado quando ocorre uma exceção em uma conexão via
OleDb;
• System.IO.IOException – Exceção genérica de I/O para disco,
disparada sempre que ocorre um erro de IO.
• System.IO.FileNotFoundException – Disparada quando um arquivo
que você está tentando acessar não existe (herda da IOException);
O tratamento de erros com exception é feito isolando-se partes do código com
try/catch. A instrução try marca o começo do bloco aonde, se for recebida uma
exceção, ela será tratada pelo bloco catch. Dessa forma, aproveitando o exemplo
do IndexOutOfRangeException, definiremos um método aonde o exception
aparece e, quando disparado, escreve “índice fora do limite” no console:
public void TesteDeException() { int[] vetor = new int[3]; try { for (int i = 0; i <= 4; i++) vetor[i] = i; } catch (exception e)
Apostila Treinamento C#
73
{ System.Console.WriteLine("índice fora do limite"); } }
Exceptions são verificadas na ordem em que foram declaradas, assim como o
seria em uma instrução Switch..Case. Se dentro de um try puderem ocorrer
vários exceptions, eles podem ser tratados independentemente:
public void TesteDeException() { int[] vetor = new int[3]; try { for (int i = 0; i <= 4; i++) vetor[i] = i; } catch (ArgumentException e) { System.Console.WriteLine("problemas no argumento"); } catch (IndexOutOfRangeException e) { System.Console.WriteLine("índice fora do limite"); } catch (Exception e) { System.Console.WriteLine(ex.Message); } }
No nosso exemplo, há tratamento para três tipos de exceções: duas são
específicas (ArgumentException e IndexOutOfRangeException) e outra genérica
(Exception).
A primeira exceção a ser testada é ArgumentException, que é disparada quando os
argumentos de uma chamada de método estão com alguma incompatibilidade com
a declaração.
A segunda exceção a ser testada é IndexOutOfRangeException. Como essa é a
exceção que nós sabemos que será disparada, a linha que escreve “índice fora do
limite” é executada e o fluxo segue para o final do try.
A terceira exceção é testada apenas quando as outras não coincidiram com a
exceção que foi disparada. Note que, ao usar a classe Exception, estamos
fazendo algo como um “switch default” de um switch...case. Note também
que temos acesso à mensagem do Exception, através da propriedade Message.
Apostila Treinamento C#
74
Exceções personalizadas Caso você esteja desenvolvendo código e deseje criar exceptions próprias, basta
criar uma classe que herda de Exception, como no exemplo abaixo:
public class MinhaException :Exception { public override string Message { get { return "Ocorreu uma MinhaException"; } } }
Note que neste código, a propriedade Message foi sobrescrita, de forma a retornar
uma string por nós definida.
Disparando exceptions Para disparar exceptions, usamos o comando throw. Nunca se esquecendo que
um Exception nada mais é que um objeto, usamos o comando abaixo para
disparar uma Exception genérica:
public void Abre() { if (trancada) throw new Exception("A porta está trancada"); }
Finally Ao blocos try...catch, é possível usar finally , que é executado sempre,
tenha havido uma exception ou não. Uma utilidade importante dessa instrução é,
por exemplo, fechar um arquivo se houver uma exception de I/O ou fechar uma
conexão com o banco de dados.
public void TesteDeException() { int[] vetor = new int[3]; try { for (int i = 0; i <= 4; i++) vetor[i] = i; } catch (Exception e) { System.Console.WriteLine(ex.Message); }
Apostila Treinamento C#
75
finally { Console.WriteLine("Ocorrendo ou não uma exception, você verá essa mensagem"); } }
Revisão Neste capítulo, vimos o que é um namespace, aprendemos a acessar classes
contidas em outros projetos ou bibliotecas, falamos um pouco sobre algumas das
bibliotecas contidas no Base Class Library do framework.NET, falamos sobre
tarefas recorrentes e, por fim, falamos sobre o conceito de tratamento de erros do
.NET. Nos próximos capítulos, iremos nos aprofundar mais no .NET.
Apostila Treinamento C#
76
Capítulo 7 – XML
Objetivos No mundo conectado de hoje, ser capaz de falar um protocolo comum com
clientes, parceiros e fornecedores torna-se cada vez mais importante. O protocolo
escolhido hoje em dia para isso é o XML. Esse capítulo servirá como uma
introdução ao formato XML. O objetivo deste capítulo é explicar rapidamente o que
é o XML, quais são as diferenças entre XML e HTML, e mostrar como utilizar o
XML em suas aplicações.
O que é XML? A sigla XML vem de Extensible Markup Language, e é uma recomendação do
W3C, como linguagem padrão para a descrição de dados na Web. A sua função é
definir um formato comum para a troca de informações entre diferentes sistemas.
O XML nada mais é que um arquivo texto (com extensão .XML), baseado em tags,
de forma semelhante ao HTML. Entretanto, diferente do HTML, a sua função é
estruturar, armazenar e transportar dados – não como exibi-los. E, para tanto, as
suas tags não são previamente definidas – as tags são definidas pelo autor.
Vejamos um exemplo:
Vemos, nesse exemplo, como seria um XML que representa um pedido de um
cliente. Enteremos o funcionamento desse exemplo nas sessões seguintes.
Apostila Treinamento C#
77
Elementos de um Documento XML Um documento XML, como o mostrado no exemplo, é composto dos seguintes
elementos:
Declaração A primeira linha que compõe um documento XML é a declaração:
<?xml version=”1.0” encoding=”utf-8” ?>
O atributo “version” define a versão do XML que estaremos trabalhando.
O atributo encoding define a codificação dos caracteres que utilizamos quando da
criação do documento. Assim, em nossa declaração definimos que o documento foi
feito utilizando-se da codificação UTF-8.
Tags No XML, uma tag (ou elemento) corresponde a um campo. Assim, quando
definimos:
<Pedido> <IdUsuario>153</IdUsuario> <DataFaturamento>2006-01-10</DataFaturamento> <Itens> <Item id=”1”> <IdItem>5</IdItem> <Quantidade>1</Quantidade> </Item> <Item id=”2”> <IdItem>2</IdItem> <Quantidade>5</Quantidade> </Item> </Itens> </Pedido>
Definimos que um Pedido possui um IdUsuario, DataFaturamento, e uma coleção
de Itens, onde cada Item dessa coleção é definido como tendo um IdItem e uma
Quantidade.
Um documento XML deve possuir a seguinte estrutura:
<root> <child> <subchild>...</subchild> </child> </root>
Apostila Treinamento C#
78
Uma tag (ou elemento) pode ter diversos tipos de conteúdos diferentes, e inclui
tudo entre o inicio de uma tag, até o final da tag de fechamento. Assim, ela pode
conter texto, outras tags e atributos.
Deve-se notar que no XML:
• Todas as tags precisam ter uma tag de fechamento;
• As tags são case-sentitive – ou seja, <Pedido> é diferente de <pedido>;
• As tags XML devem vir na ordem correta – Não é válido algo do gênero:
<Item><IdItem>5</Item></IdItem>;
• Todos os documentos XML devem ter uma tag inicial (que define o objeto
que é descrito pelo documento), e essa tag deve ser única – a chamada
“root”.
A nomenclatura das tags no XML deve seguir as seguintes regras:
• Podem conter letras, números e outros caracteres;
• Não devem começar com números ou caracteres de pontuação;
• Não podem começar com xml (ou Xml, XML, etc);
• Não podem conter espaços.
Entretanto, como os dados de um arquivo XML geralmente mapeiam dados de um
banco, ou outra fonte de dados, como boas práticas adotam-se em geral algumas
outras restrições recomendadas:
• Use nomes descritivos, mas não exagere no tamanho;
• Evite usar símbolos matemáticos (=, -, +, /, :);
• Caracteres específicos de língua são válidos – entretanto, isso pode causar
problemas quando outra empresa for consumir os seus dados. Desta forma,
evite-os;
Apostila Treinamento C#
79
Atributos No XML, uma tag pode possuir um ou mais atributos. Atributos, em geral, carregam
informação que não é parte do dado, mas que é importante para o programa que
está manipulando os dados entender do que se trata.
<Item id=”1”>
No exemplo acima, dissemos ao programa que irá tratar o XML que esse é o
primeiro item da lista de itens do usuário.
Atributos precisam sempre ser definidos entre “” ou ‘’. Se internamente ao elemento
já houver “” ou ‘’, é necessário utilizar a outra opção na definição.
Apesar dos atributos poderem conter dados, assim como as tags, elas possuem
diversas desvantagens quanto a estas:
• Atributos não podem conter múltiplos filhos (como uma tag pode);
• É mais complexo adicionar um novo atributo do que uma nova tag;
• A validação dos dados do documento é mais complexa contra atributos;
• Eles tornam mais difícil a leitura e manutenção de um documento.
Comentários Como no HTML, no XML os comentários são feitos utilizando-se “<!-- ... -->”:
<!-- Este é um comentário! -->
XML Bem Formado Diz-se que um XML é bem formado, quando ele atende as regras de sintax do
XML, que foram descritas anteriormente.
Definindo a Estrutura do Documento Dissemos que o XML foi desenvolvido para que fosse possível a intercomunicação
entre diferentes sistemas pela internet. Também dissemos que o formato do
documento XML é definido pelo usuário. Assim sendo, como fazemos com que um
sistema reconheça o formato do documento que estamos enviando? Além disso,
como verificamos que um documento atende aos requisitos corretos (por exemplo,
o campo DataFaturamento contém uma data válida)?
Apostila Treinamento C#
80
Fazemos isso através da criação de um documento que define a estrutura do
nosso XML. Existem duas formas de fazer essa definição: através de DTD, ou
usando Schemas. O DTD foi a primeira definição de um formato de documento;
entretanto, os XML Schemas estão substituindo esse formato, e vem se tornando o
padrão. Não é o objetivo deste curso entrar em detalhes na criação de um DTD ou
de um XML Schema, mas mais informações podem ser encontradas na bibliografia
indicada no final da apostila.
Imaginando um XML do tipo:
<Pedido> <IdUsuario>12</IdUsuario> <DataFaturamento>2006-03-02</DataFaturamento> <Itens> <Item id=”1”> <IdProduto>5</IdProduto> <QtdProduto>1</QtdProduto> </Item> <Item id=”2”> <IdProduto>123</IdProduto> <QtdProduto>10</QtdProduto> </Item> </Itens> </Pedido>
Um exemplo de DTD:
<?xml version="1.0"?> <!DOCTYPE Pedido [ <!ELEMENT Pedido (IdUsuario,DataFaturamento,Itens)> <!ELEMENT IdUsuario (#PCDATA)> <!ELEMENT DataFaturamento (#PCDATA)> <!ELEMENT Itens (Item*)> <!ELEMENT Item (IdProduto,QtdProduto)> <!ELEMENT IdProduto (#PCDATA)> <!ELEMENT QtdProduto (#PCDATA)> <!ATTLIST Item id CDATA “0”> ]>
Um exemplo de Schema:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.cges.com.br/XMLSchema" targetNamespace="http:// www.cges.com.br " xmlns="http:// www.cges.com.br " elementFormDefault="qualified"> <xs:element name="Pedido"> <xs:complexType> <xs:sequence>
Apostila Treinamento C#
81
<xs:element name="to" type="xs:string"/> <xs:element name="from" type="xs:string"/> <xs:element name="heading" type="xs:string"/> <xs:element name="body" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
Além da definição da estrutura, você precisa de um “parser”, ou seja, um programa
que seja capaz de validadar a estrutura do XML e confirmar a sua validade. Os
browsers mais modernos já possuem parsers embutidos, e o .NET, através da
biblioteca System.Xml, possui classes e métodos que permitem trabalhar com os
documentos XML, e realizar a sua validação.
Revisão Nesse capítulo, vimos o que é um documento XML, como este é formado e como
fazemos a validação da estrutura do documento e dos dados contidos nele.
Apostila Treinamento C#
82
Capítulo 8 – ADO.NET
Objetivos Neste capítulo, vamos estudar o funcionamento do ADO.NET, o novo pacote de
classes que expõe serviços de acesso a dados para a programação .NET. Iremos
ver quais são os classes do ADO.NET que permitem abrir uma conexão, executar
comandos, e recuperar dados do banco – incluindo o estudo do importante objeto
DataSet, que permite trabalhar de forma desconectada com uma cópia dos dados
na memória, e como fazer para utilizá-lo para recuperar dados de um arquivo XML.
O que é o ADO.NET O ADO.NET é um pacote de classes que expõe serviços de acesso a dados para a
programação .NET. Ele veio para substituir o RDO, o DAO, e por fim o ADO.
Além de ser totalmente aderente ao .NET, ele traz vantagens consideráveis, tais
como:
– Acesso desconectado a dados;
– Provedores de acesso dedicados a fornecedores de bancos de dados;
– Dataset que permite agregar várias tabelas e apontar relacionamentos;
– Manipulação direta de XML;
– Possibilidade de popular dados a partir de arquivos XML, objetos, etc.
Providers do .NET O .NET possui provedores especializados para bases de dados de diferentes
fornecedores.
A maior vantagem de se usar provedores especializados é que eles são escritos de
forma a aproveitar o melhor que o sistema gerenciador de banco de dados oferece.
Os provedores que estão disponíveis por default são:
– Data Provider for SQL Server (System.Data.SqlClient);
Apostila Treinamento C#
83
– Data Provider for OLEDB (System.Data.OleDb);
– Data Provider for ODBC (System.Data.Odbc);
– Data Provider for Oracle (System.Data.OracleClient).
É possível acessar bancos de dados usando os provedores ODBC e OLEDB, mas
os provedores especializados oferecem acesso otimizado e mais rápido, além de
acesso à características específicas de cada banco.
Modelo ADO.NET
Connection O objeto Connection é encontrado dentro do provider. Os objetos default do .NET
são SqlConnection, OracleConnection, OleDbConnection, OdbcConnection .
Além da especificidade da base de dados a ser acessada, a classe Connection
provê métodos e propriedades similares aos encontrados no objeto Connection
antigo. As strings de conexão antigas também são similares às usadas no .NET.
Command O objeto Command, já velho conhecido do ADO, recebeu novas funcionalidades no
ADO.NET.
Do Command é a responsabilidade de receber instruções SQL (e chamadas de
Stored Procedures).
DataSet
Connection
DataReader
Command
DataAdapte
r
WindowsFor
m
WebForm
Classes
WebServices
Provider
ADO.NET Consumidores
Apostila Treinamento C#
84
O Command faz parte do conjunto de componentes que um Provider oferece, e
existe um Command para cada provedor: SqlCommand, OracleCommand,
OleDbCommand, OdbcCommand.
Assim como no ADO, o Command do ADO.NET tem uma coleção de parâmetros
(Parameters) que são passados para instruções SQL.
O Command possui quatro métodos que são usados com freqüência:
– ExecuteReader: retorna um DataReader, objeto usado para leitura rápida
da base de dados. O DataReader será assunto do próximo tópico;
– ExecuteNonQuery: usado quando o comando SQL não retornará nenhum
tipo de dado (como instruções INSERT, por exemplo);
– ExecuteScalar: quando o comando SQL retorna um único valor (como um
select count(*), por exemplo);
– ExecuteXMLReader: idem ao ExecuteReader, retorna um XMLReader.
DataReader O DataReader é um objeto de leitura de dados, rápido e eficente, que funciona
como um antigo Recordset marcado com a opção adOpenForwardOnly: ele
promove escrita “somente adiante”, sem possibilidade de navegar registros para
trás, e tembém read-only.
A grande vantagem do DataReader é a sua velocidade: ele deve ser usado quando
for necessário ler grandes quantidades de dados que não serão modificados como,
por exemplo, em relatórios ou listagens.
O DataReader é específico de cada provedor: SqlDataReader, OracleDataReader,
OleDbDataReader, OdbcDataReader.
O DataReader é uma classe estática e nunca deve ser instanciado. Ele deve
sempre receber a referência de um outro objeto que retorne um DataReader, como
por exemplo um objeto Command, como veremos no exemplo abaixo.
Para usar o DataReader, criaremos um objeto Connection que acessa a base
NorthWind, inseriremos o comando de consulta (instrução SQL) e chamaremos o
Apostila Treinamento C#
85
método ExcecuteReader. A leitura é feita em um loop que chama o método Read(),
como demonstrado abaixo:
StringBuilder sb = new StringBuilder(); SqlConnection cn = new SqlConnection(); cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=c:\\somepath\\mydb.mdb; " + "User Id=admin; Password=MyPass;"; SqlCommand cmd = new SqlCommand(); cmd.Connection = cn; cmd.CommandText = "select * from customers"; cn.Open(); SqlDataReader dr; dr = cmd.ExecuteReader(); while (dr.Read()) { sb.Append(dr["CompanyName"]); sb.Append(";"); } dr.Close(); cn.Close();
Note que não fazemos mais a verificação de EOF e nem precisamos nos
preocupar com MoveNext. Ao chamarmos Read() ele já move o cursor um registro
à frente e retorna True, ou retorna False se não houver mais registros a serem
lidos.
DataAdapter O DataAdapter é um objeto especializado em intermediar as requisições de acesso
a dados da aplicação e o banco de dados.
A idéia do DataAdapter é prover a parte funcional do acesso aos dados,
agreagando dentro de si objetos do tipo Command (um para select, um para
update, um para insert e outro para delete).
Do DataAdapter é a responsabilidade de preencher (ou popular) um Dataset, e
também receber do DataSet modificações e executá-las no banco de dados.
Cada provedor tem um DataReader específico. São eles: SqlDataAdapter,
OracleDataAdapter, OleDbDataAdapter e OdbcDataAdapter.
Através do método Fill do DataAdapter, preenchemos DataTables de DataSets,
conforme será mostrado e exemplificado no próximo tópico.
Apostila Treinamento C#
86
Criando comandos automaticamente: o CommandBuilder A classe CommandBuilder permite que sejam criados objetos Command para
atualizar (update), inserir (insert) ou apagar (delete) registros de um dataset.
A grande vantagem de usar o CommandBuilder é que não é necessário especificar
a lista de campos a serem alterados nem especificar um objeto Parameter para
cada um deles.
O CommandBuilder pode ser usado apenas quando usamos um SelectCommand
simples, que usa um comando SELECT em uma tabela (e não uma stored
procedure ou select em uma view) e que não use cláusulas mais complexas, como
JOIN.
Ao ser chamado, o CommandBuilder:
1. conecta na base de dados e obtém o esquema da tabela;
2. prepara os comandos correspondentes, usando a lista de campos
obtida;
3. instancia objetos Parameter, de acordo com o tipo de cada campo.
O CommandBuilder faz parte das classes especificas de cada provider, por isso há
um command builder para cada provider.
O exemplo abaixo ilustra como criar um objeto CommandBuilder e fazer com que
ele crie automaticamente os comandos de update, insert e delete. A classe recebe
como parâmetro um DataSet que sofreu atualizações, replicando-as para o banco
de dados. O procedimento abaixo também espera que o DataSet contenha uma
tabela Clientes que foi populada com o comando SQL select * from Customers:
public void Atualiza(DataSet ds) { SqlConnection cn = new SqlConnection("Data Source=TOMAC;Initial" + "Catalog=Northwind;Integrated Security=True"); SqlCommand cmd = new SqlCommand("select * from Customers", cn); SqlDataAdapter da = new SqlDataAdapter(cmd); SqlCommandBuilder cb = new SqlCommandBuilder(da); da.UpdateCommand = cb.GetUpdateCommand(); da.InsertCommand = cb.GetInsertCommand();
Apostila Treinamento C#
87
da.DeleteCommand = cb.GetDeleteCommand(); da.Update(ds.Tables["Clientes"]); cn.Close(); }
DataSet O DataSet é um objeto genérico do ADO.NET, independente de qual provedor está
sendo usado para acesso aos dados.
Sua função é gerenciar dados previamente adquiridos por acesso a bancos de
dados, acesso a arquivos texto ou XML e também por mapeamento de objetos.
O DataSet é visto pelos programadores ADO como um “recordset vitaminado”, mas
ele é muito mais do que isso. O Recordset é capaz de armazenar apenas um
conjunto de dados. O DataSet pode armazenar vários conjuntos, organizados em
DataTables.
DataTables são estruturas em memória que reproduzem as funcionalidades de
uma tabela de um banco de dados. DataTables podem ter restrições (como chaves
primárias, por exemplo), através da coleção Constraints e podem ser relacionadas
entre si, através de relações, que são adicionadas à coleção Relations.
Após obtidos, os dados permanecem no DataSet e é feita a desconexão com a
base de dados, conexão que só voltará a ser estabelecida quando for necessária
alguma operação de escrita na base ou quando se desejar obter novamente os
dados.
Nota
Tenha sempre em mente que o DataSet é preenchido com todos os registros retornados
pelo comando SQL que foi colocado no DataAdapter. Se esse comando retornar um
milhão de registros, serão trafegados um milhão de registros pela rede de uma só vez, e
um milhão de registros que serão alocados em uma estrutura de memória.
Apostila Treinamento C#
88
Se a sua aplicação trabalhava com resultsets grandes, que também eram custosos em
termos dde processamento e alocação de cursor do lado do servidor, pode ser esta a hora
de rever o seu modelo de acesso a dados.
No ADO.NET 2.0 há novidades, como a possibilidade de usar um DataReader em
um DataTable, updates em batch, entre outros.
Populando e iterando por um DataSet O exemplo abaixo ilustra um exemplo típico de um DataSet e um DataAdapter:
OleDbConnection cn = new OleDbConnection(); cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=c:\\nwind.mdb;User Id=admin;Password=;"; OleDbDataAdapter da = new OleDbDataAdapter("select * from Customers", cn); DataSet ds = new DataSet("Clientes"); da.Fill(ds, "Clientes"); foreach( DataRow dr in ds.Tables["Clientes"].Rows) { Console.WriteLine("" + dr["CompanyName"] + ":" + dr["ContactName"]); }
Primeiro é criada a conexão com a base de dados de teste note que a base de
dados de exemplo NWind.mdb deve estar no diretório-raiz; caso ela esteja em
outro diretório basta alterar a string de conexão). Depois, é criado um DataAdapter,
que recebe o comando SQL e a conexão. O comando da.Fill instrui o DataAdapter
a conectar-se ao banco executar o SQL e preencher o DataTable Clientes do
DataSet ds com os dados obtidos como resultado.
Note também que usamos um loop foreach para iterar ao longo de uma DataTable
do DataSet. Esse tipo de construção é robusto e evita erros com índices, o que por
vezes acontecia quando usávamos construções de loops For que iteravam usando,
por exemplo, propriedades como Count.
Filtrando dados em um DataSet Embora os dados devam ser filtrados preferencialmente na origem dos dados
(usando cláusulas where) e deva ser repassado ao DataSet apenas os registros
que correspondam a uma regra, muitas vezes se deseja filtrar dados que já estão
em um DataSet.
Apostila Treinamento C#
89
Para filtrar os dados em um DataSet existe o método Select, que recebe como
parâmetro um String contendo cláusulas como as que usaríamos em um where de
uma instrução SQL. O exemplo abaixo mostra como filtrar os registros cuja coluna
CustomerID começa com “A”:
DataRow[] rows; rows = ds.Tables["Clientes"].Select("CustomerID LIKE 'A%'");
A maioria das regras de sintaxe do SQL se aplica ao método Select de um
DataSet, bem como os comandos: And, Or, Not, >, <, <>, =, CONVERT, LEN,
ISNULL, IIF são exemplos. Consulte a documentação do DataSet para ver todas as
opções.
Existem também métodos Select sobrecarregados que permitem ordenar os
campos como em uma instrução ORDER BY do SQL ou ainda filtrar de acordo com
o RowState.
O exemplo abaixo filtra os clientes brasileiros os e ordena em ordem alfabética
descrescente:
DataRow[] rows; rows = ds.Tables["Clientes"].Select("County = 'Brazil'", "CustomerName DESC");
Procurando por uma informação em um DataSet Existe uma outra forma de procurar por um determinado registro que é usada
apenas para buscas no campo de chave primária. O exemplo abaixo demonstra o
seu uso:
DataRow[] rows; rows = ds.Tables["Clientes"].Rows.Find("KOENE");
DataViews Assim como as Views de um banco de dados permitem criar uma estrutura de
dados filtrados e ordenados a partir de um DataTable.
Nota
Há diferenças entre o uso do método Select do DataTable e um DataView. O Select retorna
um conjunto de linhas copiadas de um DataTable, enquanto o DataView continua ligado ao
DataTable, e todas as alterações que forem feitas em um serão refletidas no outro.
Apostila Treinamento C#
90
Além disso, o DataView pode ser usado como DataSource de controles visuais, como um
DataGrid ou um TextBox, entre outros.
O exemplo abaixo filtra os registros cujo CustomerID começa com “A” e ordena pelo campo
CustomerName usando um DataView. Note que o DataView também serve como
DataSource para um DataGridView.
OleDbConnection cn = new OleDbConnection(); cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=c:\\nwind.mdb;User Id=admin;Password=;"; OleDbDataAdapter da = new OleDbDataAdapter("select * from Customers", cn); DataSet ds = new DataSet("Clientes"); da.Fill(ds, "Clientes"); DataView dv = new DataView(); dv.Table = ds.Tables["Clientes"]; dv.RowFilter = "CustomerID LIKE 'A%'"; dv.Sort = "CutomerName ASC"; DataGridView1.DataSource = dv;
Atualizando o banco com informações do DataSet Para atualizar um banco de dados, devemos usar um DataAdapter para que ele
faça a conexão com o banco de dados e faça as operações necessárias. Para
tanto, devemos configurar as instruções de INSERT, UPDATE e DELETE
apropriadamente, usando as respectivas propriedades InsertCommand,
UpdateCommand e DeleteCommand do DataAdapter, bem como os seus
parâmetros.
A cada linha de um DataSet é atribuída uma propriedade RowState, que reflete o
estado dos dados daquela determinada linha. Os valores possíveis são:
Added A linha foi adicionada e AcceptChanges não foi chamado
Deleted A linha foi marcada para ser apagada
Detached Acontece imediatamente depois de a linha ter sido criada
mas ainda não foi adicionada à coleção de linhas do
DataTable
Modified A linha foi modificada desde o último AcceptChanges
Apostila Treinamento C#
91
Unchanged A linha permanece a mesma desde o último AcceptChanges
O exemplo abaixo ilustra esse processo, supondo que já exista um objeto
Connection instanciado e que os únicos campos do DataSet que sofrem
atualização são CompanyName e ContactID:
StringBuilder sb = new StringBuilder(); sb.Append("UPDATE Customers "); sb.Append("SET CompanyName = @CompanyName, "); sb.Append(" ContactName = @ContactName "); sb.Append("WHERE (CustomerID = @CustomerID)"); da.UpdateCommand = new SqlCommand(sb.ToString(), cn); da.UpdateCommand.Parameters.Add("@CompanyName", SqlDbType.VarChar, 255, "CompanyName"); da.UpdateCommand.Parameters.Add("@ContactName", SqlDbType.VarChar, 255, "ContactName"); da.UpdateCommand.Parameters.Add("@CustomerID", SqlDbType.VarChar, 255, "CustomerId"); da.Update(ds.Tables("Clientes"));
Note a sintaxe que foi usada: foram criados parâmetros, que começam com @,
para cada variável que usaremos na atualização. Logo após, para cada um desses
parâmetros, informamos um tipo e tamanho de campo (no caso, usamos em todos
o tipo SqlDbType.VarChar com tamanho 255) e, por fim, indicamos a que coluna
do DataSet o parâmetro corresponde.
Por último, a instrução Update atualiza a base de dados. Todos os registros com
RowState Modified serão atualizados na base.
Acessando arquivos XML Esta seção tem por fim apenas ilustrar como usar um DataSet simples que lê ou
que grava em arquivos XML.
Gravando arquivos XML a partir de um DataSet A classe DataSet contém dois métodos para serem usados na escrita de arquivos
XML: WriteXML e WriteXMLSchema.
Apostila Treinamento C#
92
O método WriteXMLSchema permite que um DataTable populado possa ter o seu
esquema (definições de campos) salvos em um arquivo.
O método WriteXML permite que os dados de um DataTable sejam gravados em
um arquivo XML.
O exemplo abaixo ilustra os dois métodos, rode-o e veja os resultados nos dois
arquivos de saída:
OleDbConnection cn = new OleDbConnection(); cn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=c:\\nwind.mdb;User Id=admin;Password=;"; OleDbDataAdapter da = new OleDbDataAdapter("select * from Customers", cn); DataSet ds = new DataSet("Clientes"); da.Fill(ds, "Clientes"); DataView dv = new DataView(); dv.Table = ds.Tables["Clientes"]; dv.RowFilter = "CustomerID LIKE 'A%'"; dv.Sort = "CutomerName ASC"; ds.WriteXml("c:\\saida.xml"); ds.WriteXmlSchema("c:\\saida.xsd"); cn.Close();
Lendo arquivos XML em um Dataset A leitura de um arquivo XML requer que seja informado não só o arquivo de dados,
mas também um arquivo contendo as definições de cada campo. Caso não exista,
o objeto DataSet tenta inferir o esquema, ou seja, tenta criar sozinho o esquema, o
que funciona na maioria dos casos.
Para ler o esquema, usa-se o método ReadXmlSchema, e para ler o arquivo XML,
ReadXml.
O código abaixo lê um arquivo XML e popula um DataGridView com os dados
obtidos.
DataSet ds = new DataSet(); ds.ReadXmlSchema("c:\\saida.xsd"); ds.ReadXml("c:\\saida.xml"); DataGridView1.DataSource = ds.Tables(0);
Apostila Treinamento C#
93
Experimente tirar a segunda linha (que chama ReadXmlSchema) do código e veja
que o objeto DataSet foi capaz de inferir sozinho o esquema do XML.
Trabalhando com nulos Os campos de um banco de dados têm que ter uma forma de indicar se estão ou
não vazios. Um campo do tipo VarChar poderia conter uma string “” para indicar
isso, mas o que conteria um campo Int? 0? E quando precisarmos representar o
valor zero? Para isso, foi desenvolvido o tipo “Null” – para representar que o
conteúdo de um campo é nulo.
Entretanto, o significado de nulo em um banco de dados e no .NET são diferentes.
No .NET, um nulo significa apenas que a variável não aponta para lugar nenhum
da memória.
E como fazemos essa conversão? Ao fazer conversão de um dado nulo para uma
variável .NET, há três formas de fazer o tratamento:
1. IsDbNull: a função IsDbNull retorna True se o valor a ser verificado contiver
nulo;
2. DbNull.Value: deve ser usado em uma comparação, como no exemplo:
If (a == DbNull.Value) { ... }
3. Fazendo conversão com ToString(): nesse caso, o método retornará uma string
vazia se exisitir um valor nulo.
Revisão Neste capítulo, estudamos o funcionamento do ADO.NET, o novo pacote de
classes que expõe serviços de acesso a dados para a programação .NET. Vimos
um pouco sobre os diferentes DataProviders que acompanham o .NET 2.0 e qual o
novo modelo de objetos do ADO.NET. Além disso, estudamos o importante objeto
DataSet, que permite trabalhar de forma desconectada com uma cópia dos dados
na memória. Para completar, vimos como usar o DataSet para buscar dados de um
arquivo XML, e como lidar com dados nulos.
Apostila Treinamento C#
94
Capítulo 9 – Trabalhando com Windows Forms
Objetivos Neste capítulo, iremos estudar um pouco sobre programação para Windows no C#
2.0, com o objetivo de desenvolver no leitor a curiosidade de experimentar e
aprender como funciona. Vamos mostrar como é possível trabalhar com janelas,
usando formulário MDI, como adicionar controles aos seus formulários, como
definir uma janela Master, da qual outros formulários herdam e como tratar eventos
disparados pelo usuário. Além disso, como algumas vezes é necessário
desenvolver controles personalizados, falaremos como criar um User Control, e
utilizar o mesmo nos seus formulários. Por fim, trataremos um pouco sobre acesso
a dados em um Windows Form.
Formulários MDI Um formulário MDI (Multiple Document Interface) permite que sejam abertos e
confinados outros formulários dentro dele, como ilustrado:
Para criar o formulário-pai, pode ser feito de duas formas:
Apostila Treinamento C#
95
1. Usando o assistente, que está acessível ao se clicar no projeto, escolhendo
a opção Add e depois New Item. Na janela que se abrirá, uma das opções é
o MDI Parent Form. Dessa forma é criado um formulário com vários
componentes já configurados, como menu e status bar entre outros;
2. Criando um novo formulário e marcando a propriedade IsMDIParent com
True.
Para chamar formulários-filho, basta criar formulários comuns e, quando eles forem
abertos pelo formuário MDI principal, a partir de um menu, botão, eventos ou outra
forma, deve ser usado código similar ao apresentado abaixo:
' o formulário-filho foi chamado de Form1 Form1 f1 = new Form1(); ' determina que o formulário-pai é o formulário ' em que está sendo feita a chamada f1.MdiParent = this; ' opcional, faz com que o formulário inicie maximizado f1.WindowState = FormWindowState.Maximized; ' abre o formulário f1.Show();
Herança de formulários Formulários podem também ser herdados, permitindo que se desenhe um
formulário “master” e que qualquer mudança seja replicada para todos os seus
descendentes.
Para criar um novo formulário e herdar as características de outro formulário, basta
acrescentar o comando Inherits à declaração do formulário, como no exemplo
abaixo:
public class Form2 : Project1.Form1
Nota
Perceba que, conforme ilustrado, o deve ser informado o nome do projeto e o nome do
formulário a ser herdado. Caso seja informado apenas o nome do formulário, o próprio
Visual Studio gerará um erro e mostrará a sugestão para fazer com que o código funcione.
Apostila Treinamento C#
96
No exemplo acima, todos os controles e propriedades de Form1 serão herdados
por Form2, e as propriedades dos controles que foram herdados não poderão ser
alteradas. Podemos, entretanto, sobrescrever métodos e propriedades declarados
em Form1 que foram declarados com Overridable.
User Controls User Controls são controles ou grupos de controles criados pelo desenvolvedor.
Em relação aos controles ActiveX usados anteriormente, os User Controls são
mais completos e são mais fáceis de distribuir, de usar e serem extendidos, além
de serem aderentes à plataforma .NET.
Com os user controls podem ser criados modelos de controles que podem ser
repetidos e aplicados em outros formulários, a partir da Toolbox do Visual Studio
ou instanciados via código na aplicação.
User controls trazem grandes vantagens e facilidades: eles podem encapsular
controles ou grupos de controles que são usados recorrentemente em nossa
aplicação. Se tivermos um mesmo user control espalhado ao longo de vários
formulários, se fizermos uma alteração no user control, essa mudança será
replicada para todos os formulários que o usarem.
Embora isso possa parecer uma grande vantagem, também traz um inconveniente:
caso você, por exemplo, precise deixar o seu user control maior em tamanho de
tela, isso pode afetar o lay-out de formulários que já o usavam. Projete o user
control com cuidado para isso não acontecer.
Adicionando um controle programaticamente Adicionamos um controle programaticamente, adicionando o mesmo à coleção de
controles do Formulário:
this.Controls.Add(f1);
Disparando eventos de um controle Em controles (ou user controls) criados por nós ou herdados podemos criar novos
eventos para adicionar maior interação entre o formulário ou os containers e o
nosso controle (ou user control).
Apostila Treinamento C#
97
Para criar um evento, precisamos primeiro criar um Delegate. Um delegate
funciona como uma referência para um método. Ele deve ser declarado fora da
classe que irá dispará-lo, e deve ter visibilidade pública.
public delegate void MyEventHandler(object sender, EventArgs e);
Em seguida, dentro da classe declare um evento do tipo do delegate criado:
public event MyEventHandler MyEvent;
Para que a sua classe dispare esse evento, você precisa agora chamar o evento
criado, como no exemplo:
private void btnHelloWorld_Click(object sender, EventArgs e) { MyEvent(this, new EventArgs()); }
Por fim, quando você for consumir o controle, você precisa indicar qual método
será disparado quando o evento ocorrer:
myControl1.MyEvent += new MyEventHandler(myControl1_MyEvent);
A próxima seção exemplifica com código o uso de user controls e de eventos.
Lab: Criando um User Control O exemplo que será seguido aqui é um controle simples de formulário de login,
contendo uma caixa de texto para que o usuário entre o seu login e outra para a
sua senha, uma label para cada caixa de texto e um label que mostrará
mensagens de erro e um botão “Login”.
A lógica e os dados de autenticação serão, apenas para esse exemplo, embutidos
no código para fins didáticos, mas saiba que essa é uma prática que nunca deve
ser usada em aplicações que serão usadas em produção.
O controle avisará o usuário quando for feito o login ou quando houver um erro, e
isso será feito através de eventos.
Para começar, adicione um novo Windows Form chamado “FormLogin”. Adicione,
também, um User Control chamado “UCLogin” (Para criar um novo User Control,
Apostila Treinamento C#
98
usando o Solution Explorer, clique no projeto com o botão direito do mouse e clique
em Add e logo em seguida em User Control).
Agora, adicione ao seu controle:
Controle Propriedade Valor Label Text “Usuário:” Label Text “Senha:” TextBox (Name) “txtUsuario”
(Name) “txtSenha” TextBox PasswordChar * (Name) “btnLogar” Button Text “Logar”
Fora da sua classe, crie agora 2 delegates:
• UsuarioLogadoEventHandler – Evento que será disparado quando o
usuário se logar corretamente.
• LoginInvalidoEventHandler – Evento que será disparado quando o login
e/ou a senha forem inválidos.
Crie, agora dentro da classe do controle, 2 eventos:
• OnUsuarioLogado;
• OnLoginInvalido.
...que irão disparar os delegates respectivos.
Por fim, crie uma lógica de negócios que aceite:
• Usuário: “AdoptionLab”;
• Senha: “AdoptionLab”
...como resposta correta – a que dispara o evento OnUsuarioLogado – e que
qualquer outra resposta dispare o evento OnLoginInvalido.
Depois de criado o user control, faça um Build na Solution que estamos usando.
Verifique que o user control que criamos deverá aparecer no ínício da Toolbox:
Apostila Treinamento C#
99
O nosso user control é um novo controle que pode ser arrastado para um
formulário e pode ter as propriedades verificadas e confguradas através da caixa
de propriedades.
Arraste o nosso controle para o FormLogin. Observe agora as propriedades do
controle criado. Veja também que na lista de eventos aparecem os dois eventos
por nós criados:
Através desses eventos, podemos criar métodos que serão chamados quando um
deles for disparado pelo user control que criamos. Clique duas vezes em cada um
dos eventos criados, para gerar automaticamente o código de tratamento do
evento. Pode-se também gerar esses eventos de forma manual, conforme
explicado no tópico “Disparando eventos de um controle”.
Agora insira código de validação para cada um dos eventos, que mostra uma
mensagem na tela caso o usuário tenha logado corretamente, ou não.
Agora, existe mais um pequeno passo necessário antes que possamos prosseguir.
Se executarmos a nossa aplicação, ele irá automaticamente chamar o Form1. Não
queremos isso. Como fazemos então?
Apostila Treinamento C#
100
Clique duas vezes na classe “Program.cs”. No método Main, comente a linha
aonde está escrito:
Application.Run(new Form1());
E insira uma nova linha, escrita:
Application.Run(new FormLogin());
Isso fará com que a sua aplicação inicie agora pelo FormLogin. Rode a sua
aplicação e veja o resultado.
Após esse teste, volte a linha do “Program.cs” para o valor original. O código fonte
com o resultado esperado desse lab está contido no CD.
Respondendo a eventos de teclado É comum encontrar no mercado sistemas que precisem responder a eventos de
teclado, quer para validar a entrada, quer para tornar mais fácil a navegabilidade.
Eventos de teclado podem ser respondidos usando os já conhecidos eventos de
KeyDown, KeyUp, KeyPressed, TextChanged.
Data Binding Através do DataBinding, podemos vincular controles a objetos que manipulam
dados, tornando fácil a navegação e a alteração de informações nele contidas.
DataSource Diversos controles que vêm por padrão com o .NET já possuem características que
tornam possível associá-los diretamente com as fontes de dados (através de um
Apostila Treinamento C#
101
DataSet, um ArrayList, etc), facilitando o processo de manipulação e exibição
desses dados.
Para facilitar a manipulação dos dados a partir de fontes de dados, o .NET traz o
controle DataGridView. Esse controle é o controle mais poderoso contido no .NET
para trabalhar com dados, e será estudado nas próximas seções.
Alguns controles (no caso, a ComboBox e a ListBox) possuem 3 propriedades
muito importantes, que facilitam a vinculação:
• DataSource – Define a fonte de dados.
• DisplayMember – Define o campo que será usado como valor a ser exibido.
• ValueMember – Define o valor do campo (uso interno).
Vejamos um exemplo, de como popular um ListBox (o mesmo princípio se aplica a
uma ComboBox):
// Esta parte você já viu... string connectionString = "Data Source=CAIOWAA\\SQLEXPRESS;Initial " + "Catalog=Northwind;Integrated Security=True"; SqlConnection cn = new SqlConnection(connectionString); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand("SELECT * FROM Customers", cn); DataSet ds = new DataSet(); da.Fill(ds); // Essa parte é responsável pela conexão. lstCustomers.DataSource = ds.Tables[0]; lstCustomers.DisplayMember = "ContactName"; lstCustomers.ValueMember = "CustomerID";
Esses controles possuem as seguintes propriedades:
• SelectedItem – Essa propriedade retorna um objeto que representa o item
da seleção.
• SelectedValue – Esta propriedade representa o valor do item selecionado (a
propriedade configurada por ValueMember).
Apostila Treinamento C#
102
DataBinding Entretanto, esse não é o único modo de conectar um controle a uma fonte de
dados. Como dito anteriormente, poucos controles expõe a propriedade
DataSource. Se for assim, então como devo fazer?
Os controles Windows Forms (assim como as classes que herdam de UserControl)
implementam também uma propriedade chamada DataBindings. Essa propriedade
retorna uma coleção de vínculos (bindings) entre o controle a alguma fonte de
dados. Usando o método Add da coleção, podemos adicionar vínculos de nosso
controle com diversas fontes de dados.
O método DataBindings.Add aceita diversos parâmetros, dentre os quais os mais
importantes para nós são:
• propertyName – Nome, no formato texto, da propriedade do controle que
será vinculada;
• dataSource – Objeto da fonte de dados;
• dataMember – Campo da fonte de dados que será vinculada.
Vamos ver agora como fazer o binding:
textBox1.DataBindings.Add("Text", ds.Tables[0], "ContactName");
Nesse caso, vinculamos a propriedade “Text” de nosso textbox à fonte
“ds.Tables[0]”, e ao campo “ContactName”.
BindingNavigator Se você implementou o exemplo da TextBox, deve ter verificado um problema: o
vínculo foi formado, mas apenas o primeiro campo apareceu. Como eu faço para
navegar nos registros?
Com essa finalidade, o .NET traz para nós o controle BindingNavigator. A função
desse controle é exatamente essa: permitir a navegação nos dados. Esse controle
está contido na ToolBox do Visual Studio:
Apostila Treinamento C#
103
Para implementar um BindingNavigator, precisamos primeiro implementar um
BindingSource. O BindingSource define qual a fonte de dados à qual iremos nos
conectar. Ou seja, ele define:
• DataSource – Fonte de dados.
• DataMember – Subgrupo dentro da fonte de dados. Em geral, a tabela.
Enquanto isso, o BindingNavigator cria uma barra de ferramentas, que permite
navegar nos registros da fonte de dados:
Vamos ver um exemplo de implementação:
string connectionString = "Data Source=CAIOWAA\\SQLEXPRESS;Initial " + "Catalog=Northwind;Integrated Security=True"; SqlConnection cn = new SqlConnection(connectionString); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = new SqlCommand("SELECT * FROM Customers", cn); DataSet ds = new DataSet(); da.Fill(ds); bindingSource1.DataSource = ds.Tables[0]; bindingNavigator1.BindingSource = bindingSource1; textBox1.DataBindings.Add("Text", bindingSource1, "ContactName");
Lab: Data Binding Vamos usar um exemplo para demonstrar as funcionalidades do DataBind. Abra o
projeto “WindowsApplicationCS”, e adicione um novo Form chamado
“FormDataBinding.cs”. Agora, abra o “Project.cs”, e no Application.Run, altere para:
Application.Run(new FormDataBinding());
Apostila Treinamento C#
104
Nosso objetivo será obter os dados da base NorthWind, e gerar um formulário que
permita visualizar ou alterar os dados de um cliente.
Para isso, abra a janela “DataSources” (menu “Data” > “Show Data Sources”).
Clique em “Add New Data Source...”. Na janela que se abre, selecione “Database”
e clique em “Next >”.
Na tela “Choose Your Data Connection”, clique em “New Connection...” para gerar
uma nova conexão com uma base de dados. Escolha conexão a um servidor SQL.
Na tela “Add Connection”...
...em “Server Name”, aponte o nome do banco de dados configurado no seu
sistema. Na caixa “Select or enter a database name:”, selecione o banco
Northwind, e clique em OK.
De volta á tela “Choose Your Data Connection”, clique em “Next>”. Na tela “Save
the Connection String to the Application Configuration File”, clique “Next>”.
Apostila Treinamento C#
105
Agora, você verá uma tela chamada “Choose Your Database Objects”, aonde você
poderá escolher quais os objetos do banco você pretende utilizar.
Expanda a opção “Tables”, e marque a opção “Customers”. Isso irá,
automaticamente, fazer com que todos os objetos dessa tabela sejam adicionados
ao DataSet tipado que será criado. Clique em “Finish”.
Você deve ter agora algo parecido com isso na sua janela “Data Sources”. Em
“Customers”, selecione a seta para baixo, e altere o tipo para “Details”. Agora,
arraste o objeto “Customers” para o seu formulário.
Repare que todos os campos do DataSet criado são automaticamente copiados
para dentro do formulário. Além disso, note também que já foram gerados,
automaticamente, uma instância do DataSet (northwindDataSet), uma binding
source (customersDataSource) e um data adapter (customersDataAdapter).
Apostila Treinamento C#
106
Todos os controles “TextBox” já estão automaticamente vinculados à sua
BindingSource.
Agora, arraste um controle “Binding Navigator”:
Propriedade Valor
(Name) customersBindingNavigator
BindingSource customersBindingSource
Agora, arraste um botão para o seu Form:
Propriedade Valor
(Name) btnGravar
Text Gravar
Clique agora 2 vezes no botão “btnGravar”, e no evento Click do botão, insira o
seguinte código:
Apostila Treinamento C#
107
DialogResult result = MessageBox.Show("Salvar Alterações?", "DataBinding", MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { customersBindingSource.MoveLast(); int rows = customersTableAdapter.Update(northwindDataSet); if (rows > 0) { MessageBox.Show("Alterações feitas com sucesso!", "DataBinding"); } }
Execute agora a sua aplicação, e verifique o resultado:
O resultado desse lab se encontra disponível no CD do treinamento.
DataGridView O DataGrid inclui não só a facilidade de, a partir de um recordset, popular a sua
interface gráfica, mas também incluir e permitir a alteração de dados ali mostrados.
Quando o desenvolvedor necessitava de maiores funcionalidades, como
ordenação, formatação, era necessário escrever código, muitas vezes extenso, ou
depender de componentes de terceiros.
O DataGridView apareceu na versão 2.0 do framework .NET e traz consigo
características que facilitam muito a vida do desenvolvedor .NET: auto-ajuste de
linhas e colunas, estilos de célula, auto-organização de colunas, formatação, entre
outras.
Apostila Treinamento C#
108
Populando um DataGridView Popular um DataGridView a partir de um DataSet é uma tarefa simples. Basta
adicionar o DataSet à propriedade DataSource do DataGridView. O código abaixo,
implementado de forma similar ao anterior, ilustra melhor esse processo:
// Busco a string de conexão do arquivo de configuração. Properties.Settings setting = new Properties.Settings(); SqlConnection cn = new SqlConnection(setting.NorthwindConnectionString); SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Employees", cn); DataSet ds = new DataSet(); da.Fill(ds, "Empregados"); dataGridView1.DataSource = ds; dataGridView1.DataMember = "Empregados";
Ativando a ordenação automática Para ativar a ordenação automática, que permite que o usuário possa alternar a
odenação ascendente/descendente ao clicar em cima de uma coluna, basta marcar
a propriedade AllowUserToOrderColumns (o que pode também ser feito em tempo
de design usando a aba Propertires do DataGridView):
dataGridView1.AllowUserToOrderColumns = true;
Ativando o auto-ajuste de linhas e colunas Para que todas as colunas sejam auto-ajustadas, use:
dataGridView1.AutoResizeColumns;
Para que uma coluna seja auto-ajustada, use:
dataGridView1.AutoResizeColumn(<índice>);
.. onde <índice> é o número da coluna que será auto-ajustada.
Para que todas as linhas sejam auto-ajustadas, use:
dataGridView1.AutoResizeRows();
Apostila Treinamento C#
109
Para que apenas uma linha seja auto-ajustada, use:
dataGridView1.AutoResizeRow(<índice>);
Renomeando as colunas A chamada abaixo mostra como renomear uma coluna a partir do seu nome:
dataGridView.Columns["EmployeeID"].HeaderText = "ID";
Formatando colunas Para formatar colunas, podemos usar os mesmos códigos de formatação que
foram vistos no capítulo 3.
No exemplo abaixo, a coluna UnitPrice terá a formatação de valores monetários
que foi escolhida nas Configurações Regionais do Windows. A segunda linha, que
formata a coluna UnitsInStock, usa uma formatação customizada, preenchendo
com zeros as duas casas à esquerda e à direita do ponto:
dataGridView1.Columns["UnitPrice"].DefaultCellStyle.Format = "C"; dataGridView1.Columns["UnitsInStock"].DefaultCellStyle.Format = "##00.00”;
Mudando o estilo de acordo com uma condição O exemplo abaixo mostra como deixar com fundo amarelo a célula “HiredDate” de
todos os funcionários que foram contratados de 1993 para a frente.
Para que possamos fazer a alteração, basta escrever um método que manipule o
evento DataGridView.CellFormatting e usar os
DataGridViewCellFormattingEventArgs para termos acesso aos dados da célula:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { if (dataGridView1.Columns[e.ColumnIndex].Name.Equals("HireDate")) { object blah = e.Value;
Apostila Treinamento C#
110
if (e.Value != null) { if (e.Value != DBNull.Value) { if (((DateTime)e.Value).Year > 1992) { e.CellStyle.BackColor = Color.Yellow; } } } } }
Fazendo um DataGridView “zebrado” Para fazer um DataGridView “zebrado”, basta usar definir um estilo e configurá-lo
na propriedade AlternatingRowsDefaultCellStyle. Quando o DataGridView for
renderizado, o próprio componente se encarrega de alternar entre o DefaultStyle e
o AlternatingStyle.
O exemplo abaixo, adicionado ao DataGridView que viemos trabalhando, faz com
que as linhas alternadas sejam preenchidas com fundo cinza claro:
dataGridView1.AlternatingRowsDefaultCellStyle.BackColor = Color.LightGray;
Lendo eventos de seleção O exemplo abaixo mostra um método que manipula o evento Click do
DataGridView, e mostra a mensagem com o nome de todos os funcionários
selecionados:
private void dataGridView1_Click(object sender, EventArgs e) { foreach (DataGridViewCell cell in dataGridView1.SelectedCells) { DataGridViewRow row = dataGridView1.Rows[cell.RowIndex]; string firstName = row.Cells["FirstName"].Value.ToString(); string lastName = row.Cells["LastName"].Value.ToString(); string title = row.Cells["TitleOfCourtesy"].Value.ToString(); MessageBox.Show( title + " " + firstName + " " + lastName ); } }
Apostila Treinamento C#
111
Oferecendo uma lista de opções em um ListBox Agora, e se um dos campos que estamos trabalhando contém um código para um
valor em uma outra tabela (uma chave estrangeira) e precisamos que, ao invés de
exibir o código, precisemos exibir o valor?
No exemplo abaixo, utilizamos uma tabela chamada “EmployeeTerritories”, que
contém o relacionamento entre os territórios atendidos e os funcionários que o
atendem. Criamos colunas customizadas, para fazer o relacionamento.
private void FormDataGridView_Load(object sender, EventArgs e) { // Busco a string de conexão do arquivo de configuração. Properties.Settings setting = new Properties.Settings(); SqlConnection cn = new SqlConnection(setting.NorthwindConnectionString); // Um adapter para cada query. SqlDataAdapter daEmployees = new SqlDataAdapter("SELECT * FROM " + "Employees", cn); SqlDataAdapter daTerritories = new SqlDataAdapter("SELECT * FROM " + "Territories", cn); SqlDataAdapter daEmployeeTerritories = new SqlDataAdapter("SELECT *"+ " FROM EmployeeTerritories", cn); DataSet ds = new DataSet(); daEmployees.Fill(ds, "Empregados"); daTerritories.Fill(ds, "Territorios"); daEmployeeTerritories.Fill(ds, "TerritoriosEmpregados"); // Vinculo o DGV à tabela de relacionamento. dataGridView1.DataSource = ds; dataGridView1.DataMember = "TerritoriosEmpregados"; // Apago as colunas de índice, que não serão usadas. dataGridView1.Columns.Clear(); // Crio uma coluna contendo uma DropDown com os territórios. DataGridViewComboBoxColumn colTerritories = new DataGridViewComboBoxColumn(); colTerritories.DisplayIndex = 0; colTerritories.HeaderText = "Territorio"; colTerritories.DataPropertyName = "TerritoryID";
Apostila Treinamento C#
112
colTerritories.DataSource = ds.Tables["Territorios"]; colTerritories.DisplayMember = "TerritoryDescription"; colTerritories.ValueMember = "TerritoryID"; dataGridView1.Columns.Add(colTerritories); // Crio uma coluna contendo uma DropDown com os funcionários. DataGridViewComboBoxColumn colEmployees = new DataGridViewComboBoxColumn(); colEmployees.DisplayIndex = 1; colEmployees.HeaderText = "Empregado"; colEmployees.DataPropertyName = "EmployeeID"; colEmployees.DataSource = ds.Tables["Empregados"]; colEmployees.DisplayMember = "LastName"; colEmployees.ValueMember = "EmployeeID"; dataGridView1.Columns.Add(colEmployees); // Recalcula o tamanho das colunas. dataGridView1.AutoResizeColumns(); }
Formulários Master/Detail Formulários Master/Details são aqueles que mostram os dados separados em dois
grupos: o principal (Master) e o de detalhes (Detail). Quando escolhemos um
registro no principal, o de detalhes se atualiza de acordo com a relação que existe
entre os dois.
DataRelation É importante, nesse ponto, falar um pouco sobre o objeto DataRelation. O
DataRelation é um objeto do namespace System.Data, que define uma relação
entre duas colunas de duas tabelas diferentes contidas em um DataSet.
Ele aceita diversos parâmetros, mas os principais são:
• relationName – Uma string, contendo um nome para a relação.
• parentColumn – Recebe uma DataColumn (coluna do DataSet), que
representa a coluna pai.
• childColumn – Recebe uma DataColumn (coluna do DataSet), que
representa a coluna filha.
Como exemplo:
Apostila Treinamento C#
113
DataColumn colPai = ds.Tables["Empregados"].Columns["EmployeeID"]; DataColumn colFilho = ds.Tables["TEmpregados"].Columns["EmployeeID"]; DataRelation rel = new DataRelation("RelTEmpregados", colPai, colFilho);
Estratégia do Master/Detail Com o componentes BindingSource, ficou muito fácil fazer relações Master/Detail.
O que deve ser feito é:
1. criar um objeto Connection e conectar à base;
2. criar dois DataAdapters, um para cada tabela;
3. criar um DataSet que abrigará as duas tabelas e sua relação;
4. preencher dois DataTables do DataSet usando os dois DataAdapters;
5. criar um DataRelation, que fará a relação pai/filho das tabelas;
6. criar dois BindingSources;
7. um dos BindingSources receberá como DataSource o DataSet, e como
DataMember o DataTable com a tabela-pai;
8. o outro BindingSource receberá como DataSource o BindingSource
anterior, que contém os dados da tabela-pai, e o DataMember será o
DataRelation que foi criado.
Lab: Relacionamentos e Master-Detail Vamos ver como utilizar os relacionamentos, e como trabalhar com dados no
formato Master-Detail. Para isso, vamos utilizar o banco Northwind, e criar a nossa
aplicação.
Abra a solução “WindowsApplicationCS”, criada anteriormente. Adicione um
formulário, chamado “FormDataGridView.cs”. Como nas outras vezes, edite o
arquivo “Program.cs”, e altere a linha do Application.Run para que ele execute o
seu código:
Application.Run(new FormDataGridView());
Apostila Treinamento C#
114
Lembre-se de, no começo da classe, importar o namespace
System.Data.SqlClient.
Nesse formulário, adicione os seguintes controles:
Controle Propriedade Valor Label Text “Funcionário:” Label Text “Territórios Atendidos:”
(Name) “cmbFuncionario” ComboBox DropDownStyle “DropDownList”
DataGridView (Name) “dgvTerritorios” EditMode “EditProgrammatically” (Não temos
interesse em permitir a edição nesse momento).
Agora, você deve ter um visual mais ou menos como o seguinte:
Crie uma conexão e os adapters necessários para executar as seguintes buscas
no banco e gravar os dados em um DataSet:
SELECT EmployeeID, LastName + ', ' + FirstName AS [Name] FROM dbo.Employees ORDER BY Name ASC SELECT TerritoryID, TerritoryDescription FROM dbo.Territories SELECT * FROM EmployeeTerritories
Crie um DataRelation, relacionando as tabelas Employees e EmployeeTerritories,
através do campo EmployeeID, como segue:
Apostila Treinamento C#
115
DataColumn colPai = ds.Tables["Empregados"].Columns["EmployeeID"]; DataColumn colFilho = ds.Tables["TEmpregados"].Columns["EmployeeID"]; DataRelation rel = new DataRelation("RelTEmpregados", colPai, colFilho); ds.Relations.Add(rel);
Agora, adicione via código 2 objetos BindingSource, um que irá apontar para a
tabela Employees e outro que irá apontar para EmployeeTerritories:
BindingSource bsEmpregados = new BindingSource(); bsEmpregados.DataSource = ds; bsEmpregados.DataMember = "Empregados"; BindingSource bsTerritorios = new BindingSource(); bsTerritorios.DataSource = bsEmpregados; bsTerritorios.DataMember = "RelTEmpregados";
Note que, no caso do bsTerritorios, ele está apontando o DataSource para o
bsEmpregados, e o DataMember para o nome que foi dado para o relacionamento
(RelTEmpregados). Com isso, vinculamos uma fonte à outra.
Vincule agora a sua ComboBox à fonte bsEmpregados, e o DataGridView à fonte
bsTerritorios. Com isso agora eles estão corretamente relacionados.
Entretanto, note que ele não ficou visualmente agradável. O que quer dizer cada
TerritoryID? Além disso, o EmployeeID é desnecessário – não significa nada para o
usuário. Vamos melhorar o nosso programa, trabalhando os dados do Grid.
A primeira coisa a fazer é limpar o nosso Grid. Para isso, utilizamos o método
Clear, da coleção Columns do DataGridView.
Apostila Treinamento C#
116
Nosso próximo passo é adicionar programaticamente uma coluna, que receba o
TerritoryID do grid e exiba o texto. Fazemos isso com uma coluna do tipo
DataGridViewComboBoxColumn:
DataGridViewComboBoxColumn colTerritories = new DataGridViewComboBoxColumn(); colTerritories.DisplayIndex = 0; colTerritories.HeaderText = "Territorio"; colTerritories.DataPropertyName = "TerritoryID"; colTerritories.DataSource = ds.Tables["Territorios"]; colTerritories.DisplayMember = "TerritoryDescription"; colTerritories.ValueMember = "TerritoryID";
No exemplo, dissémos que a coluna irá receber a propriedade TerritoryID
(DataPropertyName), e irá se conectar à fonte ds.Tables["Territorios"]
(DataSource), e exibirá a coluna TerritoryDescription (DisplayMember).
Entretanto, como não temos interesse que o usuário possa alterar os valores, seria
bom forçarmos para que ele não possa selecionar outro valor na lista. Isso é feito
com o comando:
colTerritories.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;
Agora vamos adicionar a nossa coluna à coleção de colunas do grid, e mandar a
coluna se auto-redimensionar automaticamente.
Rode a sua aplicação e veja o resultado:
O resultado está contido no CD.
Apostila Treinamento C#
117
Revisão Neste capítulo, foi mostrado como funciona um formulário MDI no C#, como
funciona o DataBinding e falamos um pouco sobre o DataGridView e formulários
Master/Detail. Esperamos que este capítulo tenha despertado no leitor a vontade
de se aprofundar mais na programação Windows Forms.
Apostila Treinamento C#
118
Capítulo 10 – Web Services
Objetivos O termo “Web Service” vem se tornando um termo cada vez mais comum, quando
se fala de aplicações distribuídas. Mas o que vem a ser um “Web Service”, e
porque tanto se fala sobre isso?
O objetivo desse capítulo é explicar ao leitor o que é um Web Service, qual o uso
prático disso, como criar um Web Service simples, como consumir os seus dados e
como fazer para distribuí-lo.
Conceito: O que é um Web Service? De acordo com o W3C (World Wide Web Consortium), um Web Service é um
“sistema de software desenhado para suportar a interoperabilidade máquina-
máquina através de uma rede”.
Se sua aplicação precisa se comunicar com outra aplicação (como Pocket PC,
SmartPhone, SAP, etc) através da Internet e de forma transparente, você precisa
de um Web Service.
Web Services são os blocos de construção fundamentais na migração da
computação local para a computação distribuída pela Internet. Para que seja
possível a interoperabilidade entre sistemas distribuídos, ele se baseia em 3
padrões:
Apostila Treinamento C#
119
• Ele expõe suas funcionalidades através de um protocolo padrão de rede,
usualmente o SOAP (Simple Objet Access Protocol);
• Ele provê um meio de descrever suas interfaces, com detalhes suficientes
para que seja possível a uma aplicação cliente conversar com eles. Esta
descrição é feita por um documento XML chamado WSDL (Web Services
Description Language).
• Um Web Services deve ser registrado, de forma que possíveis usuários
possam localizá-lo facilmente. Isso é feito por um serviço chamado UDDI
(Universal Discovery Description and Integration).
Padrões abertos e o foco na comunicação e colaboração entre pessoas e
aplicações estão criando um ambiente onde os Web Services XML estão se
tornando a plataforma para integração de aplicações. Ou seja, os Web Services
utilizam os protocolos padrão da internet, para que se torne possível uma
comunicação transparente aplicação-aplicação.
Mas quais são as vantagens de um Web Services?
• Web Services provê interoperabilidade entre várias aplicações, rodando em
plataformas diferentes;
• Eles utilizam padrões e protocolos abertos;
• Os dados e formatos dos protocolos são baseados em texto, sempre que
possível;
• Ele utiliza o protocolo HTTP como meio de troca de informações, o que
permite que os dados sejam transferidos mesmo através de firewalls – o
que não seria possível através de chamadas RPC;
• Ele facilita a reutilização de código, concentrando o fornecimento de dados
em uma única fonte;
• O acoplamento fraco provido permite uma abordagem distribuída.
E quais são as desvantagens?
Apostila Treinamento C#
120
• Ainda não existem protocolos que reforçam transações;
• Eles possuem uma performance fraca comparada com as chamadas RPC.
Entre as plataformas que permitem a utilização de Web Services, temos:
• Axi e Jacarta Tomcat Server, parte do Apache project;
• ColdFusion, da Macromedia;
• Java Web Services Development Pack (JWSDP) da Sun;
• Servidores Microsoft .NET, da Microsoft;
• Websphere Application Server, da IBM;
• Web Application Server, da SAP;
• Oracle Application Server, da Oracle.
Criando um Web Service O C# já possui um tipo de projeto específico para o desenvolvimento de Web
Services, que encapsula a maior parte da complexidade do desenvolvimento dele.
Nada melhor que um exemplo para verificarmos como isso funciona.
Abra o Visual Studio 2005, selecione “File” > “New” > ”Web Site...”.
Apostila Treinamento C#
121
Selecione “ASP.NET Web Services”, em “Language” selecione “Visual C#” e em
“Location” digite “http://localhost/NorthwindWS”. Clique em “OK”.
O Visual Studio irá abrir um novo projeto, que estará localizado por default na raiz
do seu IIS (que, por default, é c:\inetpub\wwwroot).
Você pode verificar que ele criou automaticamente um WebService chamado
Service.asmx, que possui um método chamado HelloWorld(). Mande rodar sua
aplicação (pressionando F5 ou clicando em ), e veja o resultado. A seguinte
janela será mostrada:
Mas o que isso significa? Na primeira vez que você rodar a sua aplicação, ela
ainda não vai estar configurada para permitir a depuração do código. Na primeira
vez em que mandamos a aplicação rodar, o sistema irá nos avisar disso, e
perguntar se desejamos alterar o modo para permitir depuração. Deixe que ele
altere o Web.config, clicando em “ok”.
Apostila Treinamento C#
122
Veja que, após termos clicado em “OK”, o Visual Studio abre uma janela do
browser (Internet Explorer) aonde ele mostra o conteúdo do nosso Web Service.
Aqui, podemos ver uma lista dos serviços disponíveis. No caso, apenas o método
Hello World está disponível. Clique nele.
Uma nova janela será aberta:
Apostila Treinamento C#
123
Aqui, temos a opção de preencher todos os parâmetros necessários para a
invocação do método, e podemos chamá-lo clicando em “Invoke”. Como o Hello
World não tem nenhum parâmetro, clique em “Invoke”.
Podemos ver então qual foi a resposta que retornou quando executamos uma
chamada ao nosso método, Hello World. Isso é o que o cliente de nosso web
service vai receber como resposta – um arquivo XML (por isso estudamos XML em
um outro capítulo).
Só que este é um exemplo muito simples – é um Web Service que faz pouca coisa
ainda. Vamos criar um outro Web Method (nome dos métodos fornecidos por um
Web Service), que consome os dados de um banco de dados e retorna para o
usuário.
Clique no arquivo “Service.asmx” com o botão direito, e escolha “Delete” e
confirme. Exclua também o seu arquivo de código, clicando em “Service.vb” e
escolhendo “Delete”.
Agora, clique com o botão direito no projeto, e selecione “Add New Item”. Selecione
“Web Service”, e dê a ele o nome de “NorthwindDataProvider.asmx”.
Preste agora atenção ao Web Method HelloWorld().
[WebMethod] public string HelloWorld() { return "Hello World"; }
Existe algo diferente nele? Se você reparar, vai ver que, antes do método existe
um atributo chamado WebMethod(). Esse atributo é o que faz com que o C# saiba
que você quer que aquele método esteja disponível.
Apostila Treinamento C#
124
Vamos alterar a classe NorthwindDataProvider para conter o seguinte código:
using System; using System.Web; using System.Collections; using System.Web.Services; using System.Web.Services.Protocols; using System.Data; using System.Data.SqlClient; /// <summary> /// Summary description for NorthwindDataProvider /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class NorthwindDataProvider : System.Web.Services.WebService { public NorthwindDataProvider () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] public DataSet ObterCliente(string customerId) { string connectionString = "Data Source=(local)\\SQLEXPRESS; " + "Initial Catalog=Northwind;Integrated Security=True"; string sqlQuery = "SELECT * FROM Customers "; sqlQuery += "WHERE CustomerId='" + customerId + "'"; SqlConnection connection = null; SqlDataAdapter adapter = null; DataSet dsCliente = new DataSet(); try { connection = new SqlConnection(connectionString); connection.Open(); adapter = new SqlDataAdapter(sqlQuery, connection); adapter.Fill(dsCliente); } finally { adapter = null; if( (connection != null) && (connection.State != ConnectionState.Closed) ) { connection.Close();
Apostila Treinamento C#
125
} connection = null; } return dsCliente; } }
Essa função retorna todos os dados de um cliente, utilizando como filtro o id do
usuário. Clique com o botão direito em “NorthwindDataProvider.asmx”, e selecione
“Set As Start Page”.
Agora vamos rodar a nossa aplicação, e verificar o seu funcionamento. Use o id
“ALFKI” para verificar o que acontece.
Consumindo um Web Service Vimos, na sessão anterior, como criar um Web Service que faz uma consulta a um
banco de dados e disponibiliza essa informação. Mas como consumimos os dados
de um Web Service? Vamos ver isso com um exemplo.
Abra a solução “WindowsApplicationCS”. Adicione um novo Form
“FormWSConsumer.cs”. Como nas outras vezes, edite o arquivo “Program.cs”, e
altere a linha do Application.Run para que ele execute o seu código:
Application.Run(new FormWSConsumer());
Agora, adicione os seguintes controles:
• 1 Label – Altere a propriedade “Text” para “Customer Id:”;
• 1 Textbox – Altere a propriedade “(Name)” para “txtCustomerId”;
• 1 Button – Altere a propriedade “(Name)” para “btnSearch”, e a propriedade
“Text” para “Buscar”;
• 1 DataGridView – Altere a propriedade “(Name)” para “dgvCustomer”.
Apostila Treinamento C#
126
Agora, clique com o botão direito no projeto, e selecione “Add Web Reference...”.
Uma nova janela irá surgir.
Em URL, digite “http://localhost/NorthwindWS/NorthwindDataProvider.asmx” e
clique em “Go”. Ele irá buscar para verificar se o Web Service realmente existe. Em
“Web Reference name:”, escreva “NorthwindWS”, e selecione “Add Reference”.
Agora, clique com o botão direito no projeto, e selecione “Build”. Isso irá compilar o
projeto, o que irá facilitar a inclusão do Web Service no código.
Agora, clique 2 vezes no botão buscar. Você abrirá o método btnSearch_Click, que
irá tratar o evento clique do botão. Adicione o seguinte código:
Apostila Treinamento C#
127
DataSet dsClientes = new DataSet(); NorthwindWS.NorthwindDataProvider ndp = new NorthwindWS.NorthwindDataProvider(); dsClientes = ndp.ObterCliente(txtCustomerId.Text); dgvCustomer.DataSource = dsClientes.Tables[0];
Rode o seu programa, em CustomerId preencha “ALFKI”, clique no botão “Buscar”
e verifique o resultado.
Vimos assim como consumir os dados de um Web Service. Esse exemplo se
encontra no CD do treinamento.
Distribuindo um Web Service Para distribuir o seu Web Service para outra máquina, clique com o botão
esquerdo sobre o projeto. Verifique que a barra de configurações de projeto passa
a ser:
Onde o botão efetua a função de copiar um site web de um local para outro.
Clique nele.
A janela que se abrirá permite copiar o projeto para outra localização.
Apostila Treinamento C#
128
Vamos criar uma duplicata do nosso WS, no diretório virtual “NorthwindWS2”.
Na barra superior, clique em “Connect”.
Você pode ver, no lado esquerdo, que os arquivos podem ser copiados para
diversos locais. Selecione “Remote Site”, clique em “New Web Site...”.
Apostila Treinamento C#
129
Na janela “Create New Frontpage Web”, em “Web URL”, digite
“http://localhost/NorthwindWS2” e clique “OK”. O Visual Studio criou,
automaticamente, um novo site web vazio, com o nome dado.
Agora, volte à tela anterior. Veja que agora, você já está conectado ao site:
Selecione todos os arquivos e clique em para enviar os arquivos. Os arquivos
selecionados serão enviados automaticamente.
Agora, verifique que o novo site “Northwind2” também funciona, abrindo o
navegador e digitando
“http://localhost/NorthwindWS2/NorthwindDataProvider.asmx”.
Revisão Esperamos que, nesse ponto, você já tenha compreendido o que é um Web
Service, e porque tanto se fala sobre isso. Além disso, você já deve ser capaz de
criar um novo Web Service e como consumir os dados providos por um.
Apostila Treinamento C#
130
Capítulo 11 – Depuração, Debug e Trace
Objetivos Veremos nesse capítulo quais são os principais recursos disponíveis no Visual
Studio 2005 para verificarmos o funcionamento de nossas aplicações – desde a
depuração de código, quanto log de passagem do sistema.
Depurando uma aplicação A depuração de aplicações é uma ferramenta poderosa que o desenvolvedor
dispõe e que usa com freqüência.
Um bom desenvolvedor deve conhecer bem as funções de depuração (debug),
elas são importantes para que possamos testar a lógica da aplicação, a sequência
do fluxo, os valores de variáveis e objetos que vão sendo usados ao longo da
execução, entre outros. Além disso, a depuração nos permite rastrear e identificar
bugs reportados pela equipe de testes ou que apareceram ao longo do ciclo de
vida de aplicação.
O Visual Studio 2005 tem uma interface de depuração poderosa e amigável, que
nos permite rastrear com rapidez o estado de variáveis e objetos, acompanhar o
fluxo de execução, inspecionar a lista de chamadas, entre outros.
A seguir serão descritas as funcionalidades e as telas respectivas.
A maioria das telas abaixo são acessíveis apenas em modo de debug mas, se
você já estiver nesse modo e mesmo assim não tiver aceso a elas, procure ativá-
las na opçao View no menu superior do Visual Studio.
Para o exemplo, usaremos uma rotina simples que preeenche duas matrizes
usando o seguinte critério:
– se o elemento estiver na diagonal principal (os seus índices são iguais) ,
então ele deve conter o valor 1;
Apostila Treinamento C#
131
– se o elemento não estiver na diagonal principal (os seus índices são
iguais), o elemento deve conter a soma 0.
O código está logo a seguir:
public static class CalculaMatrizDiagonal { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Matriz m = new Matriz(); int[,] diagonal = new int[3, 3]; diagonal = m.ObterMatrizDiagonal(diagonal); for (int linha = 0; linha <= diagonal.GetUpperBound(0); linha++) { for (int coluna = 0; coluna <= diagonal.GetUpperBound(1); coluna++) { Console.Write(diagonal[linha, coluna].ToString()); } Console.Write("\n"); } Console.ReadLine(); } } public class Matriz { public int[,] ObterMatrizDiagonal(int[,] matriz) { for (int linha = 0; linha <= matriz.GetUpperBound(0); linha++) { for (int coluna = 0; coluna <= matriz.GetUpperBound(1); coluna++) { if (linha == coluna) { matriz[linha, coluna] = 1; } else { matriz[linha, coluna] = 0;
Apostila Treinamento C#
132
} } } return matriz; } }
Breakpoints e condições Para criar um breakpoint, basta clicar na barra cinza, à esquerda do código, e é
criado um breakpoint. Esse procedimento é corriqueiro e bem conhecido pelos
desenvolvedores. O que é pouco usado é o recurso de se depurar usando
condições, como pode ser visto na janela Breakpoints, como pode ser visto abaixo:
No exemplo mostrado, a interrupção só acontecerá quando a condição “(linha == 1)
&& (coluna == 2)” for verdadeira.
Para criarmos condições para breakpoints, podemos usar tanto a janela acima
quanto o menu pull-down que aparece ao clicar com o botão direito sobre o
breakpoint:
Apostila Treinamento C#
133
Watch Window A Watch Window permite adicionar expressões e variáveis, para que possamos
verificar o resultado enquanto estamos debugando o nosso código.
O QuickWatch A janela Quickwatch permite que inspecionemos variáveis e objetos. A grande
novidade do Quickwatch na versão 2005 do Visual Studio é o Intellisense, que
permite que tenhamos acesso a uma lista de propriedades e métodos quando
digitamos o nome de uma classe ou objeto.
Quando o elemento sendo verificado é um objeto, o Quickwatch mostra os detalhes
internos em forma de árvore, o que torna muito fácil entender o funcionamento
interno desse elemento.
Para acessar o Quickwatch, basta apertar Ctrl+Alt+Q ou então em modo de debug
clicar sobre uma variável e selecionar Quickwatch.
Apostila Treinamento C#
134
No exemplo a seguir, vemos uma tela do Quickwatch mostrando o objeto Me (no
caso, o Form1), e abrimos a estrutura do objeto Font, aonde somos capazers de
ver as propriedades internas desse objeto:
A janela Output Na janela Output é mostrada a saída do console. Ali é possível ver não só o
progresso da compilação, mas também todas as mensagens que são enviadas ao
console como, por exemplo, System.Console.Write().
A janela Immediate A janela Immediate permite usar expressões para verificar o conteúdo das
variáveis contidas no escopo.
Apostila Treinamento C#
135
As janelas Locals e Auto As janelas Locals e Auto tem como função mostrar as variáveis que estão dentro
de um escopo.
A diferença é que o escopo da janela Autos é a classe em questão, e a janela
Locals mostra as variáveis que estão ou serão usadas nas três linhas anteriores e
nas três linhas posteriores.
Debug e Trace As classes Debug e Trace permitem escrever informações de depuração de
código, para diversos tipos de saídas diferentes.
No caso do Debug, as saídas serão geradas apenas quando compilamos a nossa
aplicação em modo “debug”. Já a classe Trace envia os dados para a saída tanto
no modo “debug”, quanto no modo “release”.
A maior vantagem do Debug e do Trace é a possibilidade de ligar e desligar
através de um ajuste no arquivo de configuração da aplicação. Ambas as classes
estão contidas no namespace “System.Diagnostics”.
Métodos do Debug e do Trace Os métodos da classe Debug e da classe Trace são estáticos, isso é, os métodos
são chamados sem instanciar as classes.
Apostila Treinamento C#
136
São esses métodos:
– Write: escreve um texto e o envia para os listeners;
– WriteLine: o mesmo que o anterior, adicionando um símbolo de retorno
(“\n”) ao final;
– WriteIf: escreve um texto e o envia para os listeners se a condição entrada
for avaliada como True;
– WriteLineIf: idem, adicionando um símbolo de retorno (“\n”) ao final;
– Assert: escreve um texto e o envia para os listeners se a condição entrada
for avaliada como False. Além disso, o Assert também faz com que esse
texto seja mostrado em um MessageBox;
– Fail: o mesmo que Assert, mas não verifica nenhuma condição;
– Flush: faz com que as mensagens acumuladas no buffer sejam
descarregadas na saída;
– AutoFlush (propriedade): faz com que, ao receber uma mensagem, o Trace
ou o Debug escrevam imediatamente para a saída;
– Indent e Unindent: aumentam ou diminuem o nível de identação da saída,
trazendo melhor legibilidade para o texto.
Listeners Ambas as classes (Debug e Trace) escrevem para uma mesma coleção de saídas
(chamada coleção de Listeners). Por padrão, essa coleção já vem com um listener,
que aponta para a janela de Console da aplicação.
Entretanto, é possível adicionar novas saídas (listeners). Vamos ver como
adicionar um listener que grava as mensagens em um arquivo texto. Para isso,
vamos alterar o exemplo, para ao invés dele escrever no “Command prompt” com o
Console.Write, ele escrever no Trace:
Matriz m = new Matriz(); int[,] diagonal = new int[3, 3]; diagonal = m.ObterMatrizDiagonal(diagonal);
Apostila Treinamento C#
137
System.IO.FileStream fs = new System.IO.FileStream("c:\\teste.txt", System.IO.FileMode.OpenOrCreate); TextWriterTraceListener fileListener = new TextWriterTraceListener(fs); Trace.Listeners.Add(fileListener); Trace.AutoFlush = true; for (int linha = 0; linha <= diagonal.GetUpperBound(0); linha++) { for (int coluna = 0; coluna <= diagonal.GetUpperBound(1); coluna++) { Trace.Write(diagonal[linha, coluna].ToString()); } Trace.Write("\r\n"); }
Revisão Vimos as principais janelas utilizadas na depuração de nosso código, como inserir
breakpoint e breakpoints condicionais, e como gerar um log do funcionamento de
nossa aplicação através das classes Debug e Trace.
Apostila Treinamento C#
138
Capítulo 12 – Distribuição
Objetivos Agora que a nossa aplicação está funcionando corretamente, precisamos distribuir
nossa aplicação para a máquina dos clientes. Veremos nesse capítulo como
distribuir nossas aplicações: como criar um projeto de setup, como personalizá-lo e
como configurá-lo para distribuir corretamente a sua solução, como usar a
distribuição no formato Click-Once; e como gerar pacotes de atualização.
Tipos de setup suportados O Visual Studio permite que sejam criados os seguintes tipos de projeto:
– Setup Project, usado para construir instaladores de aplicativos Windows,
gera arquivos .msi e .exe, sendo o arquivo .msi o instalador, e o .exe ;
– Merge Module Project, usado para construir pacotes de componentes,
gerando arquivos com extensão.msm
– Cab Project, usado para construir arquivos .cab para distribuir componentes
ActiveX que rodam em browser;
– Web Setup Project: usado para construir instaladores de aplicações Web;
– Setup Wizard: assistente para criar os projetos de setup acima;
– Smart Device CAB Project: usado para criar instaladores para dispositivos
móveis.
Criando um projeto de setup Para criar um projeto de setup, é possível fazê-lo dentro da mesma Solution ou
criar uma Solution nova.
Nesse exemplo, mostraremos como criar um projeto de setup na mesma Solution,
embora criar uma nova Solution tenham passos similares.
Apostila Treinamento C#
139
Para começarmos, crie um novo projeto, escolha Other Project Types, Setup and
Deployment, e escolha Setup Wizard. Você pode também mudar o nome e o
diretório do projeto:
Na tela seguinte, escolhemos o tipo de setup:
Na próxima tela escolhemos o que deve ser incluso no instalador:
Apostila Treinamento C#
140
Uma das grandes vantagens de se criar um projeto de setup na mesma Solution
em que se encontra a aplicação é que a lista acima aparece, permitindo
selecionarmos para cada projeto os grupos de arquivos que queremos incluir no
setup (note que, no exemplo, temos os arquivos do projeto AdoptionLab1 e, logo
abaixo, do projeto ConsumidorWS, repetindo as opcões para todos os projetos da
mesma Solution).
As opções são:
– Localized resources: dlls e recursos de localização do aplicativo;
– XML serialization Assemblies: caso existam assemblies serializados;
– Content Files: arquivos internos do projeto;
– Primary output: os assemblies que são compilados quando se faz Build do
projeto. Essa é a opção mais usada;
– Source files: caso se deseje incluir o código-fonte do aplicativo no
instalador;
– Debug symbols: para incluir os debug symbols, que auxiliam programadores
avançados e o prórpio Visial Studio a debugarem a aplicação sem
necessariamente ter o código-fonte;
Apostila Treinamento C#
141
– Documentation files: arquivos de documentação gerados pelo Visual Studio.
A tela seguinte permite incluir outros arquivos, como por exemplo arquivos de Help,
arquivos readme.txt e outros que não são diretamente gerenciados pelo Visual
Studio:
A próxima tela confirma as opções escolhidas e encerra o assistente, criando mais
um projeto no Solution.
Personalizando o setup
Apostila Treinamento C#
142
Nas propriedades do projeto de Setup estão os primeiros itens configuráveis. Os
que mais são usados são:
• Manufacturer: nome da empresa, pode ser usada para montar o caminho
(path) de instalação;
• ProductCode, UpgradeCode, Version: vistos mais à frente;
• Localization: configurações regionais do instalador, incluindo não só a
formatação de números, mas também a língua em que serão mostradas as
mensagens. Para as telas padrão (veja ainda nesse capítulo detalhes das
telas de setup), as mensagens estão disponíveis em vários idiomas,
inclusive o Português.
O projeto de setup tem diversas opções que pode ser customizadas. A maioria é
acessível ao se clicar no projeto com o botão direito e escolher View:
Apostila Treinamento C#
143
Seção File System Na seção File System podemos incluir, excluir e alterar os arquivos que serão
inclusos no nosso instalador. Tembém é nessa seção que podemos alterar o
caminho (path) padrão em que o programa será instalado, como veremos a seguir.
Note que a maioria dos itens possui páginas de propriedades, como a mostrada na
figura. Nas propriedades de Application Folder, temos uma configuração
importante: o caminho default de instalação da aplicação, na propriedade
DefaultLocation.
Em Application Folder, colocamos todos os arquivos e pastas que serão criados no
diretório da aplicação. Para adicionar arquivos, clique com o botão direito em
Application Folder e clique em Add.
Apostila Treinamento C#
144
Em User’s Desktop ficam os ícones e as pastas que queremos que o instalador
adicione à Área de Trabalho do usuário.
Em User’s Program Menu ficam os ícones que serão colocados na pasta
Programas no menu Iniciar.
A cada opção, podemos ver a página de propriedades e notar configurações
importantes, como o bitmap de um ícone ou a opção de resgitro de um
componente COM.
Seção Registry Na seção Registry, é possível configurar para que o instalador crie chaves de
registro na instalação.
Seção File Types Na seção File Types fazemos o mapeamento de extensões para as aplicações.
Essa opção pode fazer com que, por exemplo, arquivos de um certo tipo sejam
abertas com uma de suas aplicações. O instalador do Office, por exemplo, cria
mapeamentos de arquivos .xls para serem abertos com o Excel.exe e arquivos
.doc sejam abertos com o Winword.exe.
Apostila Treinamento C#
145
Seção User Interface Nessa seção é possível configurar, editar e adicionar as telas do instalador:
Note no detalhe que, nas propriedades, podemos alterar o conteúdo da
mensagem.
Sempre que houver mudança de mensagem, o instalador aceitará como válida a
mensagem inserida nessa tela de propriedades, e desprezará a mensagem do
arquivo de linguagem respectivo, conforme selecionado nas propriedades do
projeto.
Há também a possibilidade de incluir novas telas a partir de templates prontos (não
é possível customizá-las além do que o Visual Studio oferece) e, inclusive, capturar
nessas telas variáveis que serão usadas como condições do instalador. Consulte a
documentação para ver mais detalhes.
Seções Custom Actions e Launch Conditions A seção Custom Actions permite que sejam chamados scripts, classes ou métodos
estáticos dentro de assemblies. Isso é usado para, por exemplo, fazer o registro de
uma versão “full” do aplicativo através do setup.
Apostila Treinamento C#
146
Na última opção, Launch Conditions, é possível condicionar a instalação à
presença de certos arquivos, chaves de registro ou instalador (opção Search
Target Machine) e também condições do instalador, como a presença do
framework 2.0 (opção default do instalador) e outras condições, como a verificação
de um arquivo ou uma chave criada em uma das telas customizadas do projeto de
setup.
Criando um projeto de atualização Uma dúvida recorrente e que mereceu tópico separado é o projeto de atualização.
A sua configuração é simples e é feita nas propriedades do projeto:
Para fazer com que o projeto de instalação reconheça que é uma nova versão,
basta atualizar a propriedade Version.
Uma janela perguntará se você deseja atualizar o código da versão, basta clicar
em Yes e o seu GUID será atualizado.
Note também a opção RemovePreviousVersions, que poderá ser alterada caso
você deseje que o instalador, na atualização, remova as versões anteriores.
Apostila Treinamento C#
147
Click-once deploy Note que ao clicar com o botão direito em qualquer um dos projetos do tipo
WindowsApplication, há a opção Publish. Essa opção nos permite publicar um
instalador simples que pode ser rapidamente publicado em um servidor Web para
download ou atualização.
Para acessar o ClickOnce o click-once, basta selecionar Publish... e o assistente
do ClickOnce entrará em ação.
Primeiro precisaremos escolher aonde serão disponibilizados os arquivos de
deistribuição:
Depois escolhemos o tipo da aplicação:
Apostila Treinamento C#
148
A primeira opção nos permite criar um instalador que criará atalhos no menu Iniciar
e permitirá que a aplicação seja desinstalada através na opção Adicionar/Remover
Programas, que pode ser acessada pelo painel de controle. A segunda opção nos
permite criar um instalador mais simples, que apenas faz com que a aplicação
execute. Entretanto, o usuário tem sempre que acessá-la através de rede, fazendo
o seu download sempre que dela precisar.
Na última tela, confirmamos as opções escolhidas e, ao clicar em Finish, o
ClickOnce começa a trabalhar. Ao final, o Visual Studio chama um novo browser e
já mostra uma página-modelo para fazer download da aplicação:
Apostila Treinamento C#
149
Revisão Vimos nesse capítulo como distribuir nossas aplicações. Passamos por uma parte
mais genérica, com a criação do projeto de setup, criação de pacotes de
atualização, e o Click-Once. Terminamos falando especificamente do deploy das
aplicações que desenvolvemos com o VSTO.
Apostila Treinamento C#
150
Apêndice A – Referências
Livros e Revistas Developing Windows-based applications with Microsoft Visual Basic.NET and
Visual C#.Net. Microsoft Press.
Essential .NET, Volume I: The Common Language Runtime, por Don Box e Chris
Sells.
Building Web Solutions with ASP.NET and ADO.NET, por Dino Esposito, da
Microsoft Press.
.NET Programming: A Practical Guide Using C#, Pradeep Tapadiya, da Ed.
Prentice Hall.
Test-Driven Development in Microsoft .NET, por James W Newkirk e Alexei A.
Vorontsov
Revista MSDN Magazine – Ela possui uma versão em português e uma em inglês.
A versão em Inglês pode ser vista gratuitamente em
http://msdn.microsoft.com/msdnmag/default.aspx. Já a versão em português, você
pode assinar em http://www.neoficio.com.br/msdn.
Sites
.NET e Visual C# Microsoft ASP.NET – Site oficial da Microsoft sobre ASP.NET
http://www.asp.net
MSDN Brasil – Outro site official da Microsoft, trata das plataformas de desenvolvimento Microsoft
http://www.microsoft.com/brasil/msdn/Default.aspx
Visual C# Walkthroughs
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsintro7/html/vxoriVCSharpWalkthroughs.asp
Code Project
http://www.codeproject.com
C# Reference
Apostila Treinamento C#
151
http://msdn2.microsoft.com/en-us/library/618ayhy6(VS.80).aspx
C# Programming Guide
http://msdn2.microsoft.com/en-us/library/67ef8sbd(VS.80).aspx
C# Keywords
http://msdn2.microsoft.com/en-us/library/x53a06bb(VS.80).aspx
Windows Forms Introducing a New Data Grid
http://msdn.microsoft.com/vstudio/default.aspx?pull=/library/en-us/dnvsdev05/html/vs05a9.asp
Windows Forms Demos
http://www.windowsforms.net/Default.aspx?tabindex=4&tabid=49
XML XML Tutorial
http://www.w3schools.com/xml
XML – Introdução
http://www.macoratti.net/xml.htm
DTD Tutorial
http://www.w3schools.com/dtd
XML Schema Tutorial
http://www.w3schools.com/schema
System.Xml Namespace
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemxml.asp
.NET System.Xml Class Reference
http://www.topxml.com/system_xml/default.asp
Acessando XML remoto e buscando informações com o Namespace System.Xml.XPath
http://www.linhadecodigo.com.br/artigos.asp?id_ac=563&pag=1
Migrando arquivos Textos delimitados para XML
http://www.macoratti.net/vbn_xml.htm
Apostila Treinamento C#
152
Distribuição Deploying .NET Framework-based Applications
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/DALGRoadmap.asp