apostila c#

152
Programa de Formação .NET

Upload: claytonduran

Post on 23-Jul-2015

314 views

Category:

Documents


33 download

TRANSCRIPT

Page 1: Apostila C#

Programa de Formação .NET

Page 2: Apostila C#

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

Page 3: Apostila C#

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

Page 4: Apostila C#

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

Page 5: Apostila C#

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

Page 6: Apostila C#

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

Page 7: Apostila C#

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

Page 8: Apostila C#

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

Page 9: Apostila C#

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.

Page 10: Apostila C#

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.

Page 11: Apostila C#

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.

Page 12: Apostila C#

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;

Page 13: Apostila C#

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:

Page 14: Apostila C#

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.

Page 15: Apostila C#

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.

Page 16: Apostila C#

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).

Page 17: Apostila C#

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

Page 18: Apostila C#

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.

Page 19: Apostila C#

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

Page 20: Apostila C#

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.

Page 21: Apostila C#

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.

Page 22: Apostila C#

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.

Page 23: Apostila C#

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.

Page 24: Apostila C#

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.

Page 25: Apostila C#

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”.

Page 26: Apostila C#

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.

Page 27: Apostila C#

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.

Page 28: Apostila C#

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.

Page 29: Apostila C#

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;

Page 30: Apostila C#

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

Page 31: Apostila C#

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.

Page 32: Apostila C#

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++

Page 33: Apostila C#

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++).

Page 34: Apostila C#

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

Page 35: Apostila C#

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);

Page 36: Apostila C#

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(); }

Page 37: Apostila C#

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.

Page 38: Apostila C#

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.

Page 39: Apostila C#

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.

Page 40: Apostila C#

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; } }

Page 41: Apostila C#

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; } }

Page 42: Apostila C#

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;

Page 43: Apostila C#

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(); }

Page 44: Apostila C#

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.

Page 45: Apostila C#

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;

Page 46: Apostila C#

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.

Page 47: Apostila C#

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.

Page 48: Apostila C#

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.

Page 49: Apostila C#

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.

Page 50: Apostila C#

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; }

Page 51: Apostila C#

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;

Page 52: Apostila C#

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

Page 53: Apostila C#

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:

Page 54: Apostila C#

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.

Page 55: Apostila C#

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.

Page 56: Apostila C#

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

Page 57: Apostila C#

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.

Page 58: Apostila C#

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:

Page 59: Apostila C#

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.

Page 60: Apostila C#

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.

Page 61: Apostila C#

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.

Page 62: Apostila C#

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.

Page 63: Apostila C#

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!

Page 64: Apostila C#

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);

Page 65: Apostila C#

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”.

Page 66: Apostila C#

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:

Page 67: Apostila C#

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.

Page 68: Apostila C#

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);

Page 69: Apostila C#

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){

Page 70: Apostila C#

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;

Page 71: Apostila C#

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;

Page 72: Apostila C#

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)

Page 73: Apostila C#

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.

Page 74: Apostila C#

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); }

Page 75: Apostila C#

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.

Page 76: Apostila C#

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.

Page 77: Apostila C#

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>

Page 78: Apostila C#

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;

Page 79: Apostila C#

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)?

Page 80: Apostila C#

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>

Page 81: Apostila C#

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.

Page 82: Apostila C#

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);

Page 83: Apostila C#

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

Page 84: Apostila C#

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

Page 85: Apostila C#

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.

Page 86: Apostila C#

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();

Page 87: Apostila C#

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.

Page 88: Apostila C#

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.

Page 89: Apostila C#

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.

Page 90: Apostila C#

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

Page 91: Apostila C#

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.

Page 92: Apostila C#

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);

Page 93: Apostila C#

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.

Page 94: Apostila C#

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:

Page 95: Apostila C#

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.

Page 96: Apostila C#

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).

Page 97: Apostila C#

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,

Page 98: Apostila C#

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:

Page 99: Apostila C#

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?

Page 100: Apostila C#

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

Page 101: Apostila C#

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).

Page 102: Apostila C#

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:

Page 103: Apostila C#

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());

Page 104: Apostila C#

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>”.

Page 105: Apostila C#

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).

Page 106: Apostila C#

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:

Page 107: Apostila C#

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.

Page 108: Apostila C#

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();

Page 109: Apostila C#

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;

Page 110: Apostila C#

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 ); } }

Page 111: Apostila C#

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";

Page 112: Apostila C#

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:

Page 113: Apostila C#

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());

Page 114: Apostila C#

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:

Page 115: Apostila C#

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.

Page 116: Apostila C#

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.

Page 117: Apostila C#

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.

Page 118: Apostila C#

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:

Page 119: Apostila C#

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?

Page 120: Apostila C#

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...”.

Page 121: Apostila C#

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”.

Page 122: Apostila C#

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:

Page 123: Apostila C#

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.

Page 124: Apostila C#

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();

Page 125: Apostila C#

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”.

Page 126: Apostila C#

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:

Page 127: Apostila C#

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.

Page 128: Apostila C#

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...”.

Page 129: Apostila C#

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.

Page 130: Apostila C#

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;

Page 131: Apostila C#

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;

Page 132: Apostila C#

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:

Page 133: Apostila C#

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.

Page 134: Apostila C#

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.

Page 135: Apostila C#

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.

Page 136: Apostila C#

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);

Page 137: Apostila C#

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.

Page 138: Apostila C#

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.

Page 139: Apostila C#

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:

Page 140: Apostila C#

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;

Page 141: Apostila C#

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

Page 142: Apostila C#

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:

Page 143: Apostila C#

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.

Page 144: Apostila C#

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.

Page 145: Apostila C#

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.

Page 146: Apostila C#

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.

Page 147: Apostila C#

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:

Page 148: Apostila C#

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:

Page 149: Apostila C#

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.

Page 150: Apostila C#

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

Page 151: Apostila C#

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

Page 152: Apostila C#

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