Sunteți pe pagina 1din 203

Dezvoltare de aplicatii in Visual Studio

.NET
Presented by developerWorks, your source for great tutorials
ibm.com/developerWorks

Table of Contents
If you're viewing this document online, you can click any of the topics below to link directly to that section.

1. Despre manual si despre autorul sau...............................


2. Introducere in .NET Framework - I ..................................
3. Tipuri de date si membri- II ...........................................
4. Gestionarea interfetelor utilizator - III ...............................
5. Concepte POO in Visual Studio .NET - IV .........................
6. Testarea si debugging-ul aplicatiilor - V ............................
7. Accesarea bazelor de date. ADO.NET - VI ........................
8. GDI+. Controale utilizator. Atribute - VII............................
9. Programare folosind fire de executie - VIII.........................
10. .NET Framework Advanced - IX ...................................
11. Assemblies. Aplicatii - configurare, securizare, instalare,
rulare - X ....................................................................
12. XML, Web Services - XI .............................................
13. ASP.NET - XII .........................................................
14. Appendix ...............................................................
15. Bibliografie, referinte .................................................

Dezvoltare de aplicatii in Visual Studio .NET

2
3
12
35
61
80
98
122
140
142
158
177
187
202
203

Page 1 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 1. Despre manual si despre autorul sau


Despre manual...
Manualul contine tematica cursului "Dezvoltare de
aplicatii in Visual Studio .NET" si se adreseaza, in
primul rand, studentilor Facultatii de Informatica
care au optat sa urmeze acest curs. Cititorii acestui
manual trebuie sa posede cunostinte medii de
programare orientata obiect si sa fie familiarizati cu
medii de programare vizuala. In plus, o doza de
ambitie este suficienta pentru a garanta o buna
asimilare a cunostintelor de Visual Studio .NET si,
in particular, de C# pe care autorul intentioneaza
sa le transmita.

Despre autor...
Gabriel NEGARA

Preparator universitar, Facultatea de Informatica, IASI


Lucrare de licenta, iunie 2002 - Ant Colony Optimisation
Master, iunie 2003 - Tehnici de clasificare in Data Mining
MCP 70-316 feb. 2004
Pagina web: http://www.infoiasi.ro/~ngabi
E-mail:ngabi@infoiasi.ro
Telefon: 0232 201549

Gabriel NEGARA februarie-mai 2004, Iasi

Page 2 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 2. Introducere in .NET Framework - I


1. NET Framework - privire de ansamblu
.NET Framework este o tehnologie care a reusit sa atraga simpatia lumii IT mondiale
prin:
-usurinta in dezvoltare si utilizare (developing and deploying)
-disponibilitatea pe termen lung (high availability)
-stabilitatea (reliability)
-suportul pentru o gama larga de aplicatii (multi-target application support)
-rezultatul rapid (strength)
-modernitatea
-interoperabilitatea
.NET Framework este o platforma de dezvoltare de aplicatii care implementeaza un
mecanism eficient de alocare de memorie pentru stocarea datelor si instructiunilor,
permitand executia unei aplicatii utilizator numai dupa verificarea unui set de
permisiuni; daca sunt indeplinite conditiile de lansare in executie a aplicatiei, mediul
de dezvoltare initiaza si gestioneaza executia aplicatiei, gestionand, de asemenea,
mecanismul de realocare zonelor de memorie provenite de la resurse care nu mai
sunt utlizate de aplicatie. .NET Framework consta in doua mari componente:
CommonLanguage Runtime si NET Framework Class Library.
.NET Framework este baza dezvoltarii de programe.
CLR furnizeaza mare parte din serviciile de baza necesare executiei programelor.
Libraria de clase de baza BCL .NET expune un set de clase pre-implementate, care
faciliteaza dezvoltarea de programe.
Common Language Specification (CLS) defineste un set minim de standarde pe
care toate limbajele care folosesc .NET Framework trebuie sa le suporte.
Common Type System(CTS) stabileste compatibilitatea de tipuri intre componente
implementate in diverse limbaje.
Unitatea de baza, elementara a unei aplicatii .NET este assembly-ul, care include un
manifest al assembly-ului. Acest manifest descrie assembly-ul si unul sau mai multe
module, iar modulele contin codul sursa al aplicatiei.
Un executabil .NET este stocat ca un fisier IL (MSIL - Microsoft Intermediate
Language). La incarcare, compilatorul transforma codul sursa in code managed
(compilat si administrat de CLR), se verifica daca assembly-ul verifica conditiile de
securitate impuse de sistemul local. Daca se permite rularea, se creaza un fisier .exe
sau .dll numit PE - Executabil Portabil. Acesta este incarcat de motorul de executie
care extrage separat MSIL si Metadata. MSIL este JIT-compilat in cod masina
(binar) si executat. Prezenta metadatei (data describing data, self describing data)
face ca acest cod administrat sa poata sa se auto-descrie (definitii de tipuri,
versiune, restrictii legate de securitate, etc). Aceasta extra-informatie asigura practic
o interoperabilitate fara compromisuri.
Dezvoltare de aplicatii in Visual Studio .NET

Page 3 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

CLR - interoperabilitate multi-limbaj


Integrare
compilatorul limbajului L in care se programeaza trebuie sa stie sa furnizeze cod
intermediar pentru masina virtuala .NET -CLR.
Exista, in prezent, cateva zeci de limbaje compatibile cu .NET (C#, C++, Visual Basic
.NET, Jscript .NET, COBOL, Perl, etc).
Interoperabilitate
Modulele scrise in limbajul L pot fi utilizate in orice alt limbaj compatibil .NET. Spre
exemplu, o clasa scrisa in L poate fi mostenita in C#, etc. In plus, in .NET, nu se mai
pune problema vulnerabilitatii legate de versiunea modulului scris in L (in care se
regaseste signatura si implementarea clasei de mai sus). Introducerea metadatei
rezolva aceasta problema importanta.

Figura 1 - structura .NET Framework. Interoperabilitate

Page 4 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Figura 2 - privire de ansamblu .NET Framework - aplicatii, tehnologii, protocoale

2. Libraria de clase de baza .NET (BCL)


Spatii de nume .NET reprezentative
Spatiu de nume

Descriere

System

Reprezinta spatiul de nume radacina pentru tipurile


low-level din .NET Framework si, de asemenea, pentru
tipurile primitive de data, si este baza tuturor celorlalte spatii
de nume din .NET BCL.

System.Collections

Contine clase care reprezinta o varietate de tipuri container,


cum ar fi ArrayList, SortedList, Queue si Stack. Contine, de
asemenea, clase abstracte, cum ar fi CollectionBase, foarte
utile pentru implementarea propriilor clase cu functionalitate
de container.

System.ComponentModel

Contine clase utile pentru implementarea comportamentelor


componentelor si controalelor la run-time si design-time convertori de tipuri si atribute, legare la surse de date
(binding), componente care asigura managamentul
licentelor.

System.Data

Contine clase necesare accesarii si manipularii bazelor de

Dezvoltare de aplicatii in Visual Studio .NET

Page 5 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

date, precum si spatii de nume aditionale utilizate pentru


accesul la date.
System.Data.Common

Contine un set de clase distribuite pentru provideri de date


.NET.

System.Data.OleDb

Contine clase care pot efectua operatii cu provideri de date


de tip managed, pentru acces OLE DB la surse de date.

System.Data.SQLClient

Contine clase optimizate pentru interactiunea cu Microsoft


SQL Server.

System.Drawing

Expune functionalitati GDI+, continand clase care faciliteaza


randarea grafica.

System.IO

inglobeaza tipuri pentru efectuarea operatiilor de I/O in


sistemul de fisiere.

System.Math

Contine un set de functii matematice.

System.Reflection

Furnizeaza suport pentru obtinerea de informatii si


generarea dinamica de tipuri la runtime.

System.Security

Tipuri cu ajutorul carora se pot crea si manipula permisiuni,


aspectele legate de criptografie si securitatea accesarii
codului constituie, de asemenea, subiecte strans legate de
acest spatiu de nume.

System.Threading

Contine clase care faciliteaza implementarea de aplicatii cu


fire de executie multiple.

System.Windows.Forms

Contine tipuri implicate in crearea aplicatiilor Windows


standard. Clasele care reprezinta forme si controale sunt,
de asemenea, incluse aici.

Numele spatiilor de nume sunt auto-descriptive prin design. Aceasta modalitate de


utilizare a numelor face ca .NET Framework sa fie usor de folosit si permite
utilizatorului o familiarizare rapida cu mediul de lucru.
Libraria de clase de baza .NET Framework este o librarie de cod care furnizeaza
functionalitati folositoare pentru construirea aplicatiilor. BCL este organizata in spatii de
nume, care contin tipuri si spatii de nume aditionale, legate prin functionalitate comuna.
Se poate folosi cuvantul rezervat using pentru a permite referentierea unor membri ai
unui spatiu de nume fara a folosi un nume specificat prin calea comnpleta catre
membrul respectiv. Daca se doreste folosirea unei librarii externe, trebuie creata mai
intai o referinta catre aceasta.
Tipuri valoare si tipuri referinta
Tipurile pot fi: tipuri valoare sau tipuri referinta. O variabila de tip valoare contine
toate datele asociate cu tipul respectiv. O variabila de tip referinta contine un pointer
la o instanta a unui obiect de tipul respectiv.
Tipurile valoare predefinite sunt create la declarare si ramin vide pana in momentul
in care li se asigneaza o valoare. Tipurile referinta trebuie instantiate dupa declarare
pentru a crea efectiv un obiect de acel tip. Declararea si instantierea pot fi combinate
Page 6 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

intr-un singur pas, fara nici o pierdere legata de performanta.


Cand o variabila de tip valoare este asignata unei alte variabile de tip valoare, datele
continute in prima variabila sunt copiate in cea de-a doua. Atunci cand o variabila de
tip referinta este asignata unei alte variabile de acelasi tip, numai referinta catre
obiect este copiata, si ambele variabile vor face referire catre acelasi obiect.

3. Clase si structuri
Clase versus Structuri
La prima vedere, clasele si structurile par foarte asemanatoare. Ambele pot contine
membri, cum ar fi campuri si metode, ambele necesita un constructor pentru a se crea
o noua instanta si, ca toate tipurile din .NET Framework, ambele sunt derivate din
Object. Diferenta dintre clase si structuri este accea ca structurile sunt tipuri valoare,
iar clasele sunt tipuri referinta. La nivel de alocare, aceasta inseamna ca datele de
instantiere pentru clase sunt alocate pe heap, in timp ce pentru structuri acestea sunt
alocate pe stack. Acesul la stack a fost proiectat in asa fel incat sa fie facil si rapid, dar
stocarea unor date de dimensiuni mari pe stack pot conduce la diminuari ale
performantei aplicatiei.
in termeni practici, structurile reprezinta varianta optima pentru obiecte de dimensiuni
mici si pentru care se definesc putine instante, persistente pentru perioade relativ mici
in memorie. Clasele sunt optim folosite pentru obiecte de dimensiuni mai mari si pentru
care de definesc un numar mai mare de instante, cu posibilitatea mentinerii lor in
memorie pentru perioade mari de timp.
Sinteza
Tipurile definite de uzilizator includ clase si structuri. Ambele pot avea membri campuri, proprietati, metode sau evenimente. Clasele sunt tipuri referinta iar
structurile sunt tipuri valoare.
Cuvantul rezervat class este folosit in Visual C# pentru a defini clase. Structurile sunt
create utilizand cuvantul cheie struct. Atat clasele, cat si structurile pot contine tipuri
imbricate.
Tipurile definite de utilizator sunt instantiate in acceasi maniera ca tipurile predefite,
exceptand faptul ca atat tipurile caloare cat si tipurile referinta trebuie sa foloseasca
cuvantul cheie new pentru instantiere.

4. Cum folosim metodele?


Metodele executa manipulari ale datelor care imprima claselor si structurilor un
anumit comportament. Metodele pot returna o valoare, dar acest lucru nu este
necesar. in Visual C#, daca o metoda nu returneaza o valoare, se specifica void
drept tip returnat. Metodele sunt apelate prin plasarea numelui metodei in cod,
specificandu-se eventualii parametrii necesari.
Dezvoltare de aplicatii in Visual Studio .NET

Page 7 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Metodele pot avea parametri, care reprezinta valori solicitate de metoda. Parametrii
sunt transmisi, implicit, prin valoare. Transmiterea parametrilor prin referinta se face
in Visual C# folosind cuvantul rezervat ref. Visual C# permite specificarea
parametrilor de iesire pentru o anumita metoda.
Constructorul este prima metoda apelata la instantierea unui tip. Constructorul
furnizeaza o modalitate de a seta valori implicite ale datelor sau de a executa alte
operatii necesare, inainte ca obiectul sa fie disponibil pentru operatii ulterioare.
Destructorii sunt apelati exact inainte ca un obiect sa fie distrus si pot fi folositi pentru
a executa cod de clean-up, de dealocare de memorie. Pentru ca dealocarea
memoriei alocate obiectelor este controlata de common language runtime,
utilizatorul nu poate controla momentul apelarii destructorului.

5. Nivele de acces si domenii de vizibilitate (scope)


C# - Access Levels
Modificator de acces

Efect asupra membrilor

public

poate fi accesat de oriunde

private

poate fi accesat doar de membrii din cadrul tipului care il


defineste

internal

poate fi accesat de toate tipurile din cadrul assembly-ului


parinte, dar nu dinafara acestuia

protected

poate fi accesat numai de membrii din cadrul tipului care il


defineste sau de tipuri care mostenesc acest tip

protected-internal

poate fi accessed de toate tipurile din assembly sau de


tipuri mostenite din tipul care contine membrul in discutie;
reprezinta reuniunea tipurilor de acces protected si internal

Modificatorii de acces sunt folositi pentru a controla domeniul de vizibilitate a


membrilor unui tip de date. Exista 5 modificatori de acces: public, internal,
private,protected si protected internal. Fiecare dintre acestea determina un anumit
nivel de acces.
Daca pentru o metoda nu se specifica nici un modificator de acces, nivelul de acces
asociat implicit este private pentru clasele si structurile din Visual C#. Daca nu este
specificat nici un modificator de acces pentru o variabila membru, acesta este
considerata private intr-o clasa si publicintr-o structura.
Modificatorii de acces pot fi, de asemenea, folositi pentru a controla modul in care
este instantiat un tip. Nivelele de acces pentru tipuri sunt urmatoarele: tipurile public
pot fi instantiate de oriunde. Tipurile internal pot fi instantiate numai de membrii
assembly-ului, tipurile private pot fi instantiate numai de ele insele sau dintr-un tip
care le contine.
Daca nu se specifica un modificator de acces pentru o clasa sau structura, este
considerata public.
Tipurile imbricate se supun acelorasi reguli ca si tipurile ne-imbricate dar, in practica,
Page 8 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ele nu vor avea niciodata un nivel de acces mai mare decat cel al tipului parinte.
Membrii de tip static apartin tipului si nu unei instante anume a tipului respectiv. Ei
pot fi accesati fara a crea o instanta a tipului si sunt accesati folosind numele tipului.

6. Garbage Collection
.NET Framework executa managementul automat al memoriei, ceea ce inseamna ca
atunci cand un obiect nu mai este folosit, .NET Framework elibereaza automat
memoria folosita de acel obiect. Acest proces se numeste garbage collection.
Sa consideram urmatorul exemplu:
void GarbageCollectionExample()
{
TipObiect obiect = new TipObiect();
}
La sfarsitul acestei proceduri, variabila obiect iese domeniul sau de vizibilitate, iar
obiectul la care face referire nu mai este referentiat de nici o variabila din cadrul
aplicatiei. Garbage collector-ul gestioneaza in background arborele de referinte si
identifica obiectele catre care nu se mai face referinta. Cand gaseste un astfel de
obiect, cum ar fi TipObiect din exemplul anterior, il sterge si solicita eliberarea zonei de
memorie ocpate de obiectul respectiv. Pentru ca garbage collector-ul ruleaza continuu,
utilizatorul nu trebuie sa distruga explicit obiectele la care nu se mai face referire in
program de la un anumit moment.
Garbage collector-ul reprezinta, de fapt, un fir de executie de prioritate scazuta, in
conditii normale. El intervine in executia programului cand timpul procesor nu este
consumat de sarcini mai importante. Totusi, atunci cand zonele de memorie libera se
imputineaza semnificativ, firul de executie asociat garbage collector-ului creste in
prioritate. Memoria utilizata de obiecte care nu mai sunt referentiate in program este
solicitata intr-o maniera mai insistenta, pana cand se elibereaza o zona suficienta de
memoria, caz in care firul de executie al garbage collector-ului trece la o prioritate
scazuta.
Aceasta abordare non-deterministica de eliberare a memoriei are ca scop maximizarea
performantei aplicatiei si furnizeaza un mediu de aplicatii mai putin predispus la
actiunea bug-urilor (less bug-prone ). Exista, insa, un cost. Datorita mecanismului prin
care opereza garbage collector-ul, utilizatorul nu poate sti momentul in care un obiect
va fi dealocat. Deci, nu exista control asupra momentului apelarii destructorului clasei
Visual C# in cauza. Aceste metode ar trebui sa nu contina cod care se proiecteaza a fi
executat la un anumit moment. in schimb, pot fi scrise clase care utlizeaza o cantitate
importanta de resurse si care contin o metoda Dispose() pentru eliberarea explicita a
acestor resurse, atunci cand o instanta a acestei clase nu mai este necesara in
program.
Referinte circulare

Dezvoltare de aplicatii in Visual Studio .NET

Page 9 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Procesul de garbage collection are in vedere, de asemenea, si referintele circulare, o


forma foarte comuna de utilizare ineficienta a memoriei in medii de dezvoltare
anterioare. Sa consideram urmatorul exemplu:
class Widget
{
public Widget ChildWidget;
public Widget Parent;
}
class aClass
{
Widget GrandParent;
void Demo()
{
Widget Parent;
Widget Child;
GrandParent = new Widget();
GrandParent.ChildWidget = new Widget();
Parent = GrandParent.ChildWidget;
Parent.ChildWidget = new Widget();
Child = Parent.ChildWidget;
Child.Parent = Parent;
GrandParent = null;
//acum, Parent si Child se autorefera - referinta
circulara
}
}
Desi referintele circulare pot crea probeleme in ceea ce priveste detectarea zonelor de
memorie ocupate inutil in alte platforme de dezvoltare, garbage collector-ul din .NET
Framework este capabil sa detecteze si sa faca disponibile aceste zone. Deci, daca o
pereche de obiecte se autoreferentiaza, vor fi supuse procesului de garbage collection.
.NET Framework gestioneaza procesul de eliberare automata a memoriei prin
intermediul garbage collector-ului. Garbage collector-ul este un fir de executie de
prioritate scazuta care ruleaza intotdeauna im background-ul aplicatiei. Cand
memoria disponibila s-a diminuat, prioritatea garbage collector-ului creste pana cand
se vor elibera destule resurse.

Page 10 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Pentru ca nu se poate stabili momentul in care un anumit obiect va fi eliminat de


garbage collector, utilizatorul nu trebuie sa mizeze de codul scris in interiorul
destructorilor. in schimb, pentru eliberarea resurselor, se poate folosi o metoda
Dispose() care va fi apelata explicit.
Garbage collector-ul analizeaza in mod continuu arborele de referinte si elimina
obiectele la care nu se mai face referinta, precum si obiectele cu referinte circulare.
Detalii - MSDN Library, criteriu de cautare circular reference

Dezvoltare de aplicatii in Visual Studio .NET

Page 11 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 3. Tipuri de date si membri- II


1. Tipuri de date. Utilizare.
Microsoft .NET Framework furnizeaza un sistem foarte robust de tipuri primitive care
pot fi folosite pentru stocarea si reprezentarea datelor din cadrul aplicatiei. Datele
primitive reprezinta numere intregi, flotante, valori booleene, caractere si string-uri.
Sistemul de tipuri de date .NET Framework este type-safe, adica conversiile implicite
intre diferitele tipuri de date au loc numai daca acest lucru nu conduce la pierderi de
date. Conversiile explicite pot fi executate in situatii cate pot provoca pierderi de date.
Tipurile de date .NET contin functionalitati pentru a executa un set diversificat de
conversii de tip si alte sarcini similare.
OBIECTIVE:
intelegerea mecanismului conversiilor implicite si explicite dintre tipuri
descrierea functionalitatilor oferite de tipurile .NET Framework
prezentarea operatiilor cu string-uri, folosind metodele clasei String
.NET Framework pune la dispozitia utilizatorului un sistem extensibil de tipuri care
permit stocarea, manipularea si transmiterea valorilor intre diferitele entitati din cadrul
aplicatiei. Limbajele .NET sunt puternic tipizate (strongly typed). Aceasta inseamna
ca obiectele de un anumit tip nu pot fi schimbate cu obiecte de un alt tip. Apelul unei
metode va esua daca nu se specifica parametri avand tipurile corespunzatoarte.
Conversiile implicite si explicite permit transformari asupra datelor atunci cand este
nevoie. Acest lucru este posibil deoarece toate tipurile din .NET Framework sunt
derivate din Object, tipul de baza al tuturor claselr si structurilor.
Tipuri de date .NET
Tipuri valoare - subcategorii:

tipuri intregi
tipuri flotante
tipul Boolean
tipul Char

Tipuri referinta - frecvent folosite in aplicatii:


String
Object
Tipuri intregi
Tabelul urmator sintetizeaza aceste tipuri, prezentand tipurile din Visual C#
corespunzatoare.

Page 12 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Tip

Reprezentare C#

Descriere

Domeniu

System.Byte

byte

intreg fara semn pe 8 biti

de la 0 la 255

System.Int16

short

intreg cu semn pe 16 biti

de la -32768 la
32767

System.Int32

int

intreg cu semn pe 32 biti

de la -2 la 31 la 2
la 31 - 1

System.Int64

long

intreg cu semn pe 64 biti

de la -2 la 63 la 2
la 63 - 1

System.SByte sbyte

intreg cu semn pe 8 biti

de la -128 la 127

System.UInt16 ushort

intreg fara semn pe 16 biti

de la 0 la 65535

System.UInt32 uint

intreg fara semn pe 32 biti

de la 0 to 2 la 32
-1

System.UInt64 ulong

intreg fara semn pe 64 biti

de la 0 to 2 la 64
-1

Tabel 1 - Tipuri intregi


Se pot atribui valori tipurilor intregi folosind fie notatia zecimala, fie hexazecimala.
Pentru a folosi notatia hexazecimala pentru un literal intreg, acesta trebuie prefixat cu
0x in Visual C#. De exemplu: int nr_intreg;
nr_intreg = 0x36BA;
Tipuri flotante Exista trei astfel de tipuri care pot fi folosite pentru a reprezenta numere
cu parte fractionara. Tabelul urmator sintetizeaza aceste tipuri:
Tip

Reprezentare C#

Descriere

System.Single

float

variabila flotanta pe 32 biti, precizie - 7 cifre


semnificative

System.Double

double

pe 64 biti semnificativi, precizie 15-16

System.Decimal

decimal

pe 128 biti, precizie - 28 semnificativa

Tabel 2 - Tipuri flotante


Observatii:
System.Single - util pentru calcule in virgula mobila care necesita un grad scazut de
precizie
System.Double - pentru calcule cu un grad mai mare de precizie, operand cu
numere dintr-un interval foarte vast
System.Decimal - grad foarte mare de precizie, folosind insa numere dintr-un interval
mai restrans
Tipuri non-numerice
Dezvoltare de aplicatii in Visual Studio .NET

Page 13 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

System.Boolean
System.Char
System.String
System.Object

System.Boolean
Tipul System.Boolean este folosit pentru a reprezenta o valoare care este fie true, fie
false. In C#, o variabila booleana este desemnata prin intermediul tipului bool, cu
valorile posibile true si false.
System.Char
Tipul System.Char reprezinta un caracter Unicode pe 16 biti. In C#, o variabila de tip
char (tipul C# asociat) poate fi definita prin specificarea explicita a unui caracter intre
apostroafe: char caracter;
caracter = 't';
sau atribuind valoarea numerica a codului Unicode al caracterului variabilei de tip char,
folosind o valoare hexazecimala din 4 cifre, corespunzatoare: char caracter;
caracter = '\u01fe';
System.String
Tipul System.String este un tip referinta care reprezinta o succesiune de date de tip
Char. Cu alte cuvinte, un string poate desemna un cuvant, un paragraf, un cod sau
orice alta succesiune de caractere. Tipul C# asociat este desemnat de cuvantul
rezervat string.
Exemplu de utilizare: string sir;
sir = "Acesta este un string.";
System.Object
Tipul Object este parintele tuturor tipurilor din .NET Framework. Orice tip, fie valoare,
fie referinta, este derivat din System.Object. Tipul C# asociat - object. Unei variabile
object i se poate asocia orice valoare sau obiect: object obj;
obj = 233;
obj = new System.Collections.ArrayList();
!
Daca un obiect de un anumit tip este stocat intr-o variabila object, trebuie reconvertit
explicit la acel tip pentru a accesa intreaga sa functionalitate.

Page 14 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Tipuri de conversii
Datele pot convertite in doua feluri: implicit, caz in care conversia este executata
automat, si explicit - conversie executata de utilizator.
Conversii implicite
Sunt conversii care se executa atunci cand nu exista riscul pierderilor de date. De
exemplu: int un_short = 100;
long un_long;
un_long = un_short;
Daca un tip poate fi convertit implicit la un alt tip, atunci primul tip poate fi utilizat
oriunde in program unde se solicita cel de-al doilea tip, fara a folosi o sintaxa speciala.
De exemplu: // functia prelucare_long
// are un parametru de tip long
int x = 100; // conversie implicita de la int la long
// efectuata la apelul functiei
prelucare_long(I);
Tabelul urmator ilustreaza conversiile implicite permise in C#:
De la

La

byte

short, ushort, int, uint, long, ulong, float, double, decimal

short

int, long, float, double, decimal

int

long, float, double, decimal

long

float, double, decimal

float

double

char

int, uint, long, ulong, float, double, decimal

sbyte

short, int, long, float, double, decimal

ushort

int, uint, long, ulong, float, double, decimal

uint

long, ulong, float, double, decimal

ulong

float, double, decimal

Conversii explicite
In cazul unei conversii in care tipurile nu pot fi convertite implicit, trebuie aplicata o
conversie explicita. Aceasta conversie se mai numeste cast. In C#, conversiile explicite
necesita folosirea unei sintaxe speciale. Exemplu:
int un_int = 100;

Dezvoltare de aplicatii in Visual Studio .NET

Page 15 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

short un_short;
un_short = (short)un_int;
! Conversiile explicite pot fi riscante. In exemplul anterior, conversia s-a efectuat fara
nici un fel de problema pentru ca atat o variabila int, cat si una de tip short poate retine
valoarea 100. Sa consideram acum urmatorul exemplu:
int un_alt_int = 80000;
short un_alt_short;
un_alt_short = (short)un_alt_int;
Codul acestui exemplu nu va furniza eroare de compilare sau la run-time. Totusi,
examinand valoarea lui short, aceasta nu va fi cea dorita, deoarece valoarea maxima a
domeniului tipului short este mai mica decat valoarea la care se incearca conversia.
! Deoarece conversiile explicite sunt adesea riscante, este indicata folosirea lor numai
in cazuri absolut necesare, implementand un sistem adecvat de tratare a conversiilor
nereusite si a tuturor exceptiilor care ar putea fi aruncate. (vezi cursul 5).
Functionalitati asociate tipurilor de date Toate tipurile de date au o functionalitate
implicita (built-in ). Acestea suporta urmatoarele patru metode:

Equals - determina daca doua instante sunt egale


GetHashCode - actioneaza ca o functie hash pentru un tip de date
GetType - returneaza tipul obiectului pentru instanta curenta
ToString - returneaza o descriere a obiectului, intr-un format accesibil utilizatorului

? Din cele prezentate mai sus, reiese faptul ca tipurile de date ocupa un relativ mic de
memorie. Totusi, cum este posibil ca fiecare tip sa implementeze aceste metode?
Raspunsul este dat in cele ce urmeaza.
Boxing Boxing reprezinta conversia implicita a tipurilor valoare la tipuri referinta. Toate
clasele si tipurile sunt derivate din Object, fiecare din cele patru metode amintite fiind
membre ale clasei Object. Deoarece toate clasele sunt derivate din Object, fiecare
clasa poate fi convertita implicit la acest tip. La apelul uneia dintre cele patru metode,
Common Language Runtime creaza o referinta temporara variabila de tip valoare
declarata de utilizator si se permite tratarea acesteia ca fiind de tip referinta.
Boxing explicit(manual) - prin atribuirea variabilei detip valoare unei variabile de tip
Object. Exemplu:
short s = 10;
object O;
O = s;
Unboxing reprezinta conversia unei variabile boxed la un tip valoare. Se realizeaza
prin conversia explicita a obiectului la tipul dorit. Se poate executa unboxing numai
pentru obiectele care au fost supuse operatiei de boxing.
Metoda Parse
Page 16 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Parse - metoda statica, asociata tuturor tipurilor de date. Efectueaza conversia


string-ului primit ca parametru la tipul din care face parte. Daca string-ul nu are un
continut specific(potrivit) tipului care apeleaza metoda, se va genera o eroare.
short s;
string input;
input = "321";
// s = 321
s = short.Parse(input);
Functii pentru operatii cu siruri de caractere
Metode de instanta pentru siruri de caractere
Metoda

Descriere

String.Insert

Insereaza un string specificat in instanta curenta

String.PadLeft,
String.PadRight

Adauga caractere la stanga, respectiv la dreapta sirului

String.Remove

Elimina un numar specificat de caractere din string, incepand de la un


caracter precizat

String.Replace

Inlocuieste toate aparitiile unui caracter specificat din string cu un alt


caracter

String.Insert

Insereaza un string specificat in instanta curenta

String.Split

Returneaza un array de substringuri, obtinut prin separarea


token-urilor din stringul initial, dupa un separator specificat

String.Substring

Returneaza un substring al stringului initial

String.ToCharArray

Returneaza caracterele compunente ale sirului, sub forma de array de


caractere

String.ToLower,
String.ToUpper

Transforma stringul, convertind caracterele la litere mici, respectiv


mari

String.TrimEnd,
String.TrimStart, String.Trim

Elimina spatiile de la sfarsitul, inceputul stringului sau, respectiv toate


spatiile din cadrul sirului

Metode statice cu siruri de caractere


Metoda

Descriere

String.Compare

compara doua stringuri

String.Concat

returneaza un string obtinut prin concatenarea a doua sau mai multe


siruri de caractere

String.Format

returneaza stringul formatat

String.Join

returneaza un string obtinut prin concatenarea unui array de stringuri,


specificand un separator si inserandu-l intre componentele array-ului

Dezvoltare de aplicatii in Visual Studio .NET

Page 17 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Sinteza
.NET Framework furnizeaza un sistem robust, puternic tipizat de tipuri de date.
Principalele tipuri - intregi, flotante, boolean, caracter si string.
Exista doua tipuri de conversii - implicite, executate automat de CLR, atunci cand nu
exista riscul pierderii de date si explicite, efectuate explicit prin scriere de cod,
programatorul trebuind sa analizeze ci atentie cazurile care ar putea conduce la
erori.
Boxing - macanismul care permite tratarea tipurilor valoare ca tipuri referinta.
Unboxing - converteste un tip referinta asupra caruia s-a efectuat anterior boxing
catre un tip valoare.
Tipurile .NET contin functionalitate built-in specifica tipului. Metoda Parse este
implementata de toate tipurile valoare, fiind utila pentru conversia string-uriloe la
tipuri valoare. Clasa String contine un set de functii care faciliteaza manipularea
string-urilor.

2. Constante, enumerari, tablouri, colectii


Utilizatorul simte adesea necesitatea organizarii grupurilor de obiecte intr-un anumit tip
de structura. De exemplu, anumite obiecte, de acelasi tip sau de tipuri diferite trebuie
accesate secvential si este necesara o sintaxa pentru gestionarea organizarii
obiectelor. Tablourile (array) permit organizarea grupurilor de obiecte similare si
referirea lor printr-un index, adesea in defavoarea accesarii prin nume. Colectiile sunt
similare tablourilor, dar implementeaza o functionalitate mai complexa, fiind utilizate, in
special, pentru organizarea grupurilor de obiecte de tipuri diferite. Constantele pot primi
nume familiare si contin valori utilizate frecvent in program. Enumerarile (enum) permit
organizarea unor multimi de constante, facilitand executia anumitor operatii din cadrul
programului.
Constante si enumerari
Constantele permit asignarea unor nume familiare anumitor valori utilizate frecvent in
cod. Enumerarile sunt multimi definite de utilizatori continand constante asociate unei
multimi de nume. Folosirea constantelor si enumerarilor faciliteaza scrierea de cod,
debugging-ul codului si reduc numarul erorilor de scriere.
Utilizarea constantelor
Se foloseste cuvantul rezervat const Exemplu:
public const int MAX = 25000;
Constantele pot fi de orice tip intrinsec sau enumerativ, dar nu de un tip definit de
utilizator sau array. Constantele au o valoare fixata care odata stabilita nu mai poate fi
schimbata sau redefinita. Dupa definire, o constanta poate fi folosita in cod, prin
specificarea numelui asociat. De exemplu:
public const int MAX = 25000;

Page 18 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

public int half_max()


{
return MAX/2;
}
Ca si variabilele, constantele pot avea orice nivel de acces. Pentru a defini o constanta
care va putea fi accesata de toti utilizatorii aplicatiei sau componentei, trebuie declarata
public. O constanta declarata private va putea fi accesata doar in cadrul domeniului
clasei care o defineste. internal permite accesarea constantei din cadrul assembly-ului
care o contine, iar o constanta protected permite accesul la constanta si tipurilor
mostenite din clasa care contine constanta.
Enumerari
Enumerarile permit lucrul cu multimi de constante, prin asocierea acestora cu nume
familiare utilizatorului. Exemplu:
public enum LunileAnului
{
Ianuarie = 1,
Februarie = 2,
// si celelalte..., cu valorile uzuale
Decembrie = 12
}
Tipul asociat implicit elementelor enumerarilor int, dar poate fi setat la orice alt tip
numeric integral de date (byte, short, int si long). Modalitatea de definirea explicita a
tipului elementelor se poate observa in exemplul urmator:
public enum LunileAnului : short
// cod ...
NU este obligatorie asocierea de valori membrilor enumerarii. Implicit, membrii vor
primi valori implicite, secvential, pornind de zero. Exemplu:
public enum Cifre
{
zero, // egal cu zero
unu, // egal cu doi
doi // egal cu trei
}
Dupa definirea membrilor enumerarii, acestia pot fi folositi in cod. In C#, trebuie
efectuata o conversie explicita a membrilor la tipul dorit pentru a putea accesa valoarea
reprezentata. De exemplu:
Dezvoltare de aplicatii in Visual Studio .NET

Page 19 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

// se utilizeaza enumerarea Cifre anterioara


MessageBox.Show(((int)Cifre.doi * 3).ToString());
// se afiseaza 6
! Pot fi scrise metode care primesc enumerari ca parametri; codul scris astfel este mai
putin supus la erorile de scriere. Exemplu:
public void PlanLunar(LunileAnului luna)
//enumerarea definita mai sus
{
switch(luna)
{
case LunileAnului.Februarie:
// cod...
break;
case LunileAnului.Martie:
// cod...
break;
// alte case-uri...
}
}
Tablouri (array)
Reprezinta o modalitate de gestionare a unei multimi de elemente de tip valoare sau a
unei multimi de obiecte. Folosind tablouri, se pot grupa o serie de variabile, la care se
poate face referire folosind un index. Se pot accesa toate sau o parte dintre variabile si
examina sau modifica fiecare dintre aceste variabile. Se pot defini, de asemenea,
tablouri multidimensionale. In .NET Framework, tablourile contin functionalitati
intrinseci(buit-in) care faciliteazaa o serie de operatii.
Declararea si initializarea tablourilor
Declararea si initializarea se pot face in cadrul aceleasi instructiuni. Pentru declarare,
se specifica tipul si numarul elementelor din tablou. Pentru toate tablourile din C#,
indexul primului element este zero, celelalte avand indecsi calculati secvential, pornind
de la zero.
Exemplu:
// tablou cu 20 de elemente de tip short
short[] array_shorts = new short[20];
Declararea si initializarea se pot efectua, desigur, si in pasi separati. Exemplu:
Page 20 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

//declarare
short[] array_shorts;
// initializare
array_shorts = new short[20];
Un tablou poate fi redefinit, modificandu-i dimensiunea la run-time. Exemplu:
// declarare si initializare
int[] intregi = new int[20];
// reinitializare
intregi = new int[45];
In exemplul anterior, datele continute de tablou sunt pierdute la reinitializare. Nu exista
nici o modalitate de salvare a datelor la reinitializare (excluzand o varianta manuala).
La crearea unui tablou cu elemente de tip referinta, declararea si initializarea tabloului
nu conduc la umplerea tabloului cu membri de tipul respectiv. De fapt, se creaza un
tablou de referinte null care pointeaza la acel tip. Pentru a completa tabloul cu membrii,
trebuie asignata fiecare variabila la un obiect. De exemplu:
// se creaza un tablou de obiecte
TipObiect[] obiecte = new TipObiect[10];
// se asigneaza elementului obiecte[0] un nou obiect de tip
TipObiect
obiecte[0] = new TipObiect();
// asigneaza elementului obiecte[1] un obiect existent
TipObiect un_obiect = new TipObiect();
obiecte[1] = un_obiect;
// se atribuie celorlalte elemente cate un nou obiect
for (int contor = 2; contor < 10; contor++)
{
obiecte[contor] = new TipObiect();
}
Tablouri multidimensionale
Tablourile prezentate pana acum sunt liniare, adica, tablouri cu o singura dimensiune.
Exista in .NET Framework doua tipuri de tablouri multidimensionale: tablouri
rectangulare si tablouri jagged.
Tablouri rectangulare
Sunt tablouri in care fiecare membru al fiecarei dimensiuni este extins in fiecare alta
Dezvoltare de aplicatii in Visual Studio .NET

Page 21 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

dimensiune folosind aceeasi lungime. De exemplu, un tablou bidimensional,


rectangular, poate fi gandit ca un tabel tabel, continand linii si coloane, fiecare linie
avand acelasi numar de coloane.
Exemplu:
// tablou de 4 pe 3
int[ , ] intregi = new int[4, 3];
// tablou bidimensional cu valori initiale specificate
int[ , ] intregi2 = {{1, 2, 3}, {4, 5, 6}};
// tablou tridimensional
int[ , , ] cubeArray = {{{2, 2}, {2, 4}}, {{5, 5}, {4, 4}}};
// tablou complex: 2 x 3 x 5 x 5 x 6
int[ , , , , ] tablou_complex = new int[2, 3, 5, 5, 6];
Tablouri jagged
Un astfel de tablou, bidimensional, poate fi conceput ca un tabel in care fiecare linie
poate avea un numar diferit de coloane. De exemplu, sa consideram un tabel in care
fiecare linie reprezinta un grad universitar, iar coloanele contin numele profesorilor care
au gradul respectiv. Liniile vor putea avea, deci, un numar diferit de elemente. Pentru a
gestiona o astfel de structura, se foloseste un tablou jagged, ca mai jos:
// tablou de 5 tablouri
string[][] grade = new string[5][];
// specificam numai prima dimensiune
// primul tablou are 4 membri
grade[0] = new string[] {"Popescu", "Negara", "Ionescu",
"Radulescu"};
//o alta varianta de declarare si initializare
// al doilea tablou are 3 elemente
grade[1] = new string[] {"Vidrescu", "Alexandrescu", "Macovei"};
// si asa mai departe...
grade[3] = new string[] {"Buburuzan", "Georgescu"};
...
Colectii
Colectiile contin functionalitati avansate pentru gestionarea grupurilor de obiecte. O
colectie este o clasa specializata care organizeaza si permite manipularea unui grup
de obiecte. La fel ca la tablouri, membrii unei colectii pot fi accesati prin index. In plus,
colectiile pot fi redimensionate dinamic, existand posibilitatea adaugarii si eliminarii de
elemente la run time.
Page 22 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Colectiile sunt utile pentru gestionarea grupurilor de elemente create dinamic la run
time. De exemplu, ne putem imagina o colectie in care un element contine informatii
despre un salariat al unei institutii. Creand o colectie de obiecte de tip Salariat, va fi
posibila accesarea obiectelor, iterarea acestora, adaugarea de noi obiecte sau
eliminarea obiectelor care devin irelevante.
Clasa ArrayList
System.Collections.ArrayList - confera functionalitati specifice de colectie utile intr-o
serie intreaga de situatii. Aceasta clasa permite adaugarea si eliminarea dinamica de
elemente din lista. Elementele sunt accesate prin index Exemplu:
System.Collections.ArrayList lista = new
System.Collections.ArrayList();
Metoda Add
Dupa instantiere, pot fi adaugate elemente intr-un ArrayList utilizand metoda Add:
TipObiect obiect = new TipObiect();
lista.Add(obiect);
!
Orice lista de tip ArrayList este o colectie zero-based . Primul obiect introdus in lista are
indexul zero, elementele adaugate ulterior primind indexul imediat urmator elementului
anterior.
In C#, indexatorii sunt folositi pentru accesarea elementelor colectiilor, utilizand o
sintaxa similara tablourilor. Exemplu:
object obj;
obj = lista[0];
!
Toate referintele dintr-o colectie sunt de tipul object. Se impune, deci, folosirea
conversiilor explicite, pentru a obtine un element avand acelasi tip ca tipul elementului
din lista, returnat de indexator:
TipObiect obj;
obj = (TipObiect)listaObiecte[1];
Metodele Remove si RemoveAt
Remove - elimina obiectul a carui referinta este primita ca parametru din colectie
RemoveAt - elimina din colectie elementul de la indexul a carui valoare este primita
ca parametru
Exemplu:

Dezvoltare de aplicatii in Visual Studio .NET

Page 23 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

TipObiect obj = new TipObiect();


System.Collections.ArrayList lista = new
System.Collections.ArrayList();
// adauga obj la colectie
lista.Add(obj);
// elimina obiectul obj din colectie
lista.Remove(obj);
System.Collections.ArrayList lista = new
System.Collections.ArrayList();
// adauga 5 elemente la colectie
for (int i = 0; i < 5; i++)
{
TipObiect obj = new TipObiect();
lista.Add(obj);
}
// elimina elementul cu indexul 3
lista.RemoveAt(3);
!
Incercarea de eliminare a unui obiect care nu este continut in colectie va fi ignorata,
fara a se genera eroare.
La eliminarea unor elemente din colection, are loc o reasignare a indecsilor pentru a se
ocupa spatiile disponibile. Deci, valorile indecsilor sunt dinamice si pot returna referinte
diferite la momente diferite ale executiei aplicatiei.
Proprietatea Count Returneaza numarul de elemente din colectie (cu 1 mai mult decat
indexul maxim).
Alte tipuri de colectii
Clasa

Descriere

BitArray

tablou compact de biti

CollectionBase serveste drept clasa de baza pentru implementarea propriilor


clase cu functionalitate de colectie
Hashtable

colectie de perechi de tip cheie-valoare, organizate dupa codul


hash al cheii

Queue

gestioneaza un grup de obiecte dupa principiul first-in, first-out

SortedList

contine un grup de obiecte care pot fi accesate dupa index sau


dupa valoare

Page 24 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

Stack

ibm.com/developerWorks

gestioneaza un grup de obiecte dupa principiul last-in, first-out

Enumerarea (iterarea) membrilor unui tablou sau colectii


C# ofera o sintaxa specializata pentru parcurgerea membrilor unui tablou sau colectii.
Utilizarea cuvantului rezervat foreach permite examinarea succesiva a fiecarui membru
al unui tablou sau colectii. Exemplu:
int[] tab = new int[] {1,2,3,4};
foreach (int i in tab)
{
MessageBox.Show(i.ToString());
}
!
Pentru o utilizare corecta a acestei sintaxe, toti membrii colectiei trebuie sa aiba acelasi
tip ca al variabilei desemnate ca iterator (i pentru exemplul anterior). In caz contrat, va
fi aruncata o exceptie de tipul InvalidCastException. Solutie:declararea variabilei
iterator de tip object si utilizarea metodei GetType pentru a inspecta tipul obiectelor din
colectie. Exemplu:
// lista este un ArrayList care contine
// elemente de tip string si alte elemente de alte tipuri
foreach (object o in lista)
{
if (o.GetType() == typeof(string))
{
MessageBox.Show(o.ToString());
}
}
!
Referinta continuta de iterator este read-only . Deci, sintaxa foreach nu poate fi folosita
pentru a efectua modificari ale tabloului sau colectiei. Solutie: folosirea unei sintaxe de
tip for. Exemplu:
int[] tab = new int[] {1,2,3,4};
for (int i = 0; i <= 3; i++)
{
tab[i] ++; // modificare permisa
MessageBox.Show(tab[i].ToString());

Dezvoltare de aplicatii in Visual Studio .NET

Page 25 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
Sinteza:
Constante si enumerari (const si enum). Constantele pot avea orice tip. Enumerarile
trebuie sa aiba un tip numeric integral.
Tablourile pot fi unidimensionale sau multidimensionale. Tablourile
multidimensionale pot fi rectangulare sau jagged.
Colectiile permit gestionarea grupurilor de obiecte, cu elemente de acelasi tip sau de
tipuri diferite System.Collections ofera un set de clase cu diverse functionalitati
specifice colectiilor.
Sintaxa foreach permite iterarea membrilor unui tablou sau colectii, fara a putea
modifica membrii. Pentru a altera valorile membrilor unui tablou sau colectii, se
poate utiliza o sintaxa de tip for.

3.Proprietati
Proprietatile sunt membri ai claselor care acceseaza variabile sau obiecte membre.
Prezinta similaritati atat fata de campuri cat si fata de metode. Valorile sunt setate si
inspectate folosind acceasi sintaxa ca in cazul campurilor: de fapt aceste doua operatii
sunt efectuate prin apelul unor metode specializate. Proprietatile pot contine cod care
valideaza valorile inainte de a le seta sau pot indeplini alte functionalitati impuse de
aplicatie.
Implementarea proprietatilor
Proprietatile permit accesarea valorilor si obiectelor membre intr-o maniera mai robusta
in comparatie cu inspectarea obisnuita a campurilor. O proprietate este o metoda
specializata care se comporta ca un camp. Valorile proprietatilor sunt setate si
inspectate in acelasi mod ca si campurile, fapt ilustrat in exemplul urmator:
// seteaza proprietatea Text a butonului btnExit la "Exit"
btnExit.Text = "Exit";
string sir;
// returneaza valoarea lui btnExit.Text si o asigneaza
string-ului sir
sir = btnExit.Text;
Pana acum, o proprietate arata si se comporta exact ca un camp. Totusi, codul asociat
unei proprietati este mai complex. Exista doua metode speciale asociate unei
proprietati, un getter si un setter care returneaza si, respectiv, seteaza valoarea
proprietatii. Exemplu:
// proprietatea se numeste Xmax
// o variabila locala care stocheaza valoarea
Page 26 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

private short x;
// implementarea proprietatii
public short Xmax
{
get
{
// returneaza valoarea variabilei locale
return x;
}
set
{
// seteaza valoarea variabilei locale
x = value;
}
}
Cuvantul rezervat value este un cuvant special folosit in setter-ul unei proprietati si
reprezinta intotdeauna valoarea la care se seteaza proprietatea. Proprietatile pot
expune orice tip de obiecte, tablouri sau colectii. Valoarea sau obiectul este retinut, de
obicei, intr-o variabila privata locala (x in exemplul anterior) si returnat atunci cand
proprietatea este accesata.
Exemplul anterior poate fi considerat trivial, proprietatea Xmax comportandu-se exact
ca un camp. Avantajul utilizarii proprietatilor consta in posibilitatea scrierii de cod
aditional in getter-ul si setter-ul proprietatii pentru a efectua calcule sau valida input-ul.
Exemplu:
private short x;
public short Xmax
{
get
{
// returneaza valoarea variabilei locale
return x;
}
set
{
// valoarea nu trebuie sa depaseasca 500

Dezvoltare de aplicatii in Visual Studio .NET

Page 27 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

if (value > 500)


MessageBox.Show(value.ToString() +
" coordonata x nu poate depasi valoarea 500!");
else
x = value;
}
}
De retinut:
Pentru a crea o proprietate:
creati o variabila private care va retine valoarea sau obiectul returnat de proprietate
scrieti cod pentru returnarea valorii proprietatii
adaugati cod pentru validare sau efectuare de calcule in getter-ul si setter-ul
proprietatii

Proprietati read-only si write-only


Uneori, programatorul trebuie sa implementeze a proprietate care returneaza o valoare
care nu mai poate fi modificata dupa ce clasa a fost initializata. Alteori, intr-un numar
mai mic de situatii, se impune crearea unei proprietati a carei valori poate fi modificata
dar nu poate fi citita. Aceste proprietati sunt numite read-only si, respectiv, write-only .
Proprietati read-only
Crearea unei proprietati read-only se realizeaza prin specificarea getter-ului si omitand
setter-ul proprietatii. Variabila private care retine valoarea proprietatii este declarata, in
cele mai multe cazuri, readonly (acest lucru nu este obligatoriu). Exemplu:
private readonly short s;
public short ShortNumber
{
get
{
return s;
}
}
!
Setarea variabilei care retine valoarea proprietatii trebuie efectuata in constructorul
clasei sau la initializarea variabilei.
Proprietati write-only

Page 28 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

In anumite cazuri, pot fi implementate proprietati care pot fi scrise, dar nu citite, de
catre utilizator. Exemplu: pozitionarea unei forme in functie de setari specifice
localizarii(culturii) aplicatiei (localizare - concept care va fi prezentat intr-un curs viitor) forma este pozitionata la lansarea aplicatiei, nefiind necesara consultarea valorii
proprietatii respective.
O proprietate write-only se creaza similar unei proprietati obisnuite, omitand
implementarea getter-ului. Exemplu:
private short x;
public short XmaxForm
{
set
{
x = value;
}
}
Indexatori
Sunt proprietati specializate care permit accesarea obiectelor dintr-un grup. Numele
proprietatii este this, asociindu-se o variabila index. Exemplu:
// tablou care va stoca valorile retunate de indexator
private int[] tablou;
// sintaxa speciala care foloseste cuvantul rezervat this
public int this[int index] // indexatorul
{
get
{
return tablou[index];
}
set
{
tablou[index] = value;
}
}
Proprietati ale colectiilor
Expunerea colectiilor de obiecte ca proprietati permite controlarea accesului la
obiectele componente si validarea operatiilor de atribuire. Modalitatile de implementare
Dezvoltare de aplicatii in Visual Studio .NET

Page 29 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

a acestor proprietati depind de natura si functionalitatea colectiilor. O proprietate simpla


este cea care returneaza colectia ca un singur obiect (pentru siguranta, proprietatea
poate fi definita read-only, utilizatorul putand modifica obiectele din colectie folosind
metodele colectiei). Exemplu:
private readonly System.Collections.ArrayList list_objects = new
System.Collections.ArrayList();
public System.Collections.ArrayList objects
{
get
{
return list_objects;
}
}
!
Aceasta abordare nu rezolva problema verificarii tipurilor obiectelor adaugate la
colectie (membrii colectiei sunt tratati ca obiecte).
Iata o abordare mai pertinenta:
private System.Collections.ArrayList list_objects = new
System.Collections.ArrayList();
public ItemType GetItem(int i)
{
return (ItemType)list_objects[i];
}
public void SetItem(int i, ItemType item)
{
list_objects[i] = item;
}
Acesta abordare rezolva problema tipizarii, insa rapeste utilizatorului posibilitatea
folosirii sintaxei foreach pentru parcurgerea elementelor colectiei.
!
Pentru implementarea unor proprietati care implica functionalitati avansate se pot defini
colectii derivate din System.Collections.CollectionBase.
Sinteza:

Page 30 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

proprietati - expun variabile sau obiecte membre, furnizand cod pentru validarea
valorilor proprietatilor sau pentru efectuarea altor operatii; proprietatile read-only si
write-only limiteaza abilitatea utilizatorului de a consulta sau modifica propriatatile.
indexator - proprietate implicita a colectiilor
proprietatile colectiilor expun grupuri de obiecte din colectie

4.Delegati.Evenimente
Evenimentele reprezinta o notificare determinata de o actiune survenita intr-o sectiune
a a aplicatiei. La aparitia unui eveniment, altor parti ale aplicatiei li se ofera
oportunitatea de a raspunde prin executis unor metode denumite event handler-e.
Delegati
Un delegat este, in principiu, un pointer type-safe la o functie care permite
transmiterea unei referinte catre inceputul unei metode si apelarea metodei fara a
folosi un apel explicit al acesteia. La declararea unui delegat, se specifica signatura
metodei apelate si tipul returnat
Exemplu:
public delegate int firstDelegate(double D);
// acest delegat poate invoca metode care returneaza un int
// si primesc un parametru double
// metoda care va fi invocata de delegat
public int ReturnInt(double D)
{
// implementare...
}
// declararea unei instante firstDelegate si
// invocarea metodei ReturnInt
public void invokeMethod()
{
firstDelegate aDelegate = new firstDelegate(ReturnInt);
}
Invocarea metodei pentru care s-a instantiat delegatul:
aDelegate(6780.87);
Declararea si folosirea unui delegat:
Dezvoltare de aplicatii in Visual Studio .NET

Page 31 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

se declara delegatul, specificand o signatura identica cu cea a metodelor care vor fi


invocate
se creaza o instanta a delegatului care pointeaza catre o metoda care are signatura
adecvata
se apeleaza delegatul prin folosirea numelui sau, cu parametrii corespunzatori
Declararea si lansarea evenimentelor
Declaring and Raising Events Formele si controalele au evenimente membre implicite
(built-in) care sunt apelate cand au loc anumite actiuni in program. De exemplu,
evenimentul Click este lansat la executia unui clic asupra butonului.
In C#, pentru declararea unui eveniment, trebuie desemnat explicit tipul delegatului
care va fi utilizat de eveniment:
public delegate void calculationDelegate(double d);
public event calculationDelegate CalculationComplete;
Odata declarat, evenimentul poate fi lansat in code atunci cand actiunile care vor fi
notificate de eveniment au loc. De exemplu, o componenta BankAccount lanseaza un
eveniment Closing atunci cand se doreste inchiderea contului.
//Evenimentle in C# sunt lansate prin nume,
//ca in cazul unei metode
CalculationComplete(100000);
Tratarea evenimentelor
Dupa declarare, evenimentul trebuie asociat unuia sau mai multor event handlere
inainte de a putea fi lansat raised. Un event handler este o metoda apelata prin
intermediul unui delegat atunci cand un eveniment este lansat. Lansarea unui
eveniment care nu are asociat nici un event handler provoaca aparitia unei erori.
Event Handlere
Un event handler C# poate returna o valoare care poate fi asignata unei variabile la fel
ca in cazul unui apel de functie. Asocierea unei metode cu un eveniment se realizeaza
prin crearea unei instante a unui delegat adecvat evenimentului care specifica, la
randul sau, metoda pe care o invoca; se utilizeaza operatorul += pentru realizarea
asocierii. Se pot crea, de aemenea, asocieri intre un evenimentt si o instanta a unui
delegat existent. De exemplu:
// metoda DisplayResults are signatura adecvata
// delegatului CalculationDelegate
// se creaza un nou delegat pentru a crea asocierea
Account.CalculationComplete += new
calculationDelegate(DisplayResults);
// asociere cu un delegat existent

Page 32 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

calculationDelegate calc = new


calculationDelegate(DisplayResults);
Account.CalculationComplete += calc;
Pentru evenimentele asociate controalelor si claselor .NET Framework exista delegati
impliciti; acestia nu mai trebuie declarati ci doar instantiati. Exemplu: clasa
System.EventHandler este clasa cea mai utilizata pentru instantierea delegatilor.
button1.Click += new
System.EventHandler(clickHandler);
Sinteza:
pentru a trata un eveniment in C#, se creaza o instanta a delegatului care va fi asociat
evenimentului care va fi tratat si se foloseste operatorul += pentru a realiza asocierea
eveniment - delegat.
Event-handlere care trateaza mai multe evenimente
// ClickHandler este o metoda cu signatura adecvata
// tratarii evenimentului clic pentru un buton
button1.Click += new System.EventHandler(ClickHandler);
button2.Click += new System.EventHandler(ClickHandler);
Evenimente cu handlere multiple
Un eveniment poate fi tratat de mai multe handlere,acestea apelandu-se in ordinea
asocierii (operatorul +=), valoarea returnata de eveniment avand tipul returnat de
ultimul event handler asociat.
Eliminarea handlerelor la run-time
// se foloseste operatorul -=
Account.CalculationComplete -= new
calculationDelegate(DisplayResults);
Sinteza
evenimentele sunt membri ai claselor utilizati pentru notificarea anumitor actiuni din
program. O instanta a unei clase poate lansa un eveniment membru pentru a
transmite notificarea. Evenimentul poate fi trata de metode desemnate drept event
handlere. Aceste metode sunt executate la lansarea evenimentului.
delegatii implementeaza functionalitatea de la baza evenimentelor. Un delegat este
pointer la o functie, puternic tipizat. Poate invoca o metoda fara apelul explicit al
acesteia. Asocierile dintre evenimente si event handlere implica utilizarea explicita a
delegatilor.
Evenimentele sunt declarate ca membri ai clasei; pot fi apelati prin nume si pot
returna o valoare.
Dezvoltare de aplicatii in Visual Studio .NET

Page 33 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Metodele care trateaza evenimentele se numesc event handlere. Un event handler


se creaza prin utilizarea operatorului += pentru a asocia un delegat evenimentului.
Evenimentele pot avea mai multe event handlere asociat, si evenimente multiple pot
fi tratate de acceasi metoda. Event handlerele pot fi eliminate dinamic (folosind
operatorul -=).

Page 34 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 4. Gestionarea interfetelor utilizator - III


1. Design-ul interfetelor utilizator - principii

Descrierea importantei interfetei utilizator


Rolul formelor, controalelor si a meniurilor in cadrul interfetelor
Importanta compozitiei si culorilor interfetei utilizator
Explicarea folosirii imaginilor, icon-urilor si a fonturilor in design-ul interactiv

Forme, controale, meniuri


formele contin informatii si optiuni utile utilizatorilor
fiecare forma este o clasa, pentru care se pot crea instante sau care poate fi folosita
drept clasa de baza
controalele fac informatiile accesibile utilizatorilor
meniurile si tool box-urile furnizeaza o modalitate structurata de a expune comenzile
disponibile utilizatorilor aplicatiei
Aspectul si functionalitatea aplicatiei

simplitate
pozitionarea controalelor
consistenta: organizare, culori, forme, marime, tipuri, imagini, transparenta
estetica

Sinteza:
o interfata consistenta din punct de vedere vizual si logic este mult mai usor de
inteles si folosit
elementele de baza ale unei interfete sunt formele, controalele si meniurile
o interfata reusita trebuie sa tina cont de cateva aspecte legate de look si feel
sunt importante deciziile de design adresate direct utilizatorilor - semnificatii
culturale, consistenta, simplitate

2. Forme
Formele reprezinta unitatea fundamentala a unei interfete utilizator. Ele furnizeaza o
platforma pe care se plaseaza controalele si permit prezentarea aplicatiei intr-o
maniera consistenta si atractiva. Formele afiseaza date si primesc input-ul utilizatorilor.
De obicei, aplicatiile contin una sau mai multe forme, organizate astfel incat sa urmeze
logica fireasca a aplicatiei.
stabilirea rolului unei forme intr-o aplicatie
Dezvoltare de aplicatii in Visual Studio .NET

Page 35 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

adaugarea de forme la o aplicatie


setarea formei de start si a locatiei de start
setarea aspectului vizual al unei forme
folosirea metodelor unei forme
evenimente din cadrul metodelor

Adaugarea de forme la o aplicatie


La crearea unui proiect de tip Windows Forms, se creaza si se adauga la proiect o
forma initiala, denumita Form1. Form1 nu reprezinta, efectiv, o instanta a unei forme, ci
mai degraba o clasa care contine codul asociat unei instante a formei. Designer-ul este
o reprezentare grafica a componentei(de obicei o forma) supuse design-ului, conferind
posibilitatea adaugarii de controale, meniuri sau alte elemente vizuale formei
respective. Odata cu cresterea in dimensiuni a aplicatiei, se creaza noi forme sau alte
componente necesare bunei functionalitati a aplicatiei.
Adaugarea unei noi forme la un proiect:
1. Meniul Project, Add Windows Form. Se deschide astfel fereastra de dialog Add New
Item.
2. Se selecteaza Windows Form, apoi Open. Este adaugata o noua forma mediului de
lucru.
Adaugarea unei forme la o aplicatie la run time:
Se declara si se instantiaza o variabila reprezentand forma in aceeasi maniera ca in
cazul oricarei alte clase.
De exemplu:
// se presupune existenta unei forme de tip DialogForm
DialogForm forma1;
forma1 = new DialogForm();
Mostenirea vizuala
Mostenirea vizuala este un concept care se refera la crearea de noi forme, pornind de
la forme existente, in ideea de a pastra caracteristicile vizuale si functionalitatea
claselor de baza. Aceasta tehnica permite crearea unei forme care incorporeaza toti
membrii, controalele, meniurile si codul asociat unei forme existente, folosind aceasta
forma ca baza pentru implementarea unei functionalitati aditionale. Pentru a crea relatii
de mostenire se poate folosi fie Inheritance Picker-ul, fie varianta scrierii de cod.
Crearea unei forme derivate folosind Inheritance Picker-ul:
1. Meniul Projects, Add Inherited Form. Se deschide fereastra de dialog Add New Item.
2. In panoul din stanga se selecteaza Local Project Item, in dreapta, Inherited Form. Se
introduce un nume si se deschide Inheritance Picker-ul.
3. Acesta afiseaza formele existente in proiect, dintre acestea selectandu-se forma de
Page 36 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

baza care va fi asociata noii forme create.


! se poate alege drept clasa de baza si o forma dinafara proiectului, aceasta trebuie sa
fie compilata intr-un fisier EXE sau DLL.
Crearea unei forme derivate folosind scrierea de cod:
1. Meniul Projects, Add Windows Form.
2. Se modifica, in codul asociat clasei create, declaratia clasei.
// FormaBaza este o clasa existenta,
// asociata unei forme din proiect
public class FormaDerivata : FormaBaza
{
// implementare
}
! Proiectul trebuie sa aiba acces la forma din care de deriveaza. Deci, el trebuie sa
includa fie o referinta la assembly-ul care contine forma parinte (in acest exemplu,
MainForm) sau forma trebuie sa fie inclusa in proiect.
Setarea formei de start
Daca o aplicatie de tip Windows Forms contine mai multe forme, trebuie sa se
desemneze o forma de start. Forma de start va fi prima forma incarcata la executia
aplicatiei.
public static void Main()
{
Application.Run(new myForm());
}
Setarea formei de start in Visual C# se face utilizand meniul Projects, optiunea
Properties, apoi la StartupObject se alege forma dorita.
Setarea pozitiei de start
Proprietatea StartPosition se poate utiliza pentru a determina pozitia pe ecran la care
se va afisa prima data o forma. Aceasta poate fi setata la oricare dintre valorile
enumerarii FormStartPosition.
Valori FormStartPosition
Valoare

Efect

Manual

Forma se deschide la pozitia determinata de proprietatea


Location.

Dezvoltare de aplicatii in Visual Studio .NET

Page 37 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Forma se deschide centrat pe ecran.

CenterScreen

WindowsDefaultLocation Forma se deschide la locatia implicita determinata de


setarile Windows.
WindowsDefaultBounds

Forma se deschide la pozitia Windows implicita, avand


marimea stabilita prin setari Windows implicite.

CenterParent

Forma se deschide centrat, peste forma parinte.

Modificarea aspectului unei forme


Aspectul unei interfete este o parte importanta a unei aplicatii. Utilizarea proprietatilor
atasate diferitelor obiecte permite utilizatorului modificarea aspectului formelor.
Modificarea proprietatilor:
- din fereastra Properties
- modificand codul, la run-time
// schimbarea culorii unei forme form1
form1.BackColor = System.Drawing.Color.Red;
Proprietatile BackColor, ForeColor si Text
Text - stabileste titlul formei.
BackColor si ForeColor - reprezinta culorile atasate unei forme.
ForeColor este culoarea textului in foreground.
BackColor reprezinta culoarea de background a formei.
Alte proprietati:

Valoare

Efect

Font

specifica fontul folosit in cadrul formei

Cursor

specifica icon-ul care apare atunci cand sageata


mouse-uluise afla deasupra formei

BackGroundImage

permite setarea unei imagini de background

Opacity
- variaza gradul de transparenta al formei
- valori posibile: in intervalul [0, 1]. Valoarea 1 indica faptul ca forma este complet
opaca, iar valoarea 0 creaza o forma complet transparenta. Valorile intermediare
imprima formei o transparenta partiala. Valoarea implicita este 1 (opacitate totala).
// o forma semi-transparenta
Page 38 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

MyForm.Opacity = .5;
! in fereastra Properties, Opacity este reprezentata ca o valoare procentuala.
Utilizarea metodelor specifice formelor
Orice forma incapsuleaza un set functional de baza mostenit din clasa
System.Windows.Forms.Form. Printre acestea, se gasesc metodele responsabile de
modul de afisare si de posibilitatile de accesare a formei in mediul de lucru. Cele mai
importante astfel de metode:

Form.Show
Form.ShowDialog
Form.Activate
Form.Hide
Form.Close

Folosirea acestor metode implica existenta unei instante a formei in memorie. Pe langa
instantele formelor create in cod, aplicatia creaza o instanta a formei de start-up in
lansarii in executie a programului.
Show si ShowDialog
- Form.Show - face forma vizibila (se incarca in memorie o instanta a formei, se
afiseaza forma pe ecran si primeste focus-ul aplicatiei). Proprietatea Visible este setata
la true dupa apelul lui Form.Show. Pentru o forma incarcata in memorie dar care este
invizibila (de exemplu, daca proprietatea Visible a fost setata la valoarea false), apelul
Form.Show are acelasi efect ca setarea proprietatii Visible la valoarea true.
- Form.ShowDialog - in plus, afiseaza forma modal, adica forma trebuie inchisa inainte
ca orice alta forma sa poata primi focus-ul.
// DialogForm este o clasa asociata unei forme existente
DialogForm myForm = new DialogForm();
//afiseaza fereastra in mod uzual
myForm.Show();
//afizeaza fereastra modal
myForm.ShowDialog();
Activate
pentru o forma vizibila, dar care nu a primit inca focus-ul, se poate utiliza metoda
Form.Activate
apelata in cadrul aplicatiei active, metoda Form.Activate aduce forma in prim-planul
aplicatiei si ii transmite focus-ul
apelarea metodei pentru o aplicatie inactiva in interfata utilizator, determina clipirea
titlului aplicatiei din taskbar
forma pentru care se apeleaza metoda Activate trebuie sa fie vizibila pentru a obtine
Dezvoltare de aplicatii in Visual Studio .NET

Page 39 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

efectul scontat.
//apelarea metodei Activate
myForm.Activate();
Hide
face forma invizibila. Desi forma persista in memorie, nu va mai fi vizibila pana la
apelarea metodei Form.Show sau la setarea proprietatii Visible la valoarea true in
cod
apelul metodei Hide seteaza proprietatea Visible la false
//apelarea metodei Hide
myForm.Hide();
Close
Form.Close inchide forma si o elimina din memorie
se inchid toate resursele continute de forma, fiind preluate de garbage collector
apelul Form.Close anuleaza efectul unui apel ulterior Form.Show, pentru ca
resursele asociate formei nu mai sunt disponibile
apelul Form.Close pentru forma de start-up determina inchidera aplicatiei
//apelarea metodei Close
myForm.Close();
Evenimente din cadrul formelor
Eveniment - o notificare survenita in urma unei actiuni din program. Aplicatia lanseaza
evenimentul, iar o alta componenta a aplicatiei are oportunitatea de a trata evenimentul
respectiv. Fiecare dintre metodele prezentate anterior lanseaza unul sau mai multe
evenimente; utilizatorul are oportunitatea de a trata prin cod aceste evenimente.
Exemple: apelul metodei Form.Hide determina lansarea evenimentelor Deactivate si
VisibleChanged. Un event handler este o metoda care se executa ca raspuns la
lansarea unui eveniment.
Crearea unui event handler pentru o forma, un control sau o componenta
1. Design view - selectarea formei sau a controlului pentru care se va crea event
handler-ul
2. Properties - butonul Events
3. din lista evenimentelor disponibile se selecteaza evenimentul dorit
4. se scrie codul pentru event handler

Argumentele event handler-elor


Exemplu:
Page 40 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

private void Form1_Load(object sender, System.EventArgs e)


{
// codul metodei
}
Argumente:
- sender - obiect care contine o referinta catre obiectul care a lansat evenimentul
- e - instanta a clasei EventArgs; poate contine informatii suplimentare
! se poate obtine o referinta catre tipul care a cauzat lansarea evenimentului, in cazul
in care se cunoaste acest tip, printr-o conversie explicita a argumentului sender la tipul
respectiv. De exemplu:
Form1 myForm;
myForm = (Form1)sender;
In multe cazuri, parametrul EventArgs nu contine informatii folositoare din punct de
vedere programatic. Exista insa situatii in care acest parametru furnizeaza informatii
utile.
Evenimente referitoare la durata de viata a unei forme

Load
Activated/Deactivate
VisibleChanged
Closing
Closed

Load
Se lanseaza in momentul in care o forma este incarcata pentru prima oara in program
la primul apel al metodelor Form.Show sau Form.ShowDialog.
Exemplu:
Form myForm = new Form();
myForm.Show();
// se lanseaza Load
myForm.Hide();
// forma este acum invizibila
myForm.Show();
// nu se mai lanseaza Load
myForm.Close();
// se inchide forma
Dezvoltare de aplicatii in Visual Studio .NET

Page 41 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

myForm.Show();
// exceptie, forma nu mai este disponibila
!
evenimentul Load este lansat o singura data pe parcursul duratei de viata a unei
instante a formei
Activated/Deactivate
Evenimentul Activated poate aparea in urmatoarele situatii (la primirea focus-ului):
- la apelul metodelor Form.Show, Form.ShowDialog, Form.Activate
- cand o forma este adusa in prim-planul aplicatiei
Deactivate apare ori de cite ori o forma pierde focus-ul:
- prin interactiunea utilizatorului cu interfata
- la apelul metodelor Form.Hide sau Form.Close (Form.Close lanseaza evenimentul
numai daca forma este activa)
! Activated si Deactivate sunt lansate numai cand focus-ul este modificat prin
intermediul programului.
VisibleChanged
- lansat la schimbarea proprietatii visible a formei la apelul metodelor Form.Show,
Form.ShowDialog, Form.Hide si Form.Close.
Closing - lansat in cazul in care forma este in curs de inchidere, dar nu este inca
inchisa complet
- prin apelul Form.Close sau prin apasarea butonului Close al formei
- signatura event handler-ului asociat evenimentului Closing include o instansa a clasei
CancelEventArgs
//anularea inchiderii formei
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
Closed
- se lanseaza dupa ce forma a fost inchisa prin apelul Form.Close sau prin inchiderea
manuala a formei; apare dupa lansarea evenimentului Closing si dupa executia tuturor
handler-elor asociate acestuia
Sinteza:
Page 42 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Formele reprezinta elementul de baza al interfetei utilizator pentru un program de tip


Windows Forms. Formele trebuie sa contina o interfata consistenta, completa si
atractiva pentru utilizator.
Proprietati care controleaza aspectul unei forme:

BackColor
ForeColor
Text
Font
Cursor
BackGroundImage
Opacity

Metode care controleaza durata de viata si modul de afisare a formelor:

Form.Show
Form.ShowDialog
Form.Activate
Form.Hide
Form.Close

Fiecare dintre aceste metode provoaca schimbari de vizualizare si lanseaza diverse


evenimente. Printre acestea:

Load
Activated/Deactivate
VisibleChanged
Closing
Closed

Event handler-e: metode specializate de tratare a evenimentelor.

3. Controale si componente
Controalele reprezinta al doilea element al unei interfete vizuale, in ordinea importantei,
dupa forme.
Functionalitate:
- o parte dintre controale, cum ar fi Button sau TextBox, sunt desemnate sa accepte
input-ul utilizatorului si sa execute operatii bazate pe interactiunea utilizatorului
- o alta parte constituie componente specializate, proiectate sa execute interactiuni
complexe cu alte parti ale aplicatiei.

Dezvoltare de aplicatii in Visual Studio .NET

Page 43 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Asemanari si deosebiri intre controale si componente: ambele reprezinta unitati de cod


care incapsuleaza functionalitati specifice; controalele au o reprezentare vizuala, in
timp ce componentele nu.
Controale
Adaugarea unui control intr-o aplicatie Windows Forms
1. din Toolbox, se selecteaza controlul dorit.
2. se adauga controlul pe forma
3. eventual, se face o repozitionare a controlului.
Setarea proprietatilor unui (sau mai multor) control (controale) se realizeaza, cel mai
frecvent, folosind fereastra Properties
Adaugarea de componente la o forma se face in acelasi mod, la fel si setarea
proprietatilor. Diferenta principala fata de controale este aceea ca nu exista o
reprezentare vizuala a componentelor, odata cu adaugarea lor la o forma.
Control Tab Order
Utilizatorii pot folosi tasta Tab pentru a transmite focus-ul de la un control la altul, intr-o
anumita ordine - tab order. Aceasta ordine este specificata de proprietatea TabIndex.
Pentru a stabili ordinea de primire a focus-ului, se seteaza proprietatea TabIndex a
fiecarui control la o anumita valoare. Focus-ul va fi transmis controalelor in ordinea
crescatoare a valorilor proprietatii TabIndex. Visual Studio ofera a alta modalitate de
setare a ordinii de primire a focus-ului. Din meniul View, se alege Tab Order. In
designer, apare o casuta in interiorul fiecarui control care, prin clic ofera posibilitatea
setarii unui numar. Ordinea de primire a focus-ului este ordinea data de valorile
numerelor respective.
!
Exista controale care nu pot primi focus-ul, deci nu au asociata proprietatea TabIndex.
Controale container
Sunt controale speciale care ofera posibilitatea gruparii mai multor butoane in interiorul
lor. Exemple de astfel de controale - Panel, GroupBox si TabControl. Pot fi folosite
pentru organizarea logica a grupurilor de controale pe o forma. De exemplu, se pot
grupa un set de butoane radio intr-un control GroupBox.
!
- Un control container se comporta ca o gazda pentru alte controale, dar este
independent de aceste controale. In contrast, exista controale utilizator care pot lega
controale multiple intr-o singura unitate interdependenta.
- Modificarea proprietatilor unui control container poate afecta proprietatile controalelor
continute. De exemplu, daca proprietatea Enabled a unui GroupBox este setata la
false, toate controalele continute devin disabled. La fel se intampla in cazul
proprietatilor BackColor, ForeColor, Visible si Font. Acesta confera un aspect
Page 44 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

consistent interfetei utilizator.


GroupBox si Panel
Sunt doua controale container similare. Amandoua furnizeaza posibilitatea gruparii
logice si fizice a controalelor. Pot fi proiectate ca subdiviziuni ale formei. Modificarea
proprietatilor unui control Panel sau GroupBox afecteaza toate controalele continute.
Acestea pot fi grupate sau repozitionate ca o singura unitate in momentul design-ului.
La run-time, tot grupul poate fi dezactivat prin setarea proprietatii Enabled la false.
GroupBox - furnizeaza un titlu care va fi asociat intregului grup controale (modificand
proprietatea Text).
Panel - un container cu scroll, nu contine o proprietate text. Setand proprietatea
AutoScroll la true, se ataseaza bare de defilare panel-ului respectiv.
TabControl
- grupeaza controalele intr-o multime de tabele (similar diviziunilor dintr-o carte de
adrese)
- un TabControl este un suport pentru un anumit numar de TabPages, care gazduiesc
alte controale
- exemplu de TabControl: pagini de proprietati pentru o aplicatie, fiecare tab continand
proprietati referitoare la o componenta specifica aplicatiei.
Proprietatea TabPages reprezinta o colectie de controale TabPage, fiecare cu setul
sau de proprietati. O pagina din TabPages este similara controlului de tip Panel.
Adaugarea de TabPages se efectueaza prin utilizarea proprietatii TabPages.
Docking si Anchoring
Reprezinta proprietati ale controalelor care dicteaza comportamentul acestora in cadrul
formei sau controlului parinte.
- Anchor permite definirea unei distante constante intre un control si una sau mai multe
margini ale formei
- redimensionarea unei forme la run time implica pastrarea unei distante specifice fata
de marginile indicate
- valori posibile : o enumerare care poate contine, separate prin virgule una sau mai
multe dintre valorile Top, Left, Right, Bottom
- Dock permite atasarea controlului la una din marginile formei sau ocuparea completa
a formei de catre control
- redimensionarea formei atrage dupa sine redimensionarea controlului
- setarea valorii se face prin folosirea micro-interfetei grafice puse la dispozitie in
fereastra Properties
Utilizarea colectiei Controls
Fiecare container, incluzand formele, expun o colectie a tuturor controalelor continute controls collection. Colectia expune o proprietate Count care returneaza numarul de
Dezvoltare de aplicatii in Visual Studio .NET

Page 45 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

elemente continute si o proprietate Item care returneaza un element specific. Exista, de


asemene, metode care pot fi folosite pentru a adauga si elimina controale in cadrul
colectiei.
// se presupune existenta unei instante myForm
Control aControl;
aControl = myForm.Controls[3];
Label aLabel = new Label();
aLabel.Text = "Eticheta adaugata dinamic";
myForm.Controls.Add(aLabel);
myForm.Controls.Remove(Button1);
myForm.Controls.RemoveAt(3);
//sintaxa similara pentru adaugare si eliminare
//de controale intr-un
//Panel, GroupBox sau TabPage control
// myTabControl este o instanta a unui TabControl
Button aButton = new Button();
// se adauga un buton paginii cu indexul 1 in colectia
// TabPages din TabControl
myTabControl.TabPages[1].Controls.Add(aButton);
Adaugarea de noi controale in Toolbox
1. Se alege colectia din Toolbox la care se doreste adaugarea controlului.
2. Right-click in interiorul colectiei selectate - Customize Toolbox.
!
se pot adauga componente .NET sau componente COM existente
3. se poate selecta un control deja inregistrat in lista sau se foloseste Browse pentru a
localiza un control inca neinregistrat.
!
un control care se doreste adaugat trebuie recunoscut ca ActiveX Control, componenta
COM sau assembly .NET
Event Handlere pentru controale
Fiecare control poate lansa o varietate de evenimente care corespund interactiunii cu
utilizatorul. Un exemplu este apasarea unui buton care determina lansarea unui
eveniment, cautandu-se apoi eventualele handlere; handlerele gasite sunt lansate in
executie. Fiecare control are un eveniment implicit asociat, care reprezinta evenimentul
lansat cel mai frecvent. De exemplu, evenimentul implicit pentru Button este Click, iar

Page 46 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

pentru Checkbox, CheckChanged.


Crearea unui event handler pentru evenimentul implicit al unui control:
1. In designer, se executa dublu clic pe control. Se deschide fereastra de cod asociata
event handler-ului.
2. Se scrie codul dorit pentru event handler.
Pentru a crea un event handler pentru un eveniment in general:
1. Design view - se selecteaza controlul.
2. Din fereastra Properties - se selecteaza Events. Se afiseaza lista evenimentelor
disponibile pentru controlul respectiv.
3. Se alege evenimentul dorit, apoi se scrie codul.
4. Daca exista deja event handler-e implementate pentru controlul respectiv, se poate
alege una din metodele existente, din drop-down-ul asociat evenimentului respectiv.
Interactiunea cu mouse-ul
Tabel - Evenimente determinate de interactiunea cu mouse-ul
Eveniment

Descriere

Tip EventArgs

MouseEnter

mouse-ul intra in zona controlului

System.EventArgs

MouseMove

mouse-ul se misca pe suprafata


controlului

System.MouseEventArgs

MouseHover

mouse-ul se afla pe suprafata


controlului

System.EventArgs

MouseDown

mouse-ul se afla pe suprafata


controlului si se apasa un buton

System.MouseEventArgs

MouseWheel

miscarea rotitei de scroll a mouse-ului


atunci cand controlul are focus-ul

System.MouseEventArgs

MouseUp

mouse-ul se afla pe suprafata


controlului si se elibereaza un buton

System.MouseEventArgs

MouseLeave

mouse-ul paraseste suprafata


controlului

System.EventArgs

MouseEnter, MouseHover si MouseLeave semnaleaza faptul ca mouse-ul se afla in


regiunea unui control, transmitand putine informatii event handler-elor. MouseMove,
MouseDown, MouseWheel si MouseUp, din contra, pot fi folosite pentru a implementa
interactiuni substantiale intre utilizator si interfata. Un obiect de tip MouseEventArgs
contine informatii despre starea si locatia mouse-ului.
Tabel - proprietati MouseEventArgs
Proprietate

Descriere

Dezvoltare de aplicatii in Visual Studio .NET

Page 47 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Button

specifica daca s-a apasat un buton al mouse-ului

Clicks

returneaza numarul de click-uri efectuate

Delta

Returneaza numarul de actionari asupra rotitei mouse-ului;


acesta poate fi pozitiv sau negativ - deplasare inainte sau
inapoi; fiecare astfel de deplasare adauga sau scade 120
din valoarea anterioara

returneaza coordonta x a mouse-ului in momentul executiei


unui click

returneaza coordonta y a mouse-ului in momentul executiei


unui click

Componente de tip Extender Provider


Furnizeaza proprietati aditionale controalelor.
Exemplu: ToolTipProvider. La adaugarea unei instante a unui ToolTipProvider pe o
forma, fiecare control de pe forma capata o noua propritate - ToolTip on n, unde n este
numele ToolTipProvider-ului. La run-time, valoara acestei proprietati este afisata intr-o
casuta galbena atunci cand mouse-ul se afla deasupra controlului.
ToolTipProvider - specifica mesaje gen tips la run time
HelpProvider - specifica mesaje de help
ErrorProvider - specifica mesaje de eroare
Un ToolTipProvider detine metode denumite Getn si Setn, unde n este numele
proprietatii.
Exemple: GetToolTip si SetToolTip, care pot fi folosite dinamic in cod pentru a modifica
mesajele asociate controlului respectiv
(! la run time, aceste modificari nu pot fi facute prin intermediul controlului).
// preluarea ToolTip-ului asociat unui Button button1
string myToolTip;
myToolTip = toolTip1.GetToolTip(button1);
//setarea ToolTip-ului unui Button button1
toolTip1.SetToolTip(button1, "Click for help");
Sinteza
Ordinea de primire a focus-ului poate fi setata folosind proprietatea TabIndex sau
selectand Tab Order din meniul View si executand click pe controale in ordinea dorita.
Controale container:
- Panel
- GroupBox

Page 48 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

- TabPage
Proprietatile Dock si Anchor implementeaza redimensionarea automata controalelor pe
o forma.
Colectia de controale asociate unei forme permite adaugarea dinamica de controale la
run time.
Adaugarea de noi controale la un ToolBox se face prin selectarea din lista controalelor
inregistrate in sistem a controlului dorit sau prin selectarea fisierului .dll sau .exe
asociat, din file system.
Event handlere - metode care trateaza evenimentele
Componente de tip Extender Provider - furnizeaza informatii aditionale pentru
controalele de pe o forma.

4. Meniuri
Meniurile faciliteaza accesul la sectiuni importante din cadrul aplicatiei.
OBIECTIVE:
* Explicarea importantei meniurilor in cadrul interfetelor
* Crearea unui meniu folosind componenta MainMenu
* Crearea unui meniu contextual folosind componenta ContextMenu
* Activarea si dezactivarea unui menu item
* Crearea de shortcut-uri pentru un menu item
* Crearea unui check mark sau a unui buton radio pentru un menu item
* Explicarea procedurii prin care un menu item poate deveni invizibil
* Adaugarea dinamica a unui menu item la un meniu
* Clonarea dinamica a unui meniu
Meniurile permit utilizatorilor sa acceseze comenzi si functii intr-o maniera familiara,
usor de inteles. In momentul proiectarii meniurilor, trebuie avut in vedere parcursul
logic al aplicatiei, elementele componente ale meniului trebuie grupate in concordanta
cu o anumita functionalitate.
Crearea meniurilor folosind Design View
Se foloseste componenta MainMenu. Aceasta contine si gestioneaza o colectie de
controale MenuItem care reprezinta elementele vizuale ale unui meniu la run time.
Componenta MainMenu

Dezvoltare de aplicatii in Visual Studio .NET

Page 49 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

* Crearea de noi meniuri si bare de meniu


* Adaugarea de menu items la meniuri existente
* Modificarea proprietatilor meniurilor si a elementelor meniurilor prin intermediul
ferestrei Properties
* Crearea de event handlere
La adaugarea unei optiuni intr-un meniu, designer-ul creaza o instanta a unui obiect
MenuItem. Fiecare obiect MenuItem are proprietatile si membrii sai care pot fi
modificati in fereastra Properties. Doua proprietati importante: Text - contine textul
afisat la run time si Name - numele asociat instantei MenuItem, prin care se va face
referire in cod.
Crearea de meniuri la design time - se adauga o componenta MainMenu la forma
- se adauga elemente la meniu, folosind interfata grafica
Separarea elementelor din meniu
Un astfel de separator reprezinta o linie orizontala care delimiteaza anumite elemente
ale meniului, folosta de obicei pentru a face o separarea logica a functionalitatilor din
cadrul unui meniu. Se realizeaza prin tastatea caracterului - in spatiul rezervat numelui
elementului de meniu respectiv. Separatorul va constitui un element de meniu.
Taste de acces si taste de shortcut
Sunt utile pentru facilitarea accesului la optiuni din meniuri folosind tastatura.
Taste de acces
Permit utilizatorilor accesarea unui meniu prin apasarea unei combinatii de taste
formate din Alt si o litera. Atunci cand meniul este deschis, se poate selecta o anumita
comanda folosind combinatia de taste Alt + litera de acces corecta. Exemplu : Alt + F
deschide meniul File.
Pentru a atribui o tasta de acces unui menu item:
1. se selecteaza in designer elementul de meniu dorit
2. se tasteata un ampersand in fata literei care va desemna accesul la optiunea
respectiva
Taste de shortcut
Permit accesul instant la comenzi de meniu, furnizand un shortcut pentru comenzi
frecvente din meniu. Combinatia de taste asociata unei comenzi poate fi formata
dintr-o singura tasta, cum ar fi Delete, F2 sau Insert, sau din mai multe, de exemplu
Ctrl+B, Ctrl+F3 sau Alt+Shift+S. In cazul in care proprietatea ShowShortcut a unui
element de meniu este setata la true si daca exista o combinatie de taste asociata,
aceasta va fi afisata in dreapta elementului de meniu in cauza.
Pentru a asigna un shortcut:
- se seteaza proprietatea Shortcut la combinatia de taste dorita

Page 50 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Evenimente asociate elementelor meniurilor


Metodele care trateaza evenimentele lansate de elementele meniurilor se creeaza
similar altor controale.
- Cel mai frecvent folosit eveniment este Click
- Evenimentul Select este lansat la vizualizarea unui meniu prin click sau folosind
tastele de acces. Poate fi utilizat pentru crearea unui help privitor la modul de utilizare
a unei anumite comenzi.
- Evenimentul Popup este lansat inainte ca un element al meniului sa fie afisat. O
aplicatie utila poate fi activarea sau dezactivarea anumitor elemente de meniu la run
time.
Meniuri contextuale
Un meniu contextual este vizualizat la apasarea butonului dreapta al mouse-ului pe
forma sau controlul caruia ii este asociat. Se creaza folosind componenta
ContextMenu. Se editeaza similar componentei MainMenu. Meniurile contextuale
gestioneaza o colectie de controale de tip menu-item, permite folosirea tastelor
shortcut, dar nu se pot defini taste de acces. Pentru a asocia un meniu contextual unei
forme sau unui control, se seteaza proprietatea ContextMenu a formei sau controlului
respectiv la numele meniului contextual dorit.
! un meniu contextual poate fi asociat mai multor controale, insa un singur meniu
contextual poate fi asociat unui control.
Modificarea meniurilor la run time
In functie de anumite conditii indeplinite la run time:
- se pot dezactiva anumite comenzi din meniu
- se pot afisa cate un check mark sau un buton radio in dreptul unui menu item pentru
a furniza informatii utilizatorului
- se pot ascunde anumite elemente de meniu atunci cand utilizarea lor este inadecvata
- se pot adauga elemente in meniuri la run time sau pot fi clonate sau concatenate cu
alte elemente de meniu
Activarea sau dezactivarea comenzilor din meniuri
Se utilizeaza proprietatea Enabled.
Exemplu:
menuItem1.Enabled = false;
Afisarea casutelor de selectare (check marks)
Se utilizeaza proprietatea Checked.
Exemplu:

Dezvoltare de aplicatii in Visual Studio .NET

Page 51 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

menuItem1.Checked = true;
menuItem1.Checked = false;
Afisarea butoanelor radio
Se utilizeaza proprietatea RadioCheck.
! butoanele radio sunt folosite frecvent pentru afisarea unor optiuni exclusive
Ascunderea elementelor meniurilor
Se utilizeaza proprietatea Visible.
menuItem1.Visible = false;
!
Submeniurile continute de menu item-ul care devine invizibil vor deveni, de asemenea,
invizibile si, deci, innaccesibile.
Clonarea meniurilor
Se refera la copierea unor elemente de meniu la run time. Clonare imseamna
transmiterea tuturor informatiilor posibile obiectului caruia i se asigneaza obiectul
rezultat in urma acestei operatii.
Exemplu: clonarea meniului Edit (si a submeniurilor asociate) dintr-un main menu
pentru a servi drept meniu contextual unui control.
// fileMenuItem este un menu item existent,
// myButton este un Button
// declararea si

instantierea unui meniu contextual

ContextMenu myContextMenu = new ContextMenu();


// se cloneaza fileMenuItem si se adauga meniului contextual
myContextMenu.MenuItems.Add(fileMenuItem.CloneMenu());
// se asigneaza noul meniu contextual butonului myButton
myButton.ContextMenu = myContextMenu;
Concatenarea meniurilor la run time
Pot fi concatenate mai multe meniuri de tip MainMenu cu meniuri contextuale, meniuri
cu menu items sau mai multe menu items.
Exemplu:
fileMenuItem.MergeMenu(myContextMenu);
Adaugarea de elemente de meniu la run-time
Exista posibilitatea adaugarii de noi elemente de meniu pe durata executiei aplicatiei.
Page 52 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

De exemplu, intr-un meniu, pot fi adaugate item-uri care sa afiseze caile spre cele mai
recente fisiere deschise de aplicatie. Aceste noi elemente de meniu nu vor avea event
handlere asociate, dar poate fi specificata o metoda de tratare a evenimentului Click,
ca argument al constructurului noului item. Aceasta metoda trebuie sa fie void si sa
aiba aceeasi signatura ca celelalte event handlere. Exemplu:
public void ClickHandler (object sender, System.EventArgs e)
{
// implementare...
}
Adaugarea dinamica a elementelor de meniu
Exemplu:
// ClickHandler este o metoda cu signatura
// corespunzatoare unui event handler
MenuItem myItem;
myItem = new MenuItem("Item 1", new EventHandler(ClickHandler));
//se adauga item-ul creat la un alt menu item
fileMenuItem.MenuItems.Add(myItem);
Sinteza
* meniurile permit accesul facil la comenzi din carul aplicatiei prin intermediul unei
interfete usor de folosit
* meniurile contextuale permit accesul la anumite comenzi in situatii contextuale
* meniurile se pot modifica la run time in functie de anumite situatii

5. Validarea input-ului utilizatorilor


In multe aplicatii, utilizatorul introduce informatii necesare aplicatiei folosind interfata
utilizator. Validarea datelor verifica faptul ca informatiile introduse respecta anumiti
parametri impusi de aplicatie, inainte de lansarea in executie a programului. De
exemplu, ar putea exista un camp in care utilizatorul introduce un cod ca parte a unei
adrese. Folosind validarea, se poate verifica daca s-a introdus un anumit numar de
caractere, si toate acestea sunt cifre, inainte de a continua. Validarea input-ului
utilizatorilor reduce sansa aparitiei unei erori logice sau de executie si confera aplicatiei
un caracter mult mai robust.
OBIECTIVE:
* Explicarea diferentei dintre validarea form-level si field-level
Dezvoltare de aplicatii in Visual Studio .NET

Page 53 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

* Directionarea focus-ului folosind metode si evenimente asociate controalelor


* Implementarea validarii form-level
* Implementarea validarii field-level
Validarea de tip form-level verifica datele dupa ce utilizatorul a completat toate
campurile de pe o forma. Folosind validare form-level, toate campurile de pe o forma ar
putea fi validate atunci cand utilizatorul a apasat butonul OK. Pe de alta parte,
validarea field-level verifica daca datele introduse in fiecare camp respecta conditii
specifice. De exemplu, daca un utilizator completeaza un camp asociat unui numar de
telefon, validarea field-level poate verifica daca numarul este valid, inainte de a avansa
la urmatorul camp. Odata cu tastarea unui caracter, anumite evenimente asociate
controlului respectiv pot verifica daca s-au introdus numai cifre.
Validare field-level
Proprietati ale clasei TextBox
Controlul TextBox este controlul cel mai frecvent folosit pentru input-ul utilizatorilor. O
serie de proprietati ale acestui tip de control restrictioneaza valorile introduse la
multimea de valori acceptabile. Cele mai importante proprietati de acest fel sunt:
* MaxLength - limiteaza numarul de caractere care pot fi introduse
* PasswordChar - ascunde input-ul la run time
* ReadOnly - true sau false (permite sau nu editarea)
* MultiLine - true sau false (permite sau nun introducerea datelor pe mai multe linii)
Validare field-level - utilizarea evenimentelor
Controalele care pot primi input de la tastatura lanseaza urmatoarele evenimente
specifice:
* KeyDown
* KeyPress
* KeyUp
KeyDown si KeyUp
Evenimentele KeyDown si KeyUp survin la apasarea si, respectiv, eliberarea unei
taste. Controlul care detine focus-ul lanseaza evenimentul. La lansarea acestor
evenimente, informatiile legate de tasta sau combinatia de taste care au fost apasate
sau eliberate pot fi preluate folosind o instanta a clasei KeyEventArgs. Un event
handler asociat evenimentelor KeyDown si KeyUp trebuie sa includa un parametru de
tip KeyEventArgs in signatura sa.
Proprietati KeyEventArgs
Proprietate

Descriere

Alt

specifica daca s-a apasat sau nu tasta Alt

Page 54 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Control

specifica daca s-a apasat sau nu tasta Ctrl

Handled

returneaza o valoare indicand daca evenimentul a fost tratat

KeyCode

returneaza un enum care specifica tasta apasata

KeyData

intoarce informatii despre tasta care a fost apasata,


verificand si daca s-a apasat Alt, Ctrl sau Shift

KeyValue

returneaza o reprezentare sub forma de intreg a proprietatii


KeyData

Modifiers

returneaza flag-uri care indica ce combinatie a tastelor Alt,


Ctrl sau Shift s-a folosit

Shift

specifica daca s-a apasat tasta Shift

Evenimentele KeyUp si KeyDown sunt cel mai frecvent utilizate pentru a determina
daca s-a apasat Alt, Ctrl sau Shift, prin intermediul proprietatilor instantei
KeyEventArgs transmisa ca parametru handler-ului. Proprietatile KeyEventArgs Alt,
Control si Shift returneaza o valoare booleana care indica daca aceste taste sunt
apasate - true daca tasta corespunzatoare este apasata si false daca a fost eliberata.
Exemplu: se verifica daca tasta Alt este apasata
private void textBox1_KeyUp(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if (e.Alt == true)
MessageBox.Show("Tasta ALT este inca apasata");
}
Proprietatea KeyEventArgs.KeyCode se poate utiliza pentru a examina tasta care a
lansat evenimentul. Returneaza o valoare Key care reprezinta tasta care a fost apasata
(evenimentul KeyDown) sau eliberata (evenimentul KeyUp).
Exemplu:
afisarea intr-un MessageBox a reprezentarii sub forma de string a tastei care a fost
apasate.
private void textBox1_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
MessageBox.Show(e.KeyCode.ToString());
}
KeyPress
Atunci cand utilizatorul apasa o tasta care are o valoare ASCII asociata, se lanseaza
evenimentul KeyPress. Printre tastele care au o valoare ASCII asociata sunt incluse
Dezvoltare de aplicatii in Visual Studio .NET

Page 55 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

caracterele alfabetice si numerice (a-z, A-Z, 0-9), precum si anumite taste speciale,
cum ar fi Enter and Backspace. Daca o tasta sau o combinatie de taste nu genereaza
o valoare ASCII, apasarea lor nu va determina aparitia evenimentului KeyPress.
Exemple de astfel de taste includ Ctrl, Alt si tastele functionale. La aparitia acestui
eveniment, se trasmite handler-ului ca parametru o instanta a clasei
KeyPressEventArgs. Aceasta instanta contine informatii despre tasta apasata care pot
fi folosite pentu validarea input-ului. Proprietatea KeyPressEventArgs.KeyChar contine
caracterul ASCII reprezentat de combinatia de taste care a lansat evenimentul.
KeyPressEventArgs.Handled este proprietatea care indica daca evenimentul a fost
tratat.
Validarea caracterelor
Tipul Char contine mai multe metode statice utile pentru validarea caracterelor
furnizate de evenimentul KeyPress. Cele mai importante astfel de metode:
* Char.IsDigit
* Char.IsLetter
* Char.IsLetterOrDigit
* Char.IsPunctuation
* Char.IsLower
* Char.IsUpper
Exemplu:
utilizarea metodei Char.IsDigit pentru a testa daca s-a apasat o tasta numerica:
private void textBox1_KeyPress (object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
if (Char.IsDigit(e.KeyChar) == true)
MessageBox.Show("Ai apasat o tasta numerica");
}
Tratarea focus-ului
Focus-ul reprezinta abilitatea unui obiect de a primi input prin intermediul mouse-ului
sau tastaturii. Un singur control poate detine focus-ului la un moment dat. Acesta se
afla pe forma activa a aplicatiei. Fiecare control implementeaza metoda Focus care
seteaza focus-ul controlului care a apelat-o. Returneaza o valoare booleana care
indica daca setarea focus-ului s-a executat cu succes sau nu. Proprietatea CanFocus
returneaza true in cazul in care controlul poate primi focus-ul si false in caz contrar.
if (textBox1.CanFocus == true)
textBox1.Focus();
Evenimentele referitoare la primirea sau pierderea focus-ului au loc in urmatoarea
Page 56 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ordine:
1. Enter
2. GotFocus
3. Leave
4. Validating
5. Validated
6. LostFocus
Enter si Leave - controlul primeste si, respectiv, pierde focusul.
GotFocus si LostFocus - controlul obtine pentru prima oara focus-ul, respectiv,controlul
pierde focus-ul.
Validating si Validated - cele mai utile evenimente pentru validarea field-level.
Validating si Validated
Validating - are loc inainte ca un control sa piarda focus-ul. Proprietatea
CausesValidation a controlului care va primi focus-ul si a celui care trebuie validat
trebuie setata la true pentru ca evenimentul sa poata fi lansat. Exemple de cazuri de
utilizare: un event handler care testeaza daca input-ul respecta un anumit format,
imposibilitatea parasirii unui control pana la introducerea unor informatii de un anumit
tip.
Validated - este lansat dupa ce controlul a fost validat cu succes. Poate fi folosit pentru
a executa operatii bazate pe input-ul validat.
Exemplu:
event handler pentru evenimentul Validating
private void textBox1_Validating(object sender,
System.ComponentModel.CancelEventArgs e)
{
// verifica valoarea introdusa in textBox1
if (textBox1.Text == "")
// se reda focus-ul controlului
e.Cancel = true;
}
Validare form-level
Reprezinta procesul validarii simultane (in acelasi moment al executiei aplicatiei) a
tuturor campurilor de pe o forma. O procedura centralizatoare implementeaza validarea
form-level si este apelata, de obicei, in momentul in care utilizatorul doreste sa treaca
la un nou pas al aplicatiei.
Dezvoltare de aplicatii in Visual Studio .NET

Page 57 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Exemplu:
la apasarea unui buton, se verifica toate toate controalele de tip TextBox au fost
completate si se transmite focus-ul primului TextBox care nu indeplineste aceasta
conditie, in cazul in care exista un asemenea TextBox.
private void btnValidate_Click(object sender,
System.EventArgs e)
{
// parcurgerea iterativa a tuturor controalelor de pe forma
foreach (System.Windows.Forms.Control aControl in this.Controls)
{
// se verifica daca este un TextBox si
// daca contine stringul vid
if (aControl is System.Windows.Forms.TextBox)
{
if (aControl.Text == "")
// se transmite focus-ul primului control care
// indeplineste conditia de mai sus
aControl.Focus();
return;
}
}
}
Keyboard Handler pentru validare form-level
Reprezinta o tehnica mai sofisticata de validare form-level. Un keyboard handler
centralizat permite gestionarea input-ului din toate campurile de pe o forma. Se
folosesc evenimentele KeyPress, KeyDown si KeyUp.
! pentru ca o forma sa lanseze aceste evenimente, proprietatea KeyPreview formei
trebuie setata la valoarea true. In acest caz, forma lanseaza evenimente legate de
apasarea tastelor inaintea controlului care detine focus-ul. Pentru a preveni executia
event handler-ului asociat evenimentului KeyPress al unui control, se seteaza
proprietatea KeyPressEventArgs.Handled la true:
private void Form1_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
//evita pasarea evenimentului event handler-ului
Page 58 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

//asociat controlului care detine focus-ul


e.Handled = true;
}
Feedback
La introducerea unui input invalid, utilizatorul trebuie alertat si trebuie sa i se ofere
oportunitatea de a corecta eroarea.
Modalitati de atentionare:
- pentru erori simplu de intuit, este suficienta o notificare auditiva
- schimbarea proprietatilor BackColor sau ForeColor ale controlului la care a survenit
eroarea
- utilizarea metodei MessageBox.Show, in diferite formate
Exemplu:
MessageBox.Show("Valoare invalida pentru acest control!");
Componenta ErrorProvider
Permite setarea unui mesaj de eroare pentru fiecare control de pe forma de fiecare
data cand se introduce un input invalid. Se afiseaza un icon de eroare in dreptul
controlului, iar textul mesajului de eroare este afisat ca Tool Tip atunci cand mouse-ul
este pozitionat deasupra controlului afectat.
Afisarea unui mesaj de eroare
Se utilizeaza metoda SetError a componentei ErrorProvider.
Exemplu:
// nameTextBox este o instanta a clasei TextBox,
// myErrorProvider este un ErrorProvider
myErrorProvider.SetError(nameTextBox,
"numele nu poate fi vid!");
Setarea mesajului de eroare la design-time se poate efectua prin setarea proprietatii
Error on x asociata controlului, unde x este numele ErrorProvider-ului.
Alte proprietati ale componentei ErrorProvider:
- Icon - specifica icon-ul vizualizat in dreptul controlului
- BlinkStyle - determina daca icon-ul va clipi in momentul aparitiei unei erori
- BlinkRate - stabileste cat de repede va clipi icon-ul
Exemplu:
Dezvoltare de aplicatii in Visual Studio .NET

Page 59 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

private void passTextBox_Validating(object sender,


System.ComponentModel.CancelEventArgs e)
{
// validarea input-ului
if (passTextBox.Text == "")
// setarea mesajului de eroare
myErrorProvider.SetError(passTextBox, "Parola nu poate fi
vida!");
else
// nu se afiseaza nici un mesaj de eroare
myErrorProvider.SetError(pswordTextBox, "");
}
Sinteza
* Validare form-level vs. field-level
* Proprietati ale controlului TextBox control care restrictioneaza input-ul utilizatorului:
- MaxLength
- PasswordChar
- ReadOnly
- MultiLine
* Evenimente lansate de intercatiunea utilizatorului cu tastatura:
- KeyDown
- KeyUp
- KeyPress
* Metode statice ale clasei Char utile in validarea input-ului:
- Char.IsDigit
- Char.IsLetter
- Char.IsLetterOrDigit
- Char.IsPunctuation
- Char.IsLower
- Char.IsUpper
* Validating - principalul eveniment folosit pentru validare
* ErrorProvider - componenta utila pentru setarea mesajelor de eroare

Page 60 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 5. Concepte POO in Visual Studio .NET - IV


1. Concepte generale POO
Programarea in .NET Framework este realizata cu ajutorul obiectelor. Obiectele sunt
constructii programatice care reprezinta pachete de date cu functionalitate unitara.
Obiectele furnizeaza mediului de dezvoltare de aplicatii o functionalitate specifica, fara
a se detalia comportamentul intern al obiectului. Obiectele sunt create pe baza unui
sablon, denumit clasa. Libraria de clase .NET furnizeaza un set de clase de la care se
pot crea obiecte in cadrul aplicatiilor. Exista, desigur, posibilitatea crearii propriilor clase
in Microsoft Visual Studio.
Obiecte, membri, abstractizare
Un obiect este o constructie programatica care reprezinta o anumita entitate in cadrul
aplicatiei. In lumea reala, obiectele sunt computere, case, masini etc. Fiecare dintre
aceste elemente au o anumita functionalitate si sunt caracterizate de o serie de
proprietati specifice. Intr-o aplicatie, un obiect poate fi o forma, un control, o conexiune
la o baza de date, si asa mai departe. Fiecare obiect reprezinta o unitate functionala,
continand toate datele si functionalitatea necesare pentru a isi indeplini sarcinile in
cadrul aplicatiei. Abilitatea obiectelor programatice de a reprezenta obiecte din lumea
reala este numita abstractizare.
Clasele - sabloane pentru obiecte
Clasele reprezinta tipuri referinta definite de utilizator. Clasele ar putea fi privite ca o
amprenta pe care toate obiectele de acest tip o poarta: ele definesc toti membrii unui
obiect, comportamentul acestuia si seteaza valorile initiale ale datelor membre, dupa
caz. La instantierea unei clase, se creaza o instanta a clasei respective in memorie.
Aceasta instanta este denumita obiect. O clasa se instantiaza utilizand cuvantul
rezervat new, dupa cum urmeaza:
// se declara o variabila de tip TipObiect
TipObiect un_obiect;
// instantiere si asignare
un_obiect = new TipObiect();
La instantierea unei clase, se creaza in memorie o copie a datelor care formeaza
instanta si acestea sunt asignate, unitar, variabilei referinta. Instantele individuale ale
unei clase sunt independente intre ele si reprezinta constructii programatice separate.
In principiu, nu exista o limita a numarului de copii (instante) ale unei aceleasi clase la
un moment dat. Prin analogie cu lumea reala, daca un computer reprezinta un obiect,
atunci datele tehnice de fabricatie ar putea reprezenta sablonul (clasa), pornind de la
care se pot fabrica un numar practic nelimitat de computere. O modificare adusa unui
astfel de obiect nu afecteaza in vreun fel celelalte obiecte.
Obiecte si membri
Obiectele sunt compuse din membri. Membrii pot fi: proprietati, campuri, metode si
Dezvoltare de aplicatii in Visual Studio .NET

Page 61 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

evenimente, reprezentand datele si functionalitatea care compun obiectul. Campurile si


proprietatile reprezinta datele membre ale unui obiect. Metodele reprezinta actiuni care
pot fi executate de obiect, iar evenimentele sunt notificari pe care un obiect le poate
trimite sau primi la (de la) alte obiecte in urma unor actiuni din cadrul aplicatiei.
Pentru a continua exemplul din lumea reala legat de un obiect de tip Computer, putem
considera ca un obiect Computer are campuri si proprietati, cum ar fi Frecventa, Firma,
Tip etc. Acestea sunt date care descriu starea obiectului. Un astfel de obiect poate
avea mai multe metode, cum ar fi Restart, StandBy sau Shutdown. Aceste metode
determina comportamentului obiectului, reprezentand actiuni care pot fi executate.
Evenimentele reprezinta notificari. De exemplu, un Computer poate primi un eveniment
ExtraHeating din partea procesorului sau un eveniment StartShutDown atunci cand se
apasa butonul de shutdown.
Modelarea obiectelor
Obiectele simple pot contine numai cateva proprietati, metode si, eventual, unul sau
doua evenimente. Obiectele mai complexe pot necesita un numar mare de proprietati
si metode si pot, chiar, ingloba alte obiecte. Obiectele pot contine si expune alte
obiecte ca membri. De exemplu, un control TextBox are o proprietate Font care consta
intr-un obiect de tip Font. Similar, orice instanta a clasei Form contine si gestioneaza o
colectie Controls care include toate controalele de pe forma. Modelul unui obiect
defineste ierarhia obiectelor care formeaza structura obiectului modelat.
Modelul unui obiect este o organizare ierarhica a obiectelor subordonate continute de
un obiect parinte.
Incapsulare
Incapsularea este conceptul prin care implementarea unui obiect este independenta de
interfata sa. Cu alte cuvinte, o aplicatie interactioneaza cu un obiect prin intermediul
interfetei sale, care consta in metodele si proprietatile sale publice. Cat timp aceasta
interfata ramane neschimbata, applicatia poate continua interactiunea cu respectiva
componenta, chiar daca implementarea interfetei a fost complet rescrisa de la o
versiune la alta.
Obiectele ar trebui sa interactioneze cu alte obiecte prin intermediul metodelor si
proprietatilor publice. Deci, obiectele trebuie sa contina toate datele necesare, precum
si functionalitatea completa necesara manipularii acestor date. Datele interne ale unui
obiect nu trebuie expuse in interfata; deci, campurile nu trebuie declarate public.
Polimorfism
Polimorfismul reprezinta abilitatea unor clase diferite de a efectua implementari diferite
ale aceleeasi interfete publice. Cu alte cuvinte, polimorfismul permite metodelor si
proprietatilor unui obiect sa fie apelate fara a se tine cont de o implementare particulara
a acelor membri. De exemplu, un obiect User poate interactiona cu un obiect Computer
prin intermediul interfetei publice a obiectului Computer. Daca un alt obiect, cum ar fi
ServerStation, expune aceeasi interfata publica, obiectul User poate interactiona cu
ambele obiecte, fara a fi importanta implementarea specifica a interfetei. Exista doua
tipuri importante de polimorfism: polimorfism bazat pe interfete si polimorfism bazat pe
mostenire.
Page 62 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Polimorfism bazat pe interfete


O interfata este o structura comportamentala a unei clase. In principal, o interfata
defineste membrii pe care o clasa ar trebui sa-i implementeze, dar nu specifica detalii
referitoare la aceasta implementare. Un obiect poate implementa mai multe interfete
diferite, si mai multe clase diferite pot implementa aceeasi interfata. Toate obiectele
care implementeaza aceeasi interfata sunt capabile sa interactioneza cu alte obiecte
prin intermediul acestei interfete. De exemplu, un obiect WorkStation poate implementa
o interfata ICalculation, care specifica metodele BeginCalculation, ContinueCalculation
si StopCalculation. Alte clase, cum ar fi Pda sau Laptop pot implementa aceeasi
interfata, fiind, deci, capabile sa interactioneza cu un obiect User. Obiectul de tip User
nu stie cu care dintre implementarile interfetei interactioneaza; el foloseste pur si
simplu interfata.
Polimorfism bazat pe mostenire
Mostenirea permite incorporarea functionalitatii unor clase definite anterior intr-o noua
clasa si implementarea unor alti membri. Despre o clasa care mosteneste o alta clasa
spunem ca este derivata din acea clasa, sau mosteneste clasa respectiva. O clasa
poate fi derivata direct dintr-o singura clasa, numita clasa de baza. Clasa derivata are
aceeasi membri ca si clasa de baza, adaugandu-se eventuali membri aditionali. In
plus, implementarea membrilor de baza poate fi modificata in noua clasa
supraincarcand implementarea clasei de baza. Clasele derivate retin toate
caracteristicile clasei de baza si pot interactiona cu alte obiecte in aceeasi maniera cu
obiectele de tipul clasei de baza.
Sinteza
Abstractizarea este reprezentarea obiectelor din lumea reala prin constructii
programatice. Obiectele programatice pot reprezenta obiecte din lumea reala prin
implementari ale membrilor lor.
Clasele sunt sabloane pentru obiecte. La crearea unui obiect, se creaza o copie a
clasei in memorie, fiind initializate valorile variabilelor membre. O clasa se poate
comporta ca un numar, teoretic nelimitat, de obiecte distincte.
Incapsularea este un principiu al programarii orientate obiect. Un obiect ar trebui sa
contina toate datele de care are nevoie si tot codul necesar manipularii acestor date.
Datele specifice unui obiect nu trebuie sa fie disponibile altor obiecte. Numai
proprietatile si metodele ar trebui expuse in interfata.
Polimorfismul reprezinta abilitatea unor obiecte diferite de a expune implementari
diferite ale aceleasi interfete publice.
Polimorfism bazat pe interfete
O interfata defineste trasaturile comportamentale ale unei clase. Ea specifica care
dintre membri trebuie implementati, dar nu specifica detalii legate de implementarea
acestora. Un obiect poate implementa mai multe interfete diferite, si mai multe obiecte
diferite pot implementa aceeasi interfata.
Polimorfism bazat pe mostenire
Obiectele pot mosteni functionalitati de la alte obiecte. O clasa derivata retine toata
Dezvoltare de aplicatii in Visual Studio .NET

Page 63 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

implementarea clasei de baza, iar instantele claselor derivate pot fi tratate ca instante
ale clasei de baza. Clasele derivate pot implementa functionalitati aditionale.

2. Overloading
Supraincarcarea (overloading) permite crearea mai multor membri ai unei clase avand
acelasi nume. Fiecare astfel de membru trebuie sa aiba o signatura diferita.
Supraincarcarea este cel mai frecvent folosita pentru metode, dar C# permite si
supraincarcarea operatorilor.
Sa consideram situatia crearii unei metode care poate avea diversi parametri. Sa
consideram urmatorul exemplu:
public void Afisare(int valoare)
{
// Implementare...
}
Sa presupunem ca utilizatorul doreste modificarea numarului si/sau tipurilor
parametrilor. Solutia acestei probleme este data de supraincarcare. Acesta implica
definirea mai multor functii cu acelasi nume. Metodele supraincarcate trebuie sa aiba
acelasi nume, dar acest lucru nu se respecta pentru tipul returnat sau pentru
modificatorii de acces asociati. La apelul unei metode supraincarcate, common
language runtime examineaza tipurile argumentelor transmise la apelul metodei. Se
cauta apoi o potrivire a listei argumentelor printre signaturile metodei supraincarcate si
se face apelul corespunzator. Daca nu se gaseste o astfel de potrivire, se genereaza o
eroare.
Metodele sunt membrii cel mai frecvent folositi pentru supraincarcare. C# permite
supraincarcarea operatorilor, oferind astfel functionalitati ale operatorilor pentru tipurile
definite de utilizator.
Supraincarcarea metodelor
Se poate crea o metoda supraincarcate similar crearii unei metode oarecare: prin
declararea unei metode cu un nume, un nivel de acces, returnand un anumit tip si
specificand o lista de argumente. O metoda supraincarcata trebuie sa aiba acelasi
nume ca si o alta metoda existent, dar trebuie sa aiba o signatura diferita. Nivelul de
acces si tipul returnat pot fi identice sau diferite.
Exemplu:
// metoda supraincarcata
public void Afisare(int i)
{
MessageBox.Show(i.ToString());
Page 64 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

}
// metoda cu acelasi nume, dar signatura diferita
public void afisare(string s)
{
MessageBox.Show(s);
}
Supraincarcarea operatorilor in C#
In aplicatii care utilizeaza tipuri definite de utilizator, se impune frecvent necesitatea
definirii unui set de operatii aritmetice, logice sau a unor operatori de comparare care
utilizeaza aceste tipuri de date. Exemplu:
public struct PrezenteLab
{
int nrPrez;
int nrPrezExtra;
}
Acesta structura poate fi utilizata pentru a gestiona evidenta situatiei prezentelor la un
laborator de informatica. Pentru o utilizare facila si eficienta, apare necesitatea
supraincarcarii operatorilor.
Sintaxa generala a supraincarcarii unui operator este urmatoarea:
public static tip operator op (argument1[, argument2])
{
//implementare...
}
Componenta tip din cadrul sintaxei reprezinta tipul returnat de operator. argument1,
argument2 etc. reprezinta argumentele asociate operatorului. Pentru un operator unar,
vom avea un singur argument, si trebuie sa aiba acelasi tip ca tipul returnat. Pentru un
operator binar, vom avea doua argumente, dintre care cel putin unul trebuie sa aiba
acelasi tip ca tipul retunat. op reprezinta insusi operatorul, de exemplu +, -, >, !=, si asa
mai departe. Un operator supraincarcat trebuie sa fie public, pentru a putea fi accesat.
Un operator supraincarcat trebuie sa fie, de asemenea, static. Definitia unui operator
supraincarcat trebuie sa apara in cadrul definitiei tipului asupra caruia i se aplica
operatorul. Sintaxa supraincarcarii operatorilor este similara pentru structuri si clase.
Exemplu: supraincarcarea operatorului + pentru structura definita anterior.
public struct PrezenteLab
{
int nrPrez;
Dezvoltare de aplicatii in Visual Studio .NET

Page 65 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

int nrPrezExtra;
// supraincarcarea operatorului +
public static PrezenteLab operator + (PrezenteLab a,
PrezenteLab b)
{
PrezenteLab rezultat = new PrezenteLab();
rezultat.nrPrez = a.nrPrez + b.nrPrez;
rezultat.nrPrezExtra = a.nrPrezExtra + b.nrPrezExtra;
return rezultat;
}
}
Utilizarea operatorului supraincarcat in cod:
// Saptamana2, Saptamana3 sunt instante
// ale structurii PrezenteLab
PrezenteLab total = new PrezenteLab();
total = Saptamana2 + Saptamana3;
Pornind de la ideea generala de supraincarcare, putem defini mai multe signaturi
pentru a suprincarca un acelasi operator. Exemplu:
public struct PrezenteLab
{
int nrPrez;
int nrPrezExtra;
// operatorul + supraincarcat anterior
public static PrezenteLab operator + (PrezenteLab a,
PrezenteLab b)
{
PrezenteLab rezultat = new PrezenteLab();
rezultat.nrPrez = a.nrPrez + b.nrPrez;
rezultat.nrPrezExtra = a.nrPrezExtra + b.nrPrezExtra;
return rezultat;
}
// supraincarcare aditionala (o alta signatura,
// o alta functionalitate)
Page 66 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

public static PrezenteLab operator + (PrezenteLab a, int b)


{
PrezenteLab rezultat = new PrezenteLab();
rezultat.nrPrez = a.nrPrez + b;
return rezultat;
}
}
Sinteza
- Supraincarcarea permite crearea de metode multiple avand acelasi nume, insa cu
implementari diferite. Metodele supraincarcate trebuie sa difere prin signatura dar pot
returna acelasi tip de date sau pot avea aceeasi modificatori de acces asociati.
Declararea unei metode supraincarcate este similara definirii oricarei alte metode.
- C# permite supraincarcarea operatorilor. Operatori supraincarcati trebuie sa fie publici
si statici. Pentru a declara un operator supraincarcat se utlizeaza cuvantul rezervat
operator.

3. Polimorfism
Polimorfism bazat pe interfete
Interfetele permit definirea comportamentelor obiectelor. Clase diferite pot implementa
aceeasi interfata si pot, deci, interactiona cu alte obiecte intr-o maniera polimorfica.
O interfata actioneaza ca un sablon. Orice obiect care implementeaza o anumita
interfata garanteaza implementarea membrilor definiti in acea interfata. Daca un obiect
necesita interactiune cu o interfata specifica, orice obiect care implementeaza interfata
poate raspunde acestei interactiuni.
O interfata defineste numai membrii care vor deveni disponibili prin implementarea unui
obiect. Definitia unei interfete nu implica aspecte legate de implementarea membrilor,
specificandu-se, in schimb, lista parametrilor si tipul returnat. Sarcina implementarii
unei interfete revine, in totalitate, clasei care utilizeaza interfata.
Ca urmare, este posibila, pentru obiecte diferite, scrierea de implementari total diferite
ale acelorasi membri. Sa consideram, de exemplu, o interfata IForma, care defineste o
metoda CalculArie. O clasa Cerc care implementeaza aceasta interfata va calcula aria
intr-un mod diferit fata de o clasa Patrat care implementeaza aceeasi interfata.
Definirea interfetelor
Interfetele se definesc folosind cuvantul rezervat interface. De exemplu:

Dezvoltare de aplicatii in Visual Studio .NET

Page 67 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

public interface ICalculate


{
...
}
Acesta declaratie defineste interfata ICalculate, dar nu defineste nici un membru.
Metodele membre trebuie definite specificand signatura, dar fara modificatori de acces.
Modificatorul de acces asociat interfetei determina modificatorul de acces al fiecarui
membru al interfetei. Deci, in cadrul unei interfete publice, toti membrii vor fi publici.
Exemplul urmator demonstreaza cum se pot adauga metode unei interfete:
public interface ICalculate
{
bool CheckInput(int input);
void StartCalculation();
int GetResult();
}
O interfata poate contine definitii de proprietati. Definitia unei proprietati trebuie sa
includa getter-i, setter-i, sau ambele, precum si specificarea tipului returnat de
proprietate. Exemplu:
public interface ICalculate
{
// alti membri...
string CalcType
{
get;
// eventual, urmeaza set...
}
}
!
In cadrul interfetelor nu se pot defini campuri! Aceasta restrictie blocheaza accesul
claselor care interactioneaza cu interfata la datele interne ale unui obiect.
Interfetele pot defini evenimente. Evenimentele definite in cadrul interfetelor reprezinta
evenimente lansate de obiecte care implementeaza interfata. Desi orice clasa care
implementeaza o interfata trebuie sa furnizeze o implementare pentru toate
evenimentele membre, obiectele care interactioneaza prin intermediul acestei interfete
nu sunt obligate sa trateze evenimentele lansate. In C#, trebuie desemnat explicit tipul
delegatului asociat evenimentului. Exemplu de definire a unui eveniment membru al

Page 68 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

unei interfete:
public interface ICalculate
{
// alti membri...
event System.EventHandler OutOfMemory;
}
Definirea unei interfete
Se declara interfata folosind cuvantul rezervat interface. In cadrul definitiei interfetei, se
definesc signaturile metodelor, proprietatilor si evenimentelor membre ale interetei.
Polimorfism bazat pe interfete
Orice obiect care implementeaza o anumita interfata poate interactiona cu un alt obiect
care solicita acea interfata. Sa consideram, drept exemplu, urmatoarea metoda:
public void CalculateSomething(ICalculate ic)
{
// implementare...
}
Aceasta metoda necesita o implementare a interfetei ICalculate. Orice obiect care
implementeaza aceasta interfata poate fi transmis ca parametru acestei metode.
Obiectul va fi implicit convertit la interfata corespunzatoare. Cand un obiect
interactioneaza prin intermediul interfetei sale, numai membrii interfetei sunt accesibili.
Se poate executa, de asemenea, o conversie explicita a obiectelor care
implementeaza interfete specifice. Exemplu - conversia unui obiect WorkStation la
interfata ICalculate (obiectul ws trebuie sa implementeze ICalculate):
WorkStation ws = new WorkStation();
ICalculate calculateTool;
// converteste ws la interfata ICalculate
calculateTool = (ICalculate)ws;
Implementarea interfetelor
In C#, se utilizeaza caracterul : pentru a specifica o clasa sau o structura care
implementeaza o anumita interfata. Urmatorul exemplu indica faptul ca o clasa
implemeneaza o anumita interfata:
public class WorkStation : ICalculate
{
// cod aditional...

Dezvoltare de aplicatii in Visual Studio .NET

Page 69 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
Clasele pot implementa mai multe interfete. Exemplu:
public class WorkStation : ICalculate, IMovieViewer,
IInternetExplorer
{
// cod aditional....
}
Atunci cand o clasa sau o structura implementeaza o interfata, trebuie scrise
implementari separate pentru fiecare membru al interfetei. Daca se implementeaza mai
multe interfete, trebuie furnizate implementari pentru fiecare membru al fiecarei
interfete.
Implementarea membrilor interfetelor in C#
In C#, implementarea unui membru al interfetei in cadrul clasei sau structurii se
realizarea prin definirea unui membru care are acelasi nume cu membrul definit in
cadrul interfetei. Acest membru trebuie sa aiba acelasi modificator de acces ca in
cadrul interfetei. Exemplu:
public interface ICalculate
{
void BeginCalculation(int input);
}
public class WorkStation : ICalculate
{
public void BeginCalculation(int i)
{
// implementare...
}
}
In cazul unei astfel de implementari a membrilor unei interfete, ei sunt disponibili atat
interfetei, cat si clasei insesi. Deci, acesti membri pot fi accesati daca obiectul este
convertit la propria sa clasa sau la interfata implementata.
Este, de asemenea, posibila implementarea explicita a interfetei si blocarea accesului
la membrii sai pentru clasa care implementeaza interfata. Un membru astfel
implementat poate fi accesat numai cand obiectul parinte este convertit la interfata pe
care o implementeaza (si care contine membrul respectiv). Implementarea explicita a
unui membru al unei interfete se realizeaza prin specificarea completa a numelui
interfetei si a membrului. Exemplu:

Page 70 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

public class WorkStation : ICalculate


{
void ICalculate.Begin Calculation(int input)
{
// implementare...
}
}
!
Membrul definit explicit din exemplul anterior nu are modificator de acces asociat.
Deoarece s-a efectuat o implementare explicita a unui membru al interfetei, acesta va
avea acelasi nivel de acces ca si membrul definit de interfata.
Sinteza
O interfata descrie comportamentul obiectelor. Ele definesc membrii care vor fi
accesibili prin intermediul interfetei, si parametrii si tipul returnat de acesti membri.
Orice obiect care implementeaza o interfata poate interactiona cu orice obiect care
solicita interfata respectiva. Atat clasele, cat si structurile pot implementa una sau mai
multe interfete.
Implementarea membrilor unei interfete este realizata de clasele sau structurile care
implementeaza interfata.
In C#, pentru a specifica faptul ca o clasa sau structura implementeaza o interfata, se
utilizeaza : (doua puncte). Daca o clasa sau structura implementeaza o interfata,
aceasta trebuie sa implementeze fiecare membru definit in cadrul interfetei.
In C#, exista doua modalitati de a implementa membrii unei interfete:
- implementand un membru cu acelasi nume, signatura, si nivel de access ca si
membrul definit in interfata. Acest membru va fi disponibil atat clasei care il
implementeaza, cat si interfetei.
- implementand explicit membrul interfetei, utilizand calificarea completa a numelui
membrului. Un membru implementat in aceasta maniera va fi disponibil numai interfetei
din care face parte.

Polimorfism bazat pe mostenire


Mostenirea (derivarea) permite declararea unei noi clase care retine toti membrii si
functionalitatea unei clase definite anterior. Aceast mecanism permite crearea de clase
care implementeaza functionalitati comune, de baza si apoi scrierea de subclase
specializate care introduc functiuni diferite, dar strans legate de cele ale clasei de baza.

Dezvoltare de aplicatii in Visual Studio .NET

Page 71 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Mostenirea
Mostenirea permite crearea mai multor clase distincte, dar care au in comun o anumita
functionalitate. Clasele specializate, denumite clase derivate, mostenesc o clasa
comuna, numita clasa de baza. Clasa de baza incapsuleaza functionalitatea comuna
care va fi prezenta in fiecare clasa derivata, in timp ce clasele derivate implementeaza
functionalitati specifice. De exemplu, sa consideram o clasa Laptop. Aceasta clasa
implementeza toata functionalitatea specifica unei clase Computer. In plus ea poate
implementa diverse metode specifice, cu ar fi StandByMode, apelata, de exemplu, la
inchiderea capacului laptop-ului.
Comportamente polimorfice in clasele derivate
Clasele derivate sunt, in general, intr-o relatie de tipul is-a fata de clasa de baza. De
exemplu, un Laptop este un (is-a ) Computer, iar un Computer este un Dispositif. Orice
instanta a unei clase derivate se poate comporta polimorfic ca o instanta a clasei de
baza. Deci, daca o metoda necesita un parametru de tip Computer, i se poate furniza
in schimb un obiect Laptop. Orice clasa derivata poate fi convertita implicit la clasa sa
de baza. In momentul conversiei catre clasa de baza, fiecare membru implementat de
clasa derivata va deveni inaccesibil; numai membrii clasei de baza vor fi disponibili.
Crearea claselor derivate
Se utilizeaza : (doua puncte). Exemplu:
public class Laptop : Computer
{
// implementare...
}
Clasele pot mosteni o singura clasa de baza, dar pot implementa una sau mai multe
interfete. Daca o clasa implementeaza mai multe interfete, odata cu derivarea dintr-o
clasa de baza, numele interfetelor trebuie enumerate dupa : (doua puncte), despartite
prin virgula. De exemplu:
public class Laptop : Computer,
ICalculate, IFileManager
{
// implementare...
}
Odata ce o clasa derivata a fost declarata, se pot implementa membrii aditionali pentru
a adauga functionalitati specifice clasei.
Crearea de clase care nu pot fi derivate
Uneori, este necesara definirea unor clase care nu vor putea fi mostenite. De exemplu,
o clasa specializata care va fi utilizata pentru scrierea unor componente si nu va fi utila
altor programatori, se defineste in asa fel incat sa nu poate fi mostenita. In C#, pentru a
realiza acest lucru, se utilizeaza cuvantul rezervat sealed:
Page 72 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

public sealed class ClassNotInheritable


{
// implementare...
}
Membri mosteniti
La crearea unei clase derivate, noua clasa poseda toata functionalitatea implementata
in clasa de baza. Pe langa adaugarea de noi membri, se poate modifica si
implementarea membrilor mosteniti, pentru anumite scopuri. Suprascrierea (overriding)
membrilor din clasa de baza se realizeaza printr-o noua implementare a unui membru
existent, implementat in clasa de baza. C# permite ascunderea membrilor clasei de
baza, prin implementarea unui nou membru, in clasa derivata, cu acelasi nume si
signatura, dar avand diverse alte caracteristici.
Suprascrierea membrilor din clasa de baza
La derivarea dintr-o clasa de baza, se poate furniza o implementare diferita pentru
membrii clasei de baza prin suprascrierea lor folosind o noua implementare in clasa
derivata a unui membru cu acelasi nume. De exemplu, o clasa Computer are o metoda
Hibernate. Daca derivam o clasa Laptop din clasa Computer, se poate furniza o
implementare diferita pentru metoda Hibernate.
!
Pot fi suprascrise numai proprietatile si metodele din cadrul unei clase de baza.
Variabilele si evenimentele membre nu pot fi suprascrise.
Pentru a declara o noua implementare a unui membru dintr-o clasa intr-o clasa
derivata, se utilizeaza cuvantul rezervat override. Noua implementare trebuie sa aiba o
signatura si tip returnat identice cu cele ale membrului suprascris, si trebuie sa aiba
asociat acelasi nivel de acces. De exemplu:
// Calculate este o metoda a clasei Computer
public class Laptop : Computer
{
public override void Calculate(int input)
{
// implementare....
}
}
La suprascrierea unui membru, noul membru va fi apelat in locul membrului din clasa
de baza. Aceasta afirmatie este dependenta de contextul in care este apelat un
membru. De exemplu, daca o instanta a unei clase derivate este convertita la clasa sa
de baza si este apelata o metoda membra suprascrisa, se va executa noua
implementare, desi variabila este de tipul clasei de baza. Tipul obiectului, si nu
variabila, determina care membru va fi apelat.
Dezvoltare de aplicatii in Visual Studio .NET

Page 73 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Pentru a suprascrie un membru al unei clase de baza, acesta trebuie declarat virtual.
Membrii non-virtuali sunt nu pot fi suprascrisi. Exemplu de declarare a unei metode
virtuale:
public virtual void OverridableMethod()
{
// implementare...
}
Ascunderea membrilor clasei de baza
Un membru al clasei de baza poate fi ascuns prin inlocuirea sa cu o implementare
complet noua. Mecanismul este cunoscut sub numele de ascundere (hiding). La
ascunderea unui membru, se inlocuieste implementarea din clasa de baza cu o noua
implementare. Noua implementare trebuie sa aiba aceeasi signatura ca a membrului
ascuns si trebuie sa fie asociata unui membru de acelasi tip, dar poate avea nivel de
acces, tip returnat diferite, si o implementare complet diferita. Orice metoda care are
acelasi nume ca o metoda existenta, dar o signatura diferita, este tratata ca o
supraincarcare a metodei initiale si nu se va realiza ascunderea. Pentru a ascunde un
membru al unei clase de baza se defineste un membru in clasa de baza avand aceeasi
signatura si folosind cuvantul rezervat new:
// clasa de baza
public class ClasaDeBaza
{
public string metoda(int i)
{
// implementare...
}
}
// clasa derivata
public class ClasaDerivata : ClasaDeBaza
{
// ascunderea metodei din clasa de baza
// signatura identica, insa nivel de acces diferit,
// tip returnat diferit
internal new int metoda(int i)
{
// implementare...
}

Page 74 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

}
Mentinerea compatibilitatii cu membrii ascunsi
La ascunderea unui membru al unei clase, se ascunde implementarea din clasa de
baza si se creaza o noua implementare care nu trebuie sa aiba caracteristicile
implementarii membrului din clasa de baza. Acest aspect poate conduce la implicatii
nedorite in ceea ce priveste interoperarea cu alte obiecte. Daca un obiect apeleaza
metoda din exemplul anterior, in ideea de a obtine un String, la returnarea unui int, de
catre metoda care ascunde metoda initiala, se poate genera o eroare. Ascunderea
membrilor trebuie facuta deci cu atentie.
Desi ascunsa, implementarea membrilor din clasa de baza poate fi accesibila sub
anumite circumstante. Aceasta depinde de clasa, si nu de tipul obiectului, ca in cazul
membrilor suprascrisi. De exemplu, sa consideram urmatorul fragment de cod:
// folosim clasele din exemplul anterior
ClasaDerivata X = new ClasaDerivata();
ClasaDeBaza Y;
// X si Y refera acelasi obiect, dar
// variabilele au tipuri diferite
Y = X;
// se apeleaza noul membru
X.metoda(23);
// se apeleaza metoda originala
Y.metoda(23);
Deci, tipul variabilei determina daca se va apela membrul din clasa derivata sau
membrul original (ascuns). Ca urmare, se poate modifica implementarea unui membru
fara a se distruge abilitatea unei clase de a se comporta polimorfic.
Accesarea membrilor clasei de baza
La suprascrierea sau ascunderea unor membri, poate aparea necesitatea accesarii
implementarii acestor astfel de membri din clasa de baza. Pentru aceasta, se utilizeaza
cuvantul rezervat base. Se face astfel o referinta la implementarea clasei de baza si se
permite invocarea membrilor implementati in clasa de baza. Exemplu:
// apelul unei metode din clasa de baza
// dintr-o metoda care suprascrie metoda respectiva
public override string metoda(int i)
{
base.metoda(i);
// implementare...

Dezvoltare de aplicatii in Visual Studio .NET

Page 75 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
Membri protected
membri public - accesibili din orice sectiune a aplicatiei, incluzand clase externe
membri internal - accesibili membrilor assembly-ului local, dar nu si apelantilor
externi
membri private - disponibili numai in interiorul clasei
membri protected si protected internal - discutati in cele ce urmeaza
Un membru definit protected are aceeasi vizibilitate fata de apelantii externi ca si
membrii private. Diferenta consta in faptul ca membrii protected pot fi accesati din
clasele derivate. Exemplu:
// o metoda private si o metoda protected
// in clasa de baza
public class BaseClass
{
// o metoda private nu poate fi apelata
// din clase derivate
private void private_method()
{
// implementare....
}
// un membru protected poate fi
// apelat din clase derivate
protected void protected_method()
{
// implementare...
}
}
// clasa derivata
public class InheritedClass : BaseClass
{
public void Demo()
{
// apel legal, metoda protected
this.protected_method();
Page 76 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

// apel nepermis, metoda private


this.private_method();
}
}
Membri protected internal
Acest modificator de acces este reuniunea modificatorilor de acces protected si
internal. Deci, un membru protected internal poate fi accesat de clasele din assembly
sau de clasele care mostenesc clasa care contine membrul, desigur, pe langa
posibilitatea accesarii membrului din interiorul clasei care il contine.
Clase si membri abstracti
La crearea de componente, poate surveni situatia crearii unei clase de baza care
furnizeaza o functionalitate invarianta dar lasa in seama claselor derivate
implementarea anumitor membri. Acest aspect este surprins cu ajutorul claselor
abstracte, clase care trebuie mostenite.
Clasele abstracte sunt similare interfetelor, dar au multe caracteristici in comun cu
clasele. O clasa abstracta nu poate fi instantiata; trebuie mai intai mostenita. Clasele
abstracte pot furniza sau nu implementari ale unei clase. Precum interfetele, pot
specifica membri care tebuie implementati in clasele derivate. Spre deosebire de
interfete, o clasa poate mosteni numai o clasa abstracta. Similar claselor uzuale,
clasele abstracte pot implementa complet anumiti membri, dar pot specifica membri
care trebuie implementati in clasele derivate.
Crearea claselor abstracte
O clasa se defineste ca fiind abstracta prin utilizarea cuvantului rezervat abstract. De
exemplu:
public abstract class AbstractClass
{
// implementare...
}
Membri abstracti
O clasa abstracta poate implementa orice membru. Membrii unei clase virtuale pot fi
declarati virtual, caz in care clasele derivate pot crea implementari proprii ale
membrilor, sau pot fi declarati non-virtual, avand deci o implementare fixa, comuna in
clasele derivate.
Un membru abstract este similar unui membru al unei interfete. Se specifica numai
tipul, nivelul de acces, parametrii si tipul returnat. Implementarea este sarcina clasei
derivate.
Membrii abstracti se declara in clase abstracte. Declararea unui membru abstract intr-o
clasa non-abstracta conduce la eroare.
Dezvoltare de aplicatii in Visual Studio .NET

Page 77 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

public abstract class Computer


{
public abstract void Calculate(int);
public abstract int GetResult();
public abstract string Info
{
get;
set;
}
}
!
In C#, trebuie specificati un getter si/sau un setter pentru o proprietate abstracta. Daca
sunt specificate ambele, atunci trebuie implementate impreuna in clasa derivata.
Mostenirea unei clase abstracte
Clasa derivata dintr-o clasa abstracta trebuie sa implementeze fiecare membru
abstract definit in clasa abstracta de baza. Implementarea se realizeaza prin
macanismul suprascrierii, la fel ca in cazul claselor uzuale. Exemplu (bazat pe
exemplul anterior):
public class MyComp : Computer
{
public override void Calculate(int input)
{
// implementare...
}
public override int GetResult()
{
// implementare...
}
public override string Info
{
get
{
// implementare obligatorie a
// getter-ului si a setter-ului
Page 78 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

}
set
{
// implementarea setter-ului
}
}
}
!
Se pot crea noi clase abstracte prin derivarea din alte clase abstracte. In acest caz,
clasa abstracta derivata nu trebuie sa implementeze membrii abstracti definiti in clasa
de baza (acest lucru este, insa, permis).
Sinteza - cuvinte cheie

mostenire (derivare)
supraincarcare (overriding)
ascundere (hiding)
base
protected, protected internal
virtual
abstract

Dezvoltare de aplicatii in Visual Studio .NET

Page 79 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 6. Testarea si debugging-ul aplicatiilor - V


1. Unelte de debugging
Erorile de programare sunt inevitabile. Chiar si programatorii cu experienta mare in
domeniu comit frecvent erori (bug-uri) la scrierea de cod. Debugging-ul este procesul
localizarii si corectarii erorilor.
Tipuri de erori
Exista trei tipuri de erori care pot surveni pe durata de viata a unei aplicatii. Erorile de
sintaxa sunt determinate de scrierea de cod care nu poate fi inteles de catre
compilator. Erorile de tip run-time sunt erorile care au loc atunci cand se efectueaza o
operatie imposibil de tratat in context. Erorile logice sunt erorile care rezulta atunci
cand programul se compileaza si se executa corect, dar returneaza un rezultat
neasteptat.
Erori de sintaxa
O eroare de sintaxa are loc atunci cand compilatorul nu poate compila codul scris. De
exemplu, o eroare de sintaxa apare atunci cand cuvintele cheie sunt scrise incorect,
cand lipsesc semne de punctuatie sau cand entitatile din program nu sunt bine
structurate.
Exemplu:
public void EroareDeSintaxa() {
System.Windows.Forms.MessageBoxShow("Care este eroarea?");
Mai intai, lipsa unui punct intre MessageBox si Show creaza o comanda care nu poate
fi inteleasa de compilator. Apoi, constructia prin care se specifica sfarsitul functiei
lipseste (acolada inchisa). Ambele erori vor crea o conditie pe care compilatorul nu o
poate interpreta.
Erorile de sintaxa pot fi usor identificate odata cu scrierea codului (colorarea adecvata
a portiunilor de cod). Erorile detectate vor aparea, de asemenea, in fereastra Task List,
odata cu prima compilare efectuata.
Executand dublu clic pe o eroare din fereastra Task List, cursorul se va pozitiona pe
linia de cod care a generat eroare. Frecvent, aceasta actiune furnizeaza suficiente
informatii pentru a corecta eroarea. Pentru mai multe informatii se tasteaza F1 pe codul
de eroare selectat.
Erori la executie (run-time)
Erorile la executie apar in momentul in care aplicatia incearca sa efectueaze o operatie
nepermisa in context. Aceasta include operatii imposibil de tratat, cum ar fi impartirea
la zero, si operatii nepermise, ca in cazul exceptiilor legate de securitate. La aparitia
unei astfel de erori, se arunca o exceptie care descrie eroarea. Exceptiile sunt clase
Page 80 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

speciale care sunt utilizate pentru a comunica starile de eroare ale diferitelor sectiuni
ale aplicatiei. Se poate scrie cod care sa trateze exceptiile, astfel incat acestea sa nu
stopeze executia aplicatiei.
Erori logice
Erorile logice apar atunci cand aplicatia este compilata si executata corect, dar nu se
obtin rezultatele scontate. Acestea pot fi considerate eroriele cel mai dificil de tratat,
pentru ca, adesea, nu exista informatii aditionale care sa indice sursa erorii. Erori
logice pot surveni, de exemplu, din plasarea inadecvata a punctului zecimal. De
exemplu:
public float CalculNota(int punctajLab, int punctajExamen)
{
float nota;
nota = punctajLab * 0.3 + punctajExamen * 0.07;
return nota;
}
Modul break
Modul break permite intreruperea executiei programului si executia codului linie cu
linie. In mod break, se pot utiliza uneltele de debugging pentru a examina valorile
variabilelor si proprietatile aplicatiei. In Visual Studio .NET, se intra in mod Break sub
una din urmatoarele circumstante:

s-a selectat Step Into, Step Over sau Step Out din meniul Debug sau din toolbar.
executia programului avanseaza la o linie care contine un breakpoint activ.
se intalneste un Stop
se arunca o exceptie netratata

Elementele meniului Debug


Optiune

Descriere

Windows

Deschide un submenu de ferestre de debugging.

Start/Continue F5

Se ruleaza aplicatia in mod Debug. Daca aplicatia este in


mod Break, se continua executia programului.

Break All
Ctrl+Alt+Break

Se intrerupe executia programului si se intra in mod Break


la linia curenta din program. Se poate folosi Continue pentru
a continua executia.

Stop Debugging
Shift+F5

Se opreste modul Debug si se intra in mod Design.

Detach All

Se stopeaza toate procesele in care era implicat


debugger-ul. Acesta este inchis, insa nu se intrerupe
executia programului.

Dezvoltare de aplicatii in Visual Studio .NET

Page 81 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Restart
Ctrl+Shift+F5

Se finalizeaza si se restarteaza executia aplicatiei.

Apply Code
Changes

Optiune specifica programarii C/C++.

Processes

Vizualizeaza fereastra Processes.

Exceptions
Ctrl+Alt+E

Vizualizeaza fereastra Exceptions.

Step Into F11

Se executa urmatoarea linie de cod. Daca aceasta contine


apelul unei metode, Step Into se opreste la inceputul acelei
metode.

Step Over F10

Se executa urmatoarea linie de cod. Daca aceasta contine


apelul unei metode, Step Over executa metoda si se
opreste la linia urmatoare a metodei curente.

Step Out
Shift+F11

Executa liniile ramase din metoda curenta si se opreste la


urmatoarea linie executabila de cod din metoda apelanta.

QuickWatch
Ctrl+Alt+Q

Afiseaza fereastra QuickWatch.

New Breakpoint
Ctrl+B

Afiseaza fereastra New Breakpoint.

Clear All
Breakpoints
Ctrl+Shift+F9

Elimina toate breakpoint-urile din aplicatie.

Disable All
Breakpoints

Dezactiveaza toate breakpoint-urile, fara a le elimina


efectiv.

Mai mult, anumite functii de debugging pot fi accesate prin clic dreapta pe un element
din fereastra de cod si alegand o functie meniul pop-up respectiv. Tabelul urmator
sintetizeaza o parte din aceste functii.

Tabel: functii de debugging accesibile din meniuri pop-up accesibile din cadrul ferestrei
de cod.

Optiune

Descriere

Insert Breakpoint

Insereaza un breakpoint la linia selectata.

New Breakpoint

Afiseaza fereastra New Breakpoint. Acest element este


identic cu optiunea cu acelasi nume din meniul Debug.

Add Watch

Adauga expresia specificata in fereastra Watch.

QuickWatch

Afiseza fereastra QuickWatch. Identica cu optiunea cu


acelasi nume din meniul Debug.

Show Next
Statement

Indica urmatorul bloc de program care se va executa.

Page 82 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Run To Cursor

Deplaseaza executia programului la linia selectata.

Set Next
Statement

Desemneaza linia selectata drept urmatoarea linie de cod


care se va executa. Aceasta trebuie sa fie in cadrul
procedurii curente.

Examinarea valorilor variabilelor


Valorile variabilelor din program pot fi examinate in mod Break mentinand mouse-ul
pozitionat deasupra variabilei, in fereastra de cod. Valoarea curenta a variabilei va fi
afisata intr-o casuta de tip pop-up. Aceasta tehnica furnizeaza o modalitate facila si
rapida de a determina valoarea curenta a unei variabile. Pentru mai multe informatii
referitoare la starea unei variabile, se pot folosi ferestrele Watch, Autos sau Locals.
Breakpoints
Se pot desemna linii de cod sau conditii care vor determina aplicatia sa isi opreasca
executia in debugger. Aceste entitati se numesc breakpoints. Se pot utiliza breakpoints
pentru a seta linii de cod sau conditii care vor opri executia program. Exista 4 tipuri de
breakpoints:
Setarea unui breakpoint de tip funtie:
- prin clic stanga pe bara gri din stanga ferestrei de editare de cod, in dreptul liniei
dorite
- prin clic dreapta pe linia dorita si selectand Insert Breakpoint din fereastra pop-up
- meniul Debug - New Breakpoint
Fereastra Breakpoints permite gestionarea multimii de breakpoints din program intr-o
singura fereastra.
Breakpoints - proprietati, conditii
Proprietatile unui breakpoint se pot vizualiza prin intermediul ferestrei Breakpoints - clic
dreapta, Properties. Fereastra Properties a oricarui breakpoint are trei taburi asociate:
Function, File si Address, fiecare dintre acestea fiind asociind breakpoint-ul la tipul
respectiv. Deci, chiar daca un breakpoint este asociat in fereastra de cod la un anumit
tip, el se exprima in fereastra Properties prin toate cele trei tipuri.
In plus, fereastra Breakpoint Properties contine doua butoane: butonul Conditions si
butonul Hit Count. Primul va vizualiza o fereastra care permite specificarea unei
expresii care va activa breakpoint-ul numai daca expresia este evaluata la true sau
daca expresia se modifica. Expresia poate fi orice expresie booleana care poate fi
evaluata la o valoare booleana. De exemplu, conditia poate fi setata la expresia
bool_var == true, breakpoint-ul devenind activ numai daca variabila bool_var are
valoarea true.
O alta metoda este desemnarea unei variabile sau expresii care, atunci cand se
modifica, va determina oprirea executiei programului. Expresia specificata trebuie sa
fie o expresie valida.
Butonul Hit Count determina vizualizarea ferestrei Breakpoint Hit, in care se poate seta

Dezvoltare de aplicatii in Visual Studio .NET

Page 83 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

ca breakpoint-ul sa intrerupa executia aplicatiei dupa ce a fost intalnit de un anumit


numar de ori, sau de un multiplu a unui numar predeterminat de ori sau de un numar
de ori mai mare sau egal cu un numar predeterminat. De exemplu, daca se seteaza
conditia hit count la un multiplu de 10, executia programului se va opri la fiecare a
zecea intalnire a breakpoint-ului.
!
Breakpoint-ul trebuie sa fie activ pentru a putea fi numarat.
Debugging Windows Sunt unelte de monitorizare a executiei programului. Unele,
precum fereastra Output sau fereastra Command, sunt disponibile in mod Design.
Altele, cum ar fi fereastra Locals, sunt vizibile numai pe durata debugging-ului.
Fereastra Output
- vizualizeaza output-ul generat in urma compilarii si executiei aplicatiei. Output-ul
include notificari legate de incarcarea assembly-urilor, precum si output generat de
constructii Debug si Trace.
Ferestrele Locals, Autos si Watch
Permit monitorizarea starii variabilelor din program pe durata debugging-ului
aplicatiei. Mai mult, aceste ferestre permit editarea valorilor variabilelor. Sunt utile
pentru testarea modului in care anumite proceduri raspund la diverse input-uri.
Fereastra Locals
Cand programul ruleaza in mod Debug, fereastra Locals permite monitorizarea
valorilor tuturor variabilelor din procedura curenta. Fereastra este structurata pe trei
coloane: Name, Value si Type. Tipurile mai complexe sunt vizualizate intr-un tree
care poate fi expandat pentru a vizualiza valorile membrilor. Pe parcursul executiei
programului, continutul ferestrei se mosdifica, in functie de procedura curenta. Se
pot modifica valorile tipurilor primitive prin editarea valorii variabilelor. Tipurile
complexe, precum clase sau structuri nu pot fi modificate, incercarea de a atribui
unui obiect continutul unui alt obiect neputandu-se realiza.
Fereastra Autos
Este o forma abreviata a ferestrei Locals, vizualizand numai variabilele din linia
curenta si din cea anterioara, in acelasi format si cu posibilitatea de editare a
valorilor variabilelor.
Fereastra Watch
Permite studierea evolutiei valorilor unor variabile specificate. Se poate efectua o
evaluare rapida a unei variabile utilizand dialogul QuickWatch.
Immediate Mode in fereastra Command
Este utilizat pentru executia procedurilor, evaluarea expresiilor sau modificarea
valorilor variabilelor pe durata debugging-ului. Vizualizarea ferestrei: Meniul Debug Windows - Immediate.
Afisarea valorii obtinute prin evaluarea unei expresii: folosind semnul intrebarii (?).
Exemplu:
? X*Y (o astfel de linie nu se termina prin punct si virgula).

Page 84 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

? Label2.Text - afiseaza valoarea curenta a proprietatii Text a variabilei Label2.


Alte ferestre
Tabelul urmator sintetizeaza alte ferestre disponibile din meniul Debug.
Tabel: alte ferestre disponibile din meniul Debug
Optiune

Descriere

Running
Documents

Lista documentelor incarcate in cadrul procesului care


ruleaza.

This

Afiseaza datele membre ale obiectului asociat metodei


curente.

Call Stack

Afiseaza numele functiilor din stiva de apeluri, tipul


parametrilor si valorile parametrilor.

Threads

Permite examinarea si controlul firelor de executie din


program.

Modules

Listeaza modulele (fisiere DLL sau EXE) utilizate in


program.

Memory

Afiseaza valorile stocate in memorie. Utila pentru


vizualizarea bufferelor si stringurilor de mari dimensiuni, sau
a altor date care nu pot afisate corespunzator in ferestre
Locals, Autos sau Watch.

Disassembly

Afiseaza cod assembly corespunzator instructiunilor create


de catre compilator.

Registers

Vizualizeaza continutul registrilor.

Sinteza
- tipuri de erori: de sintaxa, la executie si logice
- modul break - ferestre din meniul Debug

2. Clasele Debug si Trace


Clasele Debug si Trace permit generarea si afisarea (de obicei sub forma de log-uri) de
mesaje informative legate de anumite conditii specifice aplicatiei, fara a fi necesara
intreruperea executiei aplicatiei. Pentru aplicatii simple, frecvent utilizate, nu sunt
necesare unelte de debuging complexe, mijloacele prezentate anterior fiind suficiente.
Aplicatiile complexe ridica, insa, probleme. La aparitia unei erori logice, examinarea
variabilelor din aplicatie, urmarind liniile programului, conduce rar la identificarea si
rezolvarea erorii. Clasa Debug furnizeaza o modalitate de a crea si salva sub forma de
log-uri mesaje informative despre conditiile din program, pe masura ce aplicatia se
executa. Clasa Trace permite crearea unor instrumente de diagnostic care pun la
dispozitie mesaje informative chiar dupa ce aplicatia a fost compilata.

Dezvoltare de aplicatii in Visual Studio .NET

Page 85 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Cum functioneaza tracing-ul? Clasele Trace si Debug fac parte din spatiul de nume
System.Diagnostics care contine metode statice care permit testarea anumitor conditii
la run time si salvarea rezultatelor sub forma de log-uri. Output-ul generat de aceste
metode este afisat in fereastra Output si poate fi vizualizat pe durata debugging-ului.
Output-ul este transmis, de asemenea, colectiei Listeners. Aceasta colectie contine un
grup de clase care pot primi output de la clasele Trace si Debug. Trace si Debug
partajeaza aceeasi colectie Listeners si toti asculatatorii din colectie primesc input de la
Trace si Debug. Exista mai multe tipuri de Listeners, incluzand ascultatori care scriu in
fisiere text si Trace Listeners care scriu in loguri de evenimente. Dupa executia
programului, se pot examina aceste fisiere pentru identificarea erorilor din aplicatie.
Tracing-ul este, de asemenea, util in optimizarea programelor.
Clasele Trace si Debug sunt aproape identice. Clasa Debug este folosita, in principal in
faza de dezvoltare, in timp ce Trace poate fi utilizata pentru testare si optimizare dupa
ce o aplicatie a fost compilata si s-a generat o versiune release a aplicatiei.
Scrierea output-ului furnizat de clasele Trace si Debug
Metodele care realizeaza acest lucru sunt:

Write - scrie text in colectia Listeners, neconditionat.


WriteLine - similar, adaugand un enter la textul scris.
WriteIf - se scrie text daca conditia booleana specificata are valoarea true.
WriteLineIf - similar cu WriteLine, adaugandu-se un enter.
Assert - se scrie un mesaj de asertiune catre colectia Listeners daca expresia
booleana specificata are valoarea false. Se afiseaza, de asemenea, un message
box.
Fail - creaza o asertiune care este considerata falsa, fara a se testa vreo conditie.
Se scrie in colectia Listeners mesajul specificat de asertiune si se afiseaza, de
asemenea, un message box.
Exemplu de apelare a acestor metode:
// metodele sunt statice,
nu este necesara declararea unor instante
Trace.Write("Mesaj Trace 1");
Trace.WriteLine("Mesaj Trace 2");
// se scrie text daca expresia este true
Debug.WriteIf(x==2, "x are valoarea 2");
Debug.WriteLineIf(x==3, "x este egal cu 3");
// se scrie output si se afiseaza un message box
// daca valoarea conditiei este false
Trace.Assert(x==5, "x nu este egal cu 5!");
// se scrie output si se afiseaza un message box, neconditionat

Page 86 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Debug.Fail("Discul D nu mai este valid!");


Se poate modifica nivelul de indentare asociat mesajelor Trace atunci cand sunt
transmise colectiei Listeners apeland metodele Indent si Unindent si setand
proprietatile IndentSize si IndentLevel. Aceste metode si proprietati sunt utile pentru
crearea crearea si vizualizarea ierarhica a mesajelor de eroare. Proprietatea
IndentSize seteaza si returneaza numarul de spatii pentru o indentare, iar IndentLevel
seteaza si returneaza numarul de indentari aplicate. Metoda Indent incrementeaza
IndentLevel cu o unitate, iar Unindent decrementeaza.
Exemplu:
// incrementare IndentLevel
Trace.Indent();
Colectia Listeners
Output-ul generat de clasele Trace si Debug este directionat catre colectia Listeners.
Colectia Listeners organizeaza si expune clase capabile sa primeasca output-ul
furnizat de Trace. Fiecare membru al colectieiListeners primeste output de la clasele
Trace si Output. Tratarea output-ului depinde de tipul ascultatorului. Colectia Listeners
este initializata cu un membru, o instanta a clasei DefaultTraceListener. Acest
ascultator este creat automat si va primi output-ul claselor Trace si Debug, chiar daca
nu se ataseaza un alt ascultator. Output-ul primit de instanta DefaultTraceListener este
directionat catre debugger. DefaultTraceListener-ul este responsabil de vizualizarea
output-ului in fereastra Output. Daca se doreste salvarea mesajelor, in afara de
afisarea lor in fereastra Output, trebuie adaugat cel putin un ascultator in plus. Clase
specializate pentru scrierea de log-uri: EventLogTraceListener si
TextWriterTraceListener. Ambele clase sunt derivate din clasa abstracta TraceListener.
Crearea de log-uri sub forma de text
Clasa TextWriterTraceListener scrie output-ul primit ca text, fie catre un obiect de tip
Stream, fie catre un obiect TextWriter. De exemplu, Console.Out este un TextWriter.
Deci, se poate crea un TextWriterTraceListener care isi afiseaza intreg output-ul la
consola. Stream si TextWriter scriu in fisiere text.
Mecanismul crearii de fisiere log este urmatorul:
- se creaza un fisier care va contine output-ul
- se creaza o instance a clasei TextWriterTraceListener, specificandu-se fisierul
anterior creat
- se adauga instanta TextWriterTraceListener la colectia Listeners
Exemplu:
// se deschide fisierul log.txt
// (daca acesta nu exista, se creaza)
System.IO.FileStream firstLog = new
System.IO.FileStream("C:\\log.txt",
Dezvoltare de aplicatii in Visual Studio .NET

Page 87 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

System.IO.FileMode.OpenOrCreate); // se creaza un TraceListener


care specifica
// firstLog drept fisier tinta
TextWriterTraceListener firstListener = new
TextWriterTraceListener(firstLog);
// se adauga firstListener la colectia Listeners
Trace.Listeners.Add(firstListener);
!
Daca fisierul specificat in constructorul clasei FileStream exista, deschiderea fisierului
folosind IO.FileMode.OpenOrCreate va avea ca efect suprascrierea continutului
existent. Utilizand IO.FileMode.Append, noile informatii se vor adauga la sfarsitul
fisierului. O alta supraincarcare a constructorului TextWriterTraceListener permite
simpla specificare a fisierului in care se va scrie. Folosind acest constructor, fisierul text
va fi creat, daca nu exista sau, in caz contrar, noile informatii se vor adauga la sfarsit.
Exemplu:
TextWriterTraceListener secondListener = new
TextWriterTraceListener("C:\\log.txt");
La executia codului oricaruia dintre aceste doua exemple, tot output-ul claselor Trace si
Debug este scris in ascultatorul asociat. Pentru ca acest output sa fie scris efectiv in
fisier, trebuie apelata metods Flush a clasei Trace:
Trace.Flush();
O alta posibilitate este setarea proprietatii Trace.AutoFlush la true, ca in exemplul
urmator. Aceasta tehnica determina golirea bufferului dupa fiecare scriere:
Trace.AutoFlush = true;
Salvarea output-ului clasei Trace intr-un EventLog
EventLogTraceListener este clasa care permite salvarea output-ului clasei Trace
intr-un obiect EventLog. Mecanismul este in mare parte similar scrierii intr-un fisier text.
Se creaza un nou EventLog sau se specifica un log existent, se creaza un nou
EventLogTraceListener si se adauga la colectia Listeners. Output-ul este salvat in
EventLog ca obiecte EventLogEntry. Crearea unui nou event log si setarea numelui
sub care va fi vizualizat:
EventLog firstLog = new EventLog("Debug Log");
Se seteaza proprietatea Source pentru EventLog. Daca proprietatea Source nu este
setata, se va genera o eroare.
firstLog.Source = "Trace Output";
In continuare, se creaza o instanta EventLogTraceWriter care specifica noul log ca
target pentru output-ul Trace.
EventLogTraceListener logListener = new
EventLogTraceListenerfirstLog);
Page 88 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Daca este necesar, se poate seta proprietatea Trace.AutoFlush la valoarea true, sau
se poate apela Trace.Flush dupa fiecare scriere.
Comutatoare Trace (Trace Switches)
De obicei, la debugging, se doreste primirea intregului output provenit din constructii
care utilizeaza Trace si Debug. Totusi, dupa ce o aplicatie a fost compilata si lansata,
este de dorit activarea tracing-ului numai in anumite cazuri. Comutatoarele Trace sunt
comutatoare configurabile utilizate pentru a vizualiza constructii Trace. Acestea pot fi
configurate prin intermediul aplicatiei prin modificarea fisierului de configurare al
aplicatiei dupa ce aceasta a fost compilata si distribuita.
Exista in .NET Framework doua tipuri de comutatoare Trace. Instantele clasei
BooleanSwitch returneaza o valoare booleana. Deci, acestea sunt caracterizate prin
doua stari: on sau off. Clasa TraceSwitch permite utilizatorilor sa seteze nivelul
reprezentat de comutator, care poate fi o valoare intre 1 si 5, depinzand de tipul de
output pe care utilizatorul doreste sa il primeasca.
Ambele comutatoare necesita doi parametri in constructor: un NumeDeVizualizare,
care reprezinta numele comutatorului in cadrul interfetei utilizator si o Descriere, care
contine o scurta descriere a comutatorului. De exemplu:
BooleanSwitch firstBooleanSwitch = new BooleanSwitch("Switch1",
"Controls Data Tracing");
TraceSwitch firstTraceSwitch = new TraceSwitch("Switch2",
"Controls Forms Tracing");
Clasa TraceSwitch contine cinci setari care reprezinta diverse nivele de eroare. Aceste
setari sunt expuse prin intermediul proprietatii TraceSwitch.Level. Proprietatea poate fi
setata la una din cele cinci valori ale enumeratorului TraceLevel:

TraceLevel.Off. Desemneaza un TraceSwitch inactiv. Valoare 0.


TraceLevel.Error. Asociat cu mesaje de eroare scurte. Valoare 1.
TraceLevel.Warning. Pentru mesaje de eroare si warning-uri. Valoare 2.
TraceLevel.Info. Pentru mesaje de eroare, warning-uri si mesaje informative scurte.
Valoare 3.
TraceLevel.Verbose. Reprezinta mesaje de eroare, warning-uri si descrieri detaliate
ale executiei programului. Valoare asociata 4.
Mai mult, clasa TraceSwitch expune patru proprietati booleene read-only care
reprezenta nivelele Trace:

TraceSwitch.TraceError
TraceSwitch.TraceWarning
TraceSwitch.TraceInfo
TraceSwitch.TraceVerbose

Aceste proprietati corespund nivelurilor Trace cu aceleasi nume. La setarea proprietatii


Dezvoltare de aplicatii in Visual Studio .NET

Page 89 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

TraceSwitch.Level, are loc o setare automata a acestor patru proprietati la un nivel


corespunzator. De exemplu, daca TraceSwitch.Level este setat la TraceLevel.Info,
TraceSwitch.TraceInfo va returna true. De asemenea, TraceSwitch.TraceError si
TraceSwitch.TraceWarning vor returna true. Atunci cand in nivel este specificat, toate
nivelurile inferioare vor returna true.
Exemplu:
// se presupune declararea anterioara
// a unui obiect BooleanSwitch,
// firstBooleanSwitch, si a unui obiect
// TraceSwitch, firstTraceSwitch
Trace.WriteIf(firstBooleanSwitch.Enabled == true, "Eroare");
Trace.WriteLineIf(firstTraceSwitch.TraceInfo == true,
"Incompatibilitate de tipuri");
Dupa cum se poate observa, utilizatorul trebuie sa creeze propriile conexiuni intre
instructiunile care folosesc metodele clasei Trace si valorile comutatorilor. Daca se
folosesc metodele Trace.Write si Trace.WriteLine, valorile comutatorilorvor fi ignorate.
Configurarea comutatoarelor
Comutatoarele Trace pot fi activate sau dezactivate dupa ce aplicatia a fost compilata
si distribuita. Configurarea manuala se poate realiza prin intermediul fisierului de
configurare a aplicatiei (.config), un fisier XML care contine informatii despre aplicatie.
Fisierul .config trebuie plasat in acelasi director cu executabilul aplicatiei si trebuie sa
aiba acelasi nume: nume_aplicatie.exe.config. Nu toate aplicatiile au un fisier .config
file, deci pentru a folosi comutatoare Trace, este necesara crearea unui fisier .config. In
momentul in care aplicatia executa cod care creaza un comutator Trace, se verifica
fisierul .config pentru a extrage eventualele informatii in legatura ce acel comutator.
Fisierul este examinat cate o data pentru fiecare comutator. Orice modificare din
fisierul de configurare legata de un anumit comutator necesita oprirea si apoi
restartarea aplicatiei (fara o noua compilare!).
La crearea unui comutator, unul dintre parametrii este NumeleDeVizualizare. Acesta
este numele folosit pentru a configura comutatorul Trace in fisierul .config. La editarea
fisierului .config, trebuie specificat nu numai numele comutatorului, ci si valoarea la
care este setat. Valoarea trebuie sa fie intreaga. Pentru instante BooleanSwitch, zero
reprezinta off, iar o valoare nenula reprezinta on. Pentru obiecte TraceSwitch, valorile
zero, unu, doi, trei si patru corespund, respectiv, cu TraceLevel.Off, TraceLevel.Error,
TraceLevel.Warning, TraceLevel.Info si TraceLevel.Verbose. Orice valoare mai mare
decat 4 este tratata ca TraceLevel.Verbose.
Daca aplicatia nu are un fisier .config, acesta se poate crea, de exemplu, folosind
meniul Project, optiunea Add New Item. Fisierul trebuie sa aiba numele app.config,
unde app este numele aplicatiei. Se editeaza in cadrul fisierului tagul de inceput, xml, si
tagul configuration.
Intre tagurile configuration, se declara comutatoarele si se seteaza valorile acestora.
Page 90 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Exemplu:
<system.diagnostics>
<switches>
<add name="firstBooleanSwitch" value="0" />
<add name="firstTraceSwitch" value="3" />
</switches>
</system.diagnostics>
In acest exemplu, firstBooleanSwitch este setat pe off, iar firstTraceSwitch este setat la
TraceLevel.Info. Se modifica apoi valorile comutatoarelor, in functie de output-ul pe
care dorim sa il vizualizam. Se pot adauga, eventual, comentarii adecvate, pentru a
explica configurarile efectuate prin intermediul fisierului XML.
<system.diagnostics>
<switches>
<!-- pentru a primi mesaje Trace, setati valoarea la un intreg
nenul... -->
<add name="firstBooleanSwitch" value="0" />
<!-- setati valoarea la 1,2,3 sau 4 pentru, respectiv, mesaje
minimale, normale, detaliate sau complete -->
<add name="firstTraceSwitch" value="3" />
</switches>
</system.diagnostics>
Sinteza
- clasele Debug si Trace classes allow you to display and log messages
- colectia Trace.Listeners:
* DefaultTraceListener
* TextWriterTraceListener
* EventLogTraceListener
- comutatoare Trace: BooleanSwitch, TraceSwitch
- fisierul de configurare al aplicatiei

3. Exceptii
Chiar si dupa testarea si debugging-ul complet al aplicatiei, pot inca aparea erori la
Dezvoltare de aplicatii in Visual Studio .NET

Page 91 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

run-time. De exemplu, o aplicatie care salveaza date pe un floppy disk va genera o


eroare daca se incearca salvarea pe un disc care nu este disponibil. Chiar daca codul
aplicatiei functioneaza, eroarea poate aparea. C# confera posibilitatea tratarii
exceptiilor, adica scrierea de cod care sa permita continuarea executiei programului in
astfel de situatii.
Cum se trateaza exceptiile?
Atunci cand o aplicatie intalneste o eroare la run-time, se arunca o exceptie. Exceptiile
sunt instante ale unor clase specializate care mostenesc clasa de baza
System.Exception. Clasele folosite pentru tratarea exceptiilor includ aspecte care
faciliteaza diagnosticarea si managementul erorilor, cum ar fi:
- proprietatea Message - contin o descriere a erorii, precum si alte informatii relevante
despre aceasta
- proprietatea StackTrace - ofera posibilitatea localizarii fragmentului de cod care a
generat eroarea
Utilizatorul poate crea propriile exceptii, derivand din clasa
System.ApplicationException. La intalnirea unei erori la run-time, se creaza o instanta
a exceptiei corespunzatoare erorii si este transmisa de la metoda care a generat
eroarea catre metoda apelanta, prin intermediul stivei de apeluri. Daca, la nivelul
metodei apelante, se intalneste o structura de tratare a exceptiei, aceasta este tratata.
In caz contrar, exceptia este pasata urmatoarei metode apelante s.a.m.d. Daca nu se
intalneste nici o astfel de structura, se efectueaza o tratare implicita a exceptiei.
Aceasta are ca efect afisarea unui message box care vizualizeaza informatii legate de
tipul exceptiei si alte informatii aditionale si apoi aplicatia se termina, fara a mai avea
posibilitatea salvarii datelor sau tratarii erorii.
Utilizand structuri de tratare a exceptiilor, se pot defini modalitati de tratare a erorilor
sau, cel putin, de salvare a datelor inainte de inchiderea aplicatiei.
Crearea unui exception handler
Structurile de tratare a exceptiilor sunt implementate pentru metode specifice. Deci,
fiecare metoda poate avea propriul exception handler, specific metodei respective si
exceptiilor pe care le poate arunca. Metodele care pot arunca exceptii, cum ar fi
metodele care implica acces la fisiere, trebuie sa implementeze structuri de tratare a
exceptiilor. Acestea utilizeaza structuri de forma Try...Catch...Finally. Urmatorii trei pasi
sunt specifici crearii unei structuri de tratare a exceptiilor:
- se scrie codul care se va asocia handler-ului intr-un bloc try
- se adauga unul sau mai multe blocuri catch pentru tratarea posibilelor exceptii
- se adauga intr-un bloc finally cod care se va executa neconditionat (chiar daca se
arunca sau nu exceptia)
Exemplu:
try
{
// cod care poate arunca exceptii
Page 92 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

}
// urmeaza blocuri catch sau finally
Un bloc try poate fi urmat de unul sau mai multe blocuri catch. Un bloc catch contine
cod care va fi executat atunci cand exceptia va fi aruncata. Blocurile catch pot fi
generice sau specifice exceptiei. Exemplu: un bloc catch generic.
// bloc try... catch
{
// se executa la aruncarea oricarei exceptii
}
Se poate obtine o referinta a exceptiei care a fost aruncata. Acest lucru permite
accesarea in cadrul rutinei de tratare a exceptiei a informatiei continute de exceptie. Se
pot crea astfel blocuri catch multiple, specifice exceptiilor respective.
Exemplu:
// bloc try...
catch (System.NullReferenceException e)
{
// se prinde o exceptie NullReferenceException
}
catch (System.Exception e)
{
// acest bloc va prinde toate celelalte exceptii
}
Blocurile finally contin cod care trebuie executat independent de faptul ca o exceptie a
fost aruncata sau nu. Exemplu:
public void Parsare(string sir)
{
try
{
double x;
x = Double.Parse(sir);
}
catch (System.ArgumentNullException e)
{
// cod pentru cazul in care s-a
Dezvoltare de aplicatii in Visual Studio .NET

Page 93 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

// aruncat o exceptie de acest tip


}
catch (System.Exception e)
{
// cod pentru tratarea celorlalte exceptii
}
finally
{
// cod care se va executa neconditionat
}
}
Se va executa tot timpul un singur bloc catch. Se executa apoi blocul finally. Executia
aplicatiei se continua cu urmatoarea linie de cod de dupa linia care a apelat rutina ce
contine erori.
!
Deoarece se executa un singur bloc catch, acestea trebuie scrise de la cel mai specific
la cel mai putin specific bloc. Uneori, se doreste tratarea exceptiilor in cadrul rutinei
care a apelat rutina ce contine blocul try (cu un nivel mai sus). Chiar si in acest caz,
poate aparea necesitatea scrierii de cod care se va executa indiferent de aruncarea
sau nu a exceptiei. Pentru aceasta, se omite blocul catch si se utilizeaza o structura
try...finally. Exemplu:
try
{
// codul metodei...
}
finally
{
// cod de clean-up
}
Aruncarea exceptiilor
Se disting doua situatii specifice:
- eroare care poate fi patial tratata local: se trateaza partial eroarea, apoi aceasta este
transmisa stivei de apeluri
- eroare care nu poate fi tratata local: se arunca o exceptie .NET sau o exceptie
specifica

Page 94 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Rearuncarea exceptiiilor
Uneori, structura de tratare a exceptiilor, initial proiectata, nu este capabila sa trateze
total o anumita exceptie. In acest caz, se utilizeaza cuvantul rezervat throw, in cadrul
blocului catch, pentru rearuncarea exceptiei, adica transmiterea acesteia catre functia
apelanta. Exemplu:
try
{
// cod...
}
catch (System.NullReferenceException e)
{
// cod care testeaza posibilitatea tratarii exceptiei
// daca aceasta nu va putea fi tratata complet, va fi rearuncata
throw e;
}
In cazul unui catch generic, se utilizeaza cuvantul rezervat throw, fara a mai specifica o
referinta catre o anumita exceptie:
// bloc catch
catch
{
throw;
}
La rearuncare, se poate crea o noua exceptie care contine mesaje informative,
incluzand caracteristicile exceptiei initiale (in cazul in care dorim furnizarea de
informatii suplimentare catre nivelul superior al aplicatiei, caruia i se transmite exceptia
prin throw) Exemplu:
// bloc catch
catch (NullReferenceException e)
{
throw new NullReferenceException(
"Obiectul X este neinitializat", e);
}
Exceptii definite de utilizator (custom)
Un al doilea scenariu in care se poate arunca o noua exceptie este dezvoltarea de
Dezvoltare de aplicatii in Visual Studio .NET

Page 95 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

componente. In cazul unei conditii care nu poate fi rezolvate, este indicata aruncarea
unei exceptii definite de utilizator in cadrul aplicatiei client.
!
Aruncarea exceptiilor nu trebuie sa devina o obisnuinta, ci trebuie efectuata numai in
conditii exceptionale din program.
Exceptiile de tip custom se creaza prin derivarea din clasa
System.ApplicationException. Aceasta incapsuleaza intreaga functionalitate necesara
unei exceptii, incluzand proprietatile Message, StackTrace si InnerException. Exemplu:
public class CustomException: System.ApplicationException
{
KindOfObject an_object;
public KindOfObject ErrorObject // proprietate
{
get
{
return an_object; // read-only
}
}
// constructor - parametri de tip KindOfObject si string
public CustomException(KindOfObject o, string a) : base(s)
// se apeleaza constructorul din clasa de baza
{
// se seteaza proprietatea
an_object = o;
}
}
Dupa crearea unei clase exceptie, se poate arunca o noua instanta a acestei clase:
Exemplu:
KindOfObject a = new KindOfObject();
// cod care corupe obiectul a omis...
throw new CustomException(a, "Obiectul a a fost corupt!");
Sinteza

Page 96 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

- exceptii
- tratarea exceptiilor: try, catch, finally
- rearuncarea exceptiilor
- clasa System.ApplicationException

Dezvoltare de aplicatii in Visual Studio .NET

Page 97 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 7. Accesarea bazelor de date. ADO.NET - VI


1. Privire de ansamblu
O mare parte dintre aplicatii necesita un anumit tip de acces la baze de date. Aplicatiile
desktop trebuie sa integreze modele care sa interactioneze cu baze de date centrale,
colectii de date in format XML sau baze de date locale. Tehnologia ADO.NET de acces
la baze de date permite accesul facil si eficient la colectiile de date, prin eficientizarea
utilizarii resurselor.
Acces la baze de date fara conexiune
Tehnologiile anterioare functionau pe baza accesului la baze de date prin stabilirea
unei conexiuni permanente pe durata efectuarii operatiilor specifice. Intr-un astfel de
model, aplicatia creaza o conexiune la baza de date si aceasta este activa pana la
sfarsitul aplicatiei, sau cel putin pe durata interogarii bazei de date.
Dezavantaje ale conexiunilor permanente la baze de date:
-conexiunile deschise la bazele de date sunt costisitoare din punct de vedere al
resurselor
-aplicatiile sunt dificil de scalat; o aplicatie care functioneaza foarte bine cu 5 clienti
poate avea performante foarte scazute pentru 50 de conexiuni deschise simultan
-utilizarea unui numar mare de conexiuni poate conduce la epuizarea licentelor
disponibile pentru baza de date
ADO.NET vine in intampinarea acestor probleme implementand un model de accesare
a bazelor de date fara conexiune permanenta. In cadrul acestui model, conexiunile
sunt initializate si mentinute active doar pe durata efectiva a executiei operatiilor cu
baza de date. De exemplu, daca o aplicatie solicita anumite date dintr-o baza,
conexiunea este deschisa doar pe durata incarcarii datelor in aplicatie, apoi
conexiunea este inchisa. Similar, in cazul altor operatii.
Arhitectura ADO.NET
Accesul la date in ADO.NET implica doua entitati:
-un DataSet, care stocheaza datele pe masina locala
-un Data Provider, un set de componente care mediaza interactiunea dintre program si
baza de date
DataSet
Un DataSet este o reprezentare non-conexiune, in-memory , a unei multimi de date.
Poate fi gandit ca o copie locala a sectiunilor bazei de date utile aplicatiei. Datele pot fi
incarcate intr-un DataSet din orice sursa valida, cum ar fi un server SQL, o baza de
date Microsoft Access sau un fisier XML. DataSet-ul persista in memorie, iar datele
continute pot fi modificate, manipulate, independent de baza se date. La momentul
oportun, DataSet-ul poate actiona ca un sablon pentru modificarea bazei de date
Page 98 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

centrale.
Un obiect DataSet contine o colectie de zero sau mai multe obiecte DataTable, fiecare
dintre acestea fiind o reprezentare in-memory a unei tabele. Structura unui obiect
DataTable este definita de colectia DataColumns, care enumereaza coloanele dintr-o
tabela si de colectia Constraint care enumereaza legaturile, constrangerile din tabela.
Aceste doua colectii definesc schema tabelei. Un obiect DataTable contine, de
asemenea, o colectie DataRows, care contine datele corespunzatoare din DataSet.
Un DataSet contine o colectie DataRelations care permite crearea asocierilor intre
liniile unei tabele si liniile altei tabele. Colectia DataRelations enumereaza un set de
obiecte DataRelation care definesc relatiile intre tabelele din DataSet.
Data Provider
Legatura cu baza de date este creata si mentinuta de un data provider. Acesta este
format dintr-un set de componente interconectate care coopereaza pentru a furniza
date intr-o maniera eficienta, performanta.
Exista patru tipuri de furnizori de date in .NET Framework:
- SQL Server .NET Data Provider
- OleDb .NET Data Provider
- ODBC Data Provider
- Oracle Data Provider
Fiecare dintre acesti furnizori contin versiuni ale urmatoarelor clase generice:
- Connection - realizeaza conexiunea la baza de date
- Command - executa o comanda asupra unei surse de date: comenzi non-query
(INSERT, UPDATE sau DELETE) sau comanda SELECT, returnand un DataReader
- DataReader - desemneaza o multime de inregistrari (recordset) bazata pe conexiune,
de tip forward-only , read-only
- DataAdapter - populeaza un DataSet sau DataTable non-conexiune si executa
modificari
Mecanismul accesarii bazelor de date in ADO.NET este urmatorul:
- un obiect Connection stabileste o conexiune intre aplicatie si baza de date. Aceasta
conexiune poate fi accesata direct de un obiect Command sau de un obiect
DataAdapter. Obiectul Command executa o comanda asupra bazei de date. Daca se
returneaza valori multiple, se utilizeaza un obiect DataReader care va contine datele
returnate. Aceste date pot fi procesate direct de de aplicatie. Alternativ, se poate utiliza
un DataAdapter pentru a popula un obiect DataSet. Modificarile asupra bazei de date
se pot efectua prin intermediul unui obiect Command sau unui obiect DataAdapter.
Connection
Reprezinta conexiunea curenta la baza de date.
Tipuri de conexiuni:
Dezvoltare de aplicatii in Visual Studio .NET

Page 99 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

- SqlConnection - pentru conectarea la SQL Server 7 sau versiuni ulterioare


- OleDbConnection - conexiuni la diverse tipuri de baze de date
- ODBCConnection
- OracleConnection
Un obiect Connection contine toate informatiile necesare deschiderii unui canal de
comunicatie cu baza de date in cadrul proprietatii ConnectionString. Sunt incorporate,
de asemenea, metode pentru facilitarea tranzactiiilor.
Command
Este reprezentat de doua clase: SqlCommand si OleDbCommand Utilizat pentru a
efectua apeluri de proceduri stocate sau de comenzi SQL asupra bazei de date sau
pentru a returna tabele. Metode:
- ExecuteNonQuery - executa comenzi care nu returneaza inregistrari - INSERT,
UPDATE, DELETE
- ExecuteScalar - returneaza o singura valoare dintr-o interogare
- ExecuteReader - returneaza o multime rezultat, sub forma unui obiect DataReader
DataReader
- contine un recordset bazat pe conexiune, forward-only, read-only
- obiectele DataReader nu pot fi instantiate direct, sunt returnate ca rezultat al metodei
ExecuteReader a unui obiect Command (SqlCommand - SqlDataReader etc)
- o singura linie din recordset este in memorie la un moment dat, deci se foloseste un
minim de resurse, dar este necesara mentinerea activa a unui obiect Connection pe
durata de viata a obiectului DataReader
DataAdapter
DataAdapter este clasa din nucleul tehnologiei ADO.NET, bazata pe mecanismul
non-conexiune.
- faciliteaza comunicarea intre baza de date si DataSet
- populeaza obiectele DataTable sau DataSet ori de cate ori se apeleaza metoda Fill
- metoda Update inregistreaza modificarile, efectuate local, in baza de date
Proprietati:
- SelectCommand - contine textul sau obiectul asociat comenzii care se va efectua la
apelul metodei Fill
- InsertCommand - contine textul sau obiectul asociat comenzii prin care se insereaza
o linie in tabela
- DeleteCommand - similar, pentru stergerea unei linii din tabela
- UpdateCommand - similar, pentru modificarea valorilor din baza de date
La apelul metodei Update, se copie modificarile din DataSet in baza de date,
Page 100 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

executandu-se una din comenzile reprezentate de InsertCommand, DeleteCommand


sau UpdateCommand.

2. Comenzi SQL
Structured Query Language (SQL) - limbajul universal al bazelor de date relationale.
SQL poate fi utilizat pentru a prelua si filtra inregistrari din baza de date, pentru a
adauga inregistrari, pentru a sterge inregistrari din baza de date si pentru a modifica
valorile unei inregistrari existente.
Exista 4 constructii de baza:
- SELECT - pentru selectarea anumitor inregistrari din baza de date
- UPDATE - pentru modificarea unor inregistrari in baza de date
- INSERT - pentru inserarea unei noi linii intr-o tabela
- DELETE - pentru eliminarea unei inregistrari

SELECT
Sintaxa:
SELECT lista_campuri
FROM lista_tabele
WHERE (Optional) filtre
ORDER BY (Optional) criteriu_de_ordonare
Sintaxa minimala:
SELECT campuri FROM tabele
Exemplu:
SELECT StudentID, Prenume FROM Studenti;
Selectarea tuturor campurilor dintr-o tabela:
SELECT * FROM Studenti
WHERE - filtreaza inregistrarile dupa un anumit criteriu
SELECT * FROM Studenti WHERE Prenume = 'Vlad'
O conditie mai complexa:
SELECT * FROM Studenti WHERE Prenume = 'Vlad' AND Nume = 'Tepes'
Operatorul IN:

Dezvoltare de aplicatii in Visual Studio .NET

Page 101 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

SELECT Prenume, Nume FROM Studenti WHERE OrasNatal IN ('Deva', 'Bod')


Operatorul BETWEEN:
SELECT * FROM Studenti WHERE Media BETWEEN 8.5 AND 10
Sabloane:
SELECT * FROM Studenti WHERE Prenume LIKE 'Vla_'
Sablonul se va potrivi pentru prenume de 4 litere care incep cu Vla.
SELECT * FROM Studenti WHERE Prenume LIKE 'Vla%'
Se vor returna studentii al caror prenume incepe cu Vla.
Clausa ORDER BY
SELECT * FROM Studenti ORDER BY Medie DESC
DELETE
Elimina in mod ireversibil inregistrari din baza de date.
DELETE FROM Studenti WHERE Prenume = 'Vlad' AND Nume = 'Tepes';
Clauza WHERE are acceasi sintaxa ca in cazul comenzii SELECT.
UPDATE
Sintaxa generala:
UPDATE tabela
SET coloana1 = valoare1, ... ,coloanaN = valoareN
[WHERE predicat]
Exemplu:
UPDATE Studenti
SET Nume = 'Diaconu'
WHERE Prenume = 'Maria' AND Nume = 'Popescu'
Operatorii IN, BETWEEN, LIKE si clauza WHERE au aceeasi utilizare ca in cazul
comenzii SELECT.
INSERT INTO
Insereaza o inregistrare intr-o tabela. Sintaxa:
INSERT INTO tabela [(coloana1, ..., coloanaN)]
VALUES (valoare1, ... , valoareN)
Exemplu:

Page 102 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

INSERT INTO Studenti (Prenume, Nume, Varsta, Sex) VALUES ('Vlad', 'Tepes', 500,
'M')

3. Accesarea datelor
Conectarea la o baza de date
Exista mai multe posibilitatati de conectare la o baza de date:
- crearea unei conexiuni in mod design utilizand uneltele grafice din Visual Studio .NET
Conexiunile curente sunt vizualizate in fereastra Server Explorer, ca noduri copil ale
nodului Data Connections. Adaugarea unei conexiuni la proiect se face prin drag and
drop
- in fereastra Server Explorer se executa clic dreapta pe nodul Data Connections si se
selecteaza Add Connection, setandu-se proprietatile conexiunii in fereastra Data Link
care se deschide
- varianta manuala - adaugarea unui obiect Connection din Toolbox sau declararea si
instantierea obiectului in cod
- crearea unei conexiuni direct in cod - se seteaza manual proprietatea
ConnectionString. Exemplu:
// declararea si instantierea unui obiect OleDbConnection
OleDbConnection firstConnection = new OleDbConnection();
// setarea proprietatii connection string
firstConnection.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;DataSource=" +
"C:\\Mdb_databases\\studenti.mdb";
Utilizarea comenzilor asupra bazelor de date
Un obiect Command contine o referinta la o procedura stocata in cadrul bazei de date
sau o comanda SQL si poate executa comanda respectiva prin intermediul unei
conexiuni active la baza de date. Un astfel de obiect contine toate informatiile necesare
executiei comenzii, inclusiv o referinta la conexiunea activa, specificarea efectiva a
comenzii si, eventual, parametrii solicitati de comanda.
Clase de tip Command:
-OleDbCommand - interactiunea cu diverse tipuri de baze de date
-SqlCommand - interactiunea cu SQL Server 7 sau cu versiuni mai noi
Deoarece obiectele de tip Command implica existenta unei conexiuni active si nu
necesita interactiunea cu un DataAdapter, ele furnizeaza o modalitate rapida si
eficienta de interactiune cu baza de date.
Actiuni posibile:
Dezvoltare de aplicatii in Visual Studio .NET

Page 103 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

- executia unor comenzi care nu returneaza inregistrari - INSERT, UPDATE, DELETE


- executia unor comenzi care returneaza o singura valoare
- executia unor comenzi de tipul Database Definition Language (DDL), cum ar fi
CREATE TABLE sau ALTER
- interactiunea cu un DataAdapter pentru a returna un DataSet
- extragerea unei multimi de inregistrari utilizand direct o instanta a unui obiect
DataReader
- returnarea unei multimi de inregistrari in format XML (numai utilizand SqlCommand)
- returnarea unei multimi de inregistrari din mai multe tabele sau constructii care
desemneaza comenzi
Crearea si configurarea unei comenzi (Command):
- prin atasarea la proiect (in mod design) a unei proceduri stocate pe serverul de baze
de date, utilizand fereastra Server Explorer
- prin selectarea unui obiect Command din Toolbox, adaugarea acestuia in proiect si
configurarea sa folosind fereastra Properties
- prin declararea, instantierea si configurarea manuala a unui obiect Command, in cod
La crearea manuala a unui obiect Command, trebuie setate proprietatile Connection,
CommandType si CommandText.
CommandType - tipul comenzii specificate de proprietatea CommandText. Exista 3
valori posibile:
- Text - valoarea proprietatii CommandText va fi tratata drept comanda SQL (una sau
mai multe, separate prin punct si virgula (;), comenzile executandu-se secvential)
- StoredProcedure - valoarea proprietatii CommandText trebuie sa contina, in acest
caz, numele unei proceduri stocate pe serverul de baze de date; executia acestei
comenzi determina executia procedurii specificate
- TableDirect - se indica numele unei (mai multor) tabela(e); se va returna continutul
tabelei(lor) specificate
Proprietatea Connection trebuie setata la o conexiune existenta, avand tipul adecvat
(SqlCommand - SqlConnection, OleDbCommand - OleDbConnection).
Executia comenzilor
Se face prin intermediul a trei metode specifice:
-ExecuteNonQuery - specifica comenzilor de tip INSERT, UPDATE si DELETE
(comenzi non-query) si comenzilor de tip DDl, CREATE si ALTER
-ExecuteScalar - returneaza prima coloana a primei linii din multimea de inregistrari
returnate de comanda
-ExecuteReader - returneaza un obiect DataReader (forward-only, read-only), cu acces
rapid la date, utilizat atunci cand nu este necesara modificarea datelor in baza

Page 104 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

-ExecuteXmlReader (numai pentru SqlCommand)-returneaza un obiect XmlReader


(forward-only, read-only), in format XML
Parametri
Frecvent, comenzile implica utilizarea parametrilor, valorile anumitor entitati din cadrul
unei comenzi nefiind cunoscute pana in momentul executiei aplicatiei. Exemplu de
constructie SQL cu parametri:
SELECT * FROM Studenti WHERE (Prenume LIKE [sir])
sir este o valoare furnizata de utilizator la executie. Parametrii sunt valori care
inlocuiesc entitati din cadrul textului unei comenzi. Fiecare parametru este identificat
efectiv in program ca o instanta a clasei OleDbParameter sau SqlParameter. Ei sunt
stocati in proprietatea Parameters a clasei Command si, la run-time, valorile sunt citite
din proprietate si plasate in constructia SQL sau furnizate procedurii. Colectia
Parameters contine obiecte Parameter, avand urmatoarele proprietati mai importante:
- DbType
- Direction - cu valorile posibile Input, Output, InputOutput, or ReturnValue
- OleDbType
- ParameterName
- Precision
- Scale
- Size
- SourceColumn
- SourceVersion
- SQLType
- Value
Exemplu:
// setarea valorii primului parametru din colectie prin index
OleDbCommand1.Parameters[0].Value = "Primul parametru...";
// setarea valorii unui parametru identificat prin nume
OleDbCommand1.Parameters["nume_parametru1"].Value =
"valoare...";
Proprietatile Precision, Scale si Size stabilesc dimensiunea si acuratetea parametrilor pentru parametri numerici, binari sau de tip string.
SourceColumn si SourceVersion sunt utilizati atunci cand parametrul este legat de o
coloana intr-un DataTable.
Proprietatea Value contine valoarea reprezentata de parametru.
Pentru obiecte OleDbCommand, atunci cand CommandType este setata la valoarea

Dezvoltare de aplicatii in Visual Studio .NET

Page 105 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Text, parametri sunt specificati in cadrul comenzii SQL prin caractere (?). De exemplu:
SELECT StudentId, Prenume, Nume
FROM Studenti
WHERE (Prenume = ?) AND (Nume = ?)
Parametrii sunt inserati in ordinea in care apar in colectia Parameters.
Obiectele de tip SqlCommand utilizeaza parametri identificati prin nume, mai precis, in
cadrul comenzii SQL, un parametru este identificat prin simbolul @, urmat de valoarea
proprietatii ParameterName a parametrului respectiv:
SELECT StudentId, Prenume, Nume
FROM Studenti
WHERE (Nume = @Nume)
Executia unei comenzi non-query utilizand un obiect Command
- INSERT, UPDATE, DELETE, CREATE TABLE si ALTER
- CommandType - setata la StoredProcedure sau Text - se specifica eventualii
parametri - se apeleaza metoda Command.ExecuteNonQuery
// apel identic pentru OleDbCommand sau SqlCommand
firstCommand.ExecuteNonQuery();
Utilizarea unui obiect Command pentru a returna o valoare singulara
- CommandType - setata la StoredProcedure sau Text
- se specifica eventualii parametri
- se apeleaza metoda Command.ExecuteScalar
Object o;
o = firstCommand.ExecuteNonScalar();
DataReader
Pentru a utiliza un obiect Command care are asociate interogari care returneaza valori
multiple, se apeleaza metoda ExecuteReader pentru a returna un DataReader. Un
DataReader este un obiect care gestioneaza date intr-o maniera read-only,
forward-only, eficienta si rapida. Un DataReader itereaza inregistrarile returnate intr-o
multime rezultat. Viteza de accesare a datelor este mare, dar limitarile provin din faptul
ca maniera de prelucrarea este read-only, forward-only si nu se pot face modificari
asupra bazei de date. Mai mult, este necesara mentinerea unei conexiuni active pe
durata efectuarii acestor operatii, ceea ce determina un consum destul de semnificativ
de resurse.
Crearea unui DataReader
Un DataReader nu poate fi creat explicit. El este instantiat printr-un apel al metodei
Page 106 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ExecuteReader a unui obiect Command. Exemplu:


// firstOleDbCommand si firstSqlCommand sunt doua
// obiecte OleDbCommand, respectiv SqlCommand create anterior
System.Data.OleDb.OleDbDataReader firstOleDbReader;
System.Data.SqlClient.SqlDataReader firstSqlReader;
// creare si asignare
firstOleDbReader = firstOleDbCommand.ExecuteReader();
firstSqlReader = firstSqlCommand.ExecuteReader();
Accesarea datelor utilizand un DataReader
Iterarea inregistrarilor se poate realiza folosind metoda Read:
while (firstDataReader.Read())
{
// code care se va executa pentru fiecare inregistrare
}
Valorile coloanelor individuale din fiecare inregistrare pot fi accesate prin index sau prin
nume. De exemplu:
while (firstDataReader.Read())
{
object o = firstDataReader[3];
object oo = firstDataReader["StudentID"];
}
Toate valorile furnizate de un DataReader sunt preluate ca obiecte, dar se pot retuna
valori si in maniera puternic tipizata. Orice obiect DataReader mentine un acces
exclusiv asupra conexiunii utilizate, de accea, dupa efectuarea operatiilor, trebuie
apelata metoda Close a obiectului DataReader.
firstDataReader.Close();
Accesarea coloanelor de date cu un DataReader
Exemplu: afisarea valorilor unei coloane la consola.
firstConnection.Open();
// se creaza un DataReader
System.Data.OleDb.OleDbDataReader firstReader =
firstOleDbCommand.ExecuteReader();
// se apeleaza Read

Dezvoltare de aplicatii in Visual Studio .NET

Page 107 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

while (firstReader.Read())
{
// accesarea coloanelor prin nume
Console.WriteLine(firstReader["Prenume"].ToString());
}
firstReader.Close();
// se inchide DataReader-ul
firstConnection.Close();
// se inchide conexiunea
DataReader - tipizare
Clasa DataReader expune, de asemenea, metode tipizate de extragere a informatiilor,
de tip Get:
bool bool_var;
bool_var = myDataReader.GetBoolean(3);
// se utilizeaza numarul coloanei
Metoda GetOrdinal
int StudID;
string student;
// se preia indexul coloanei, utilizand numele acesteia
StudID = firstDataReader.GetOrdinal("StudentID");
student = firstDataReader.GetString(StudID);
Multimi rezultat multiple
Daca proprietatea CommandType a obiectului Command este setata la valoarea Text,
se pot returna mai multe multimi de inregistrari drept rezultat. Exemplu de comanda
SQL care va furniza rezultate multiple:
SELECT *
FROM Studenti;
SELECT *
FROM Profesori;
Un DataReader returneaza implicit prima multime de inregistrari in mod automat.
Pentru a accesa urmatoarea multime rezultat, se apeleaza metoda NextResult.
Exemplu:
do
{
Page 108 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

while (firstReader.Read())
{
// iterarea inregistrarilor multimii rezultat curente
}
} while (firstReader.NextResult());
Executia interogarilor SQL Ad Hoc
Sunt comenzi ale caror interogari se construiesc la run-time. Exemplu 1:
string cmd;
cmd = "SELECT * FROM Studenti WHERE Nume = '" + sir_de_caractere
+ "'";
Exemplu 2:
public void DeleteRecord(string sir)
{
string cmd;
cmd = "DELETE * FROM Studenti WHERE Nume = '" + sir + "'";
OleDbCommand firstCommand = new OleDbCommand(cmd,
firstConnection);
firstConnection.Open();
firstCommand.ExecuteNonQuery();
firstConnection.Close();
}
!
Atentie la validarea continutului variabilelor utilizate in constructia comenzilor SQL!
Crearea si configurarea obiectelor DataAdapter
Asigura legatura intre o sursa de date si un DataSet, gestionand schimbul de date intre
aceste doua entitati. Un DataAdapter incorporeaza functionalitatea necesara extragerii
datelor, popularii unui DataSet si aplicarii modificarilor in baza de date.
Clase .Net Framework: SqlDataAdapter, OleDbDataAdapter.
Un DataAdapter este utilizat, in general, pentru gestionarea schimbului de date dintre
un obiect DataTable continut intr-un DataSet si o singura tabela sursa.
Modalitati de creare a unui DataAdapter:
- utilizand fereastra Server Explorer (se adauga, prin drag and drop, o tabela in
design-ul aplicatiei)
- folosind Data Adapter Configuration Wizard (utilizand componenta DataAdapter din
Toolbox)

Dezvoltare de aplicatii in Visual Studio .NET

Page 109 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

- manual

Extragerea multimilor de date utilizand obiecte DataAdapters


Un DataSet este o reprezentare in-memory a datelor extrase la un moment dat din
baza de date si nu implica existenta unei conexiuni active. Un DataSet poate contine
tabele multiple, relatii intre tabele si constrangeri. Pot fi incluse intr-un DataSet date
provenind de la diverse surse de date. Obiectele DataAdapter gestioneaza
interactiunea dintre obiectele DataSet si bazele de date.
Popularea unui DataSet cu date se efectueaza prin apelarea metodei Fill a obiectului
DataAdapter. Metoda Fill executa instructiunile specificate de proprietatea
SelectCommand, in cadrul conexiunii specificate de proprietatea Connection si
populeaza DataSet-ul cu datele returnate. Exemplu:
DataSet firstDataSet = new DataSet();
firstDataAdapter.Fill(firstDataSet);
Popularea unui DataSet care contine mai mumte tabele:
- se creaza o instanta DataSet
- se creaza un DataAdapter pentru fiecare tabela din DataSet
- se apeleaza secvential metoda Fill pentru fiecare DataAdapter, specificand
DataSet-ul drept target
Obiecte DataSet tipizate
Exemplu 1: obiecte DataSet netipizate.
string stud;
stud =
(string)dsFacultate.Tables["Studenti"].Rows[0]["StudentID"];
Exemplu 2: obiecte DataSet tipizate.
string stud;
stud = dsFacultate.Studenti[0].StudentID;
Un DataSet tipizat este, de fapt, o instanta a unei clase noi, derivare din clasa DataSet.
Structura noii clase este bazata pe un fisier XSD (XML Schema Definition) care
defineste structura DataSet-ului, incluzand numele tabelelor si al coloanelor. Se pot
crea DataSet-uri tipizate numai in momentul in care se cunoaste structura exacta a
datelor.
Pentru a genera un DataSet se poate selecta optiunea Generate Dataset din meniul
Data.
Sinteza
- Connection

Page 110 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

- Command
* ExecuteNonQuery
* ExecuteScalar
* ExecuteReader
- parametri
- DataReader
- DataAdapter

4. Mai multe despre DataSet


DataSet reprezinta componenta centrala a arhitecturii ADO.NET, fiind o reprezentare
in-memory a datelor. Obiectele DataSet pot fi populate cu date prin intermediul
obiectelor DataAdapter, din fisiere XML, din fisiere text sau prin constructii
programatice.
Crearea si popularea obiectelor DataSet fara a utiliza un DataAdapter
Exemplu de creare a unui DataSet prin scrierea de cod:
DataSet firstDataSet = new DataSet();
DataTable firstTable = new DataTable();
firstDataSet.Tables.Add(firstTable);
In cadrul unui DataSet, tabelele sunt gestionate prin intermediul colectiei Tables, de
asemenea, in cadrul unei tabele, colectia Columns manipuleaza coloanele.
DataColumn StudentColumn = new DataColumn("Student");
firstDataSet.Tables[0].Columns.Add(StudentColumn);
Dupa adaugarea tuturor coloanelor dintr-o tabela, se pot adauga inregistrari, prin
intermediul obiectelor DataRows.
DataRow firstRow;
// nu se instantiaza, se apeleaza metoda NewRow
firstRow = firstDataSet.Tables[0].NewRow();
Un obiect DataRow poate fi populat cu date provenind dintr-o colectie, un array sau
input-ul utilizatorului. Exemplu:
// SourceString este un ArrayList
...
firstRow[i] = SourceString[i];
Dezvoltare de aplicatii in Visual Studio .NET

Page 111 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Adaugarea unui DataRow la colectia Rows a unui DataTable:


firstDataSet.Tables[0].Rows.Add(firstRow);
Accesarea fisierelor text
In multe aplicatii, datele sunt stocate in fisiere text de dimensiuni mari, fiind necesara
citirea datelor din aceste fisiere si popularea unui DataSet ADO.NET. Spatiul de nume
utilizat este System.IO. Un fisier text poate fi manipulat prin intermediul clasei
System.IO.StreamReader. Un format foarte des utilizat de structurare a informatiilor in
cadrul fisierelor text este .CSV. Exemplu: vezi resurse - Curs6, 1_flat_file.txt.
DataRelation
Un obiect DataRelation reprezinta o relatie intre doua coloane din doua tabele diferite.
De exemplu, pot exista doua tabele, Studenti si Optionale, fiecare continand o coloana
StudentID. Fiecare student apare o singura data in tabela Studenti, dar poate aparea
de mai multe ori in tabela Optionale. StudentID in tabela Optionale specifica studentul
din tabela Studenti care a ales optionalul respectiv. Acesta este un exemplu de relatie
one-to-many . Obiectele DataRelation sunt utilizate pentru identificarea acestor tipuri
de relatii.
Obiectele DataRelation ale unui DataSet particular sunt continute in proprietatea
Relations a DataSet-ului. Un obiect DataRelation este creat specificand numele relatiei,
coloana parinte si coloana copil. Intr-un DataSet tipizat, ambele coloane trebuie sa aiba
acelasi tip. Exemplu:
// coloana1, coloana2 sunt doua instante DataColumns
DataRelation oRelatie =
new DataRelation("Data Relation 1", coloana1,
coloana2);
Adaugarea la colectia Relations a DataSet-ului
unDataSet.Relations.Add(oRelatie);
Accesarea inregistrarilor implicate intr-o relatie
Se utilizeaza metodele GetChildRows si GetParentRow ale clasei DataRow. Exemplu:
DataRow[] ChildRows;
DataRow ParentRow;
// se returneaza liniile din Optionale care sunt in relatie cu
// linia 1 din tabela Studenti
ChildRows =
unDataSet.Tables["Studenti"].Rows[1].GetChildRows(oRelatie);
// linia din Studenti care este in relatie cu linia 3 din
// tabela Studenti

Page 112 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ParentRow = unDataSet.Tables["optionale"].
Rows[2].GetParentRow(oRelatie);
Constrangeri
Constrangerile definesc reguli de adaugare si manipulare a datelor in tabele. Tipuri de
constrangeri: UniqueConstraint (o coloana nu trebuie sa aiba valori duplicate) si
ForeignKeyConstraint (defineste regulile de modificare a liniilor copil atunci cand se
modifica o linie parinte).
Constrangerile sunt manipulate prin intermediul colectiei Constraints a tabelei si sunt
active atunci cand proprietatea EnforceConstraints a DataSet-ului este setata la true.
Exemple:
myDataColumn.Unique = true;
// se creaza o canstrangere UniqueConstraint
Creare manuala:
UniqueConstraint myConstraint = new
UniqueConstraint(myDataColumn);
myDataTable.Constraints.Add(myConstraint);
Stabilirea unei chei multiple:
DataColumn[] KeyColumns = new DataColumn[2];
KeyColumns[0] = StudentsTable.Columns["FirstName"];
KeyColumns[1] = StudentsTable.Columns["LastName"];
UniqueConstraint myConstraint = new
UniqueConstraint(KeyColumns);
StudentsTable.Constraints.Add(myConstraint);
Constrangeri Foreign Key
ForeignKeyConstraint myConstraint = new
ForeignKeyConstraint(Studenti.Columns["StudentID"],
Optionale.Columns["StudentID"]);
Adaugarea la colectia Constraints:
Studenti.Constraints.Add(myConstraint);
Reguli ForeignKeyConstraint referitoare la relatia parent-child :
UpdateRule: invocata la modificarea unei linii parinte
DeleteRule: invocata la stergerea unei linii parinte
AcceptRejectRule: invocata la apelarea metodei AcceptChanges a obiectului
DataTable caruia ii apartine constrangerea.

Dezvoltare de aplicatii in Visual Studio .NET

Page 113 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Fiecare dintre aceste reguli sunt expuse ca proprietati ale obiectului care desemneaza
constrangerea si pot avea diverse valori: Cascade, None, SetDefault, SetNull.
Fiecare DataSet mentine doua versiuni ale informatiilor continute: versiunea curenta,
care contine copia client a DataSet-ului si evidenta modificarilor efectuate, si versiunea
originala, care contine datele in formatul in care se gaseau la prima populare a
DataSet-ului. La apelul metodei Update a obiectului DataAdapter, valorile initiale sunt
utilizate de comenzi UPDATE, INSERT si DELETE pentru a executa modificarile in
baza de date.
Editarea datelor
- prin intermediul controalelor din interfata utilizator conectate la anumite entitati din
baza de date
- prin constructii programatice (vezi exemplu)
// accesare prin index sau nume
aDataRow[3] = "M";
aDataRow["Studenti"] = "Vlad";
Metoda RejectChanges anuleaza modificarile efectuate asupra unui DataRow:
aDataRow.RejectChanges();
AcceptChanges - se aplica modificarile efectuate asupra obiectului DataRow apelant:
with the edited version.
aDataRow.AcceptChanges();
Se poate determina starea unui obiect DataRow analizand proprietatea RowState.
Valori posibile:
- Unchanged
- Modified
- Added
- Deleted
- Detached
Obiectele DataTable si DataSet contin, de asemenea, metode RejectChanges si
AcceptChanges, care permit refuzarea sau acceptarea modificarilor din DataTable,
respectiv DataSet.
Modificarea bazei de date
firstDataAdapter.Update();
secondOtherDataAdapter.Update();
Metoda Update are ca efect copierea versiunii client a datelor in baza de date.
Page 114 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

// se pot modifica numai anumite entitati din DataSet


aDataAdapter.Update(someDataSet);
aDataAdapter.Update(someDataTable);
aDataAdapter.Update(someDataRows);
Tranzactii
Reprezinta un set de operatii asupra bazei de date care se efectueaza ca un
ansamblu: daca una dintre operatii esueaza, tranzactia nu se efectueaza. Exemplu:
// tranzactiile trebuie incluse in blocuri
//Try...Catch...Finally
System.Data.OleDb.OleDbTransaction aTransaction = null;
try
{
aConnection.Open();
aTransaction = aConnection.BeginTransaction();
// crearea unei tranzactii si asocierea la conexiune
// adaugare de operatii la tranzactie
Update1.Transaction = aTransaction;
Update2.Transaction = aTransaction;
// se executa comenzile Update1 si Update2
Update1.ExecuteNonQuery();
Update2.ExecuteNonQuery();
// daca nu s-au lansat exceptii, se efectueaza tranzactia
aTransaction.Commit();
}
catch (Exception ex)
{
// tranzactia nu s-a efectuat, s-au lansat exceptii
aTransaction.Rollback();
}
finally
{
// se inchide conexiunea
aConnection.Close();

Dezvoltare de aplicatii in Visual Studio .NET

Page 115 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
Tratarea erorilor de Update
Clasele SqlDataAdapters si OledbDataAdapters contin un eveniment RowUpdated
care se lanseaza dupa modificare unei linii, inainte de lansarea eventualelor exceptii.
Acest eveniment trebuie tratat in mod adecvat. Evenimentul RowUpdated contine o
instanta SqlRowUpdatedEventArgs sau OleDbRowUpdatedEventArgs, care furnizeaza
informatii utile in determinarea erorii care a survenit.
Proprietati ale RowUpdatedEventArgs:

Command
Errors
RecordsAffected
Row
Status
Continue
ErrorsOccurred
SkipAllRemainingRows
SkipCurrentRow

Exemplu:
private void aDataAdapter_RowUpdated(object sender,
System.Data.SqlClient.SqlRowUpdatedEventArgs e)
{
// se verifica proprietatea Status
if (e.Status == UpdateStatus.ErrorsOccurred)
{
MessageBox.Show("A survenit o eroare de tipul " +
e.Errors.ToString()+".
Informatii aditionale : " + e.Errors.Message);
// se ignora modificarile de la linia curenta,
// continuandu-se cu urmatoarele
e.Status = UpdateStatus.SkipCurrentRow;
}
}

5. Accesarea, vizualizarea si filtrarea datelor

Page 116 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Vizualizarea datelor reorezinta o parte vitala a multor aplicatii. Pentru aceasta,


inregistrarile din cadrul unei surse de date trebuie asociate cu o serie de controale de
pe o forma (binding), permitandu-se accesaream parcurgerea si modificarea datelor.
Data Binding - crearea unei relatii intre un data provider si un data consumer. Un data
provider poate fi orice obiect la care poate fi legat un consumator. In .NET Framework,
orice obiect care implementeaza interfata IList poate fi furnizor de date. Aceasta nu
include obiecte ADO.NET, cum ar fi DataSet, DataTable sau DataColumn, care pot fi
prin constructie furnizori de date.
Parcurgerea datelor se realizeaza prin intermediul unui obiect CurrencyManager
asociat implicit fiecarei surse de date.
Data Consumer Orice control conectat, intr-un anumit fel, la o sursa de date poate fi
considerat consumator. Exemplu: o forma care permite introducerea de date. In cadrul
acesteia, anumite controale, cum ar fi TextBox, CheckBox, ListBox, etc. sunt conectate
la anumite coloane dintr-un DataSet.
Tipuri de legare (binding): simpla si complexa.
Un control simplu legat identifica o singura inregistrare. De exemplu, un Label asociat
unei coloane dintr-un DataTable.
Legarea complexa permite asocierea controlului cu mai multe inregistrari. Exemplu:
ListBox sau ComboBox asociate unei coloane dintr-un DataTable sau un DataGrid
asociat unui DataTable sau chiar unui DataSet.
Crearea unui control simplu legat
Prin intermediul proprietatii DataBindings. Aceasta este o instanta a clasei
ControlBindingsCollection care gestioneaza controalele legate la surse de date. Pentru
un anumit control, in fereastra Properties se poate expanda nodul din dreptul
proprietatii DataBindings si selecta un anumit data provider.
Legare la executie
Scenarii:
- modificarea unei surse de date pentru un control legat
- identificarea sursei de date a unui control legat
- legarea unui control la un array sau colectie care este instantiata la run time
Exemplu:
// legarea unei etichete la coloana StudentID
// din tabela Students
LabelID.DataBindings.Add("Text", DataSet1.Students,
"StudentID");
// Text este proprietatea care va fi legata

Dezvoltare de aplicatii in Visual Studio .NET

Page 117 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Exemplu 2:
String[] studenti = new String[3];
studenti[0] = "Aionesei";
studenti[1] = "Agafitei";
studenti[2] = "Georgescu";
TextBox1.DataBindings.Add("Text", studenti, "");
// al treilea parametru este vid, sursa de date
// nu este complexa, nu are membri
Eliminarea unei legaturi:
Label1.DataBindings.Remove(Label1.DataBindings["Text"]);
// se elimina legatura existenta pentru proprietatea
// Text a etichetei Label1
Eliminarea tuturor legaturilor asociate unui control - prin apelarea metodei Clear:
Label1.DataBindings.Clear();
Navigare (Data Currency)
Fiecare forma gestioneaza obiecte CurrencyManager asociate surselor de date prin
intermediul unui obiect central BindingContext. Accesarea unui anumit currency
manager se face prin intermediul proprietatii BindingContext, specificand sursa de date
a obiectului in cauza. De exemplu:
this.BindingContext[DataSet1.Students];
Inregistrarea curenta poate fi setata prin intermediul proprietatii Position a unui
BindingContext:
// tabela Studenti face parte din DataSet1
// setarea inregistrarii curente la prima
// inregistrare din sursa de date
this.BindingContext[DataSet1.Studenti].Position = 0;
// setarea inregistrarii curente la a
//treia inregistrare din sursa de date
this.BindingContext[DataSet1.Studenti].Position = 2;
// avansarea la urmatoarea inregistrare
this.BindingContext[DataSet1.Studenti].Position ++;
Navigarea prin colectia de date dintr-o forma Windows
Se seteaza proprietatea Position a membrului BindingContext dorit.
Page 118 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Este imposibila deplasarea inaintea primei inregistrari sau dupa ultima inregistrare.
Exemplu: utilizarea evenimentului PositionChanged din cadrul clasei CurrencyManager
pentru dezactivarea butoanelor de navigare atunci cand linia curenta este pozitionata
pe prima sau ultima inregistrare.
// handler
public void OnPositionChanged(object sender, System.EventArgs e)
{
if (this.BindingContext[DataSet1.Students].Position == 0)
// dezactivarea butonului Back
BackButton.Enabled = false;
else
// activare
BackButton.Enabled = true;
// similar pentru butonul Forward
}
// linia de adaugat in constructorul formei
this.BindingContext[DataSet1.Customers].PositionChanged += new
EventHandler(this.OnPositionChanged);
Legare complexa
Prin setarea proprietatii DataSource:
DataGrid1.DataSource = DataSet1.Students;
Proprietatea DisplayMember desemneaza numele coloanei la care se leaga controlul.
Exemplu:
ComboBox1.DataSource = DataSet1.Students;
ComboBox1.DisplayMember = "StudentID";
Filtrarea si sortarea datelor
DataView permite lucrul cu un subset al datelor continute intr-un DataTable. Aceasta
clasa contine metode pentru sortarea si filtrarea datelor, permitand si modificarea
obiectului DataTable pe care il reprezinta.
Crearea unui DataView
Se specifica obiectul DataTable care va fi filtrat. Exemplu:
DataView aDataView = new DataView(aDataTable);
Alternativa:
Dezvoltare de aplicatii in Visual Studio .NET

Page 119 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

DataView anotherDataView = new DataView();


anotherDataView.Table = anotherDataTable;
Un DataView poate fi creat utilizand Toolbox-ul.
Filtrare si sortare in DataSet
Exemple: sortare dupa una sau mai multe coloane.
aDataView.Sort = "StudentID";
anotherDataView.Sort = "Prenume, Nume";
Filtrare: prin setarea proprietatii RowFilter. Se specifica un string care reprezinta o
expresie prin care se selecteaza inregistrari. Exemplu:
aDataView.RowFilter = "Nume = 'Popescu'";
In general, expresiile RowFilter urmeaza sintaxa SQL.
Proprietatea DataView.RowState permite filtrarea obiectelor DataRow in functie de
starea lor. Valori posibile ale acestei proprietati (se poate seta la una sau mai multe din
aceste valori):
- Unchanged
- Added
- Deleted
- OriginalRows
- CurrentRows
- ModifiedCurrent
- ModifiedOriginal
Editarea datelor folosind un DataView
Proprietati care stabilesc daca datele dintr-un DataView pot fi editate.
- AllowDelete - se permite sau nu stergerea
- AllowEdit - se permite sau nu editarea
- AllowNew - se permite sau nu adaugarea de noi linii
Clasa DataViewManager
O instanta a acestei clase este asociata cu un DataSet, gestionand obiecte DataView
pentru diverse tabele. Exemplu:
DataViewManager aDataViewManager = new
DataViewManager(aDataSet);
DataViewManager anotherDataViewManager = new DataViewManager();

Page 120 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

anotherDataViewManager.DataSet = anotherDataSet;
Colectia DataViewSettings contine proprietatile DataView asociate tabelelor dintr-un
DataSet. Exemplu:
aDataViewManager.DataViewSettings["Students"].RowFilter =
"Prenume = 'Costel'";
Sinteza:
- data binding
- data provider
- data consumer
- CurrencyManager
- DataView
- RowFilter si Sort
- DataViewManager

Dezvoltare de aplicatii in Visual Studio .NET

Page 121 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 8. GDI+. Controale utilizator. Atribute - VII


1. GDI+
Interfetele grafice sunt entitati frecvent intalnite in lumea utilizatorilor. Desi exista foarte
multi adepti ai interfetelor text, cu siguranta nimeni nu va ezita sa foloseasca o interfata
grafica prietenoasa, cu ajutorul careia sa interactioneze cu usurinta cu aplicatia care o
pune la dispozitie. Microsoft Windows este, in principiu, o interfata grafica. Utilizatorii
interactioneaza cu aplicatiile prin intermediul ferestrelor, care sunt reprezentari grafice
ale optiunilor si datelor din cadrul aplicatiilor. Pentru o utilizare facila, aplicatiile trebuie
sa isi expuna functionalitatea prin intermediul interfetei grafice. Desi .NET Framework
pune la dispozitie un set complex de controale grafice, apare adesea necesitatea
vizualizarii propriului continut grafic si crearii unui aspect personalizat pentru un anumit
control. Toate acestea implica utilizarea Graphic Device Interface (GDI). In .NET
Framework, aceasta interfata este gestionata prin intermediul GDI+. Clasele .NET
Framework care expun functionalitatea GDI+ sunt incluse in spatiul de nume
System.Drawing si in spatiile de nume asociate.
GDI+ este o implementare managed a GDI, utilizata pentru vizualizarea informatiilor
graphice pe ecranul computerului. Aceasta interfata utilizeaza clase divizate in sase
spatii de nume, pe baza functionalitatii.
Spatii de nume System.Drawing

Spatiu de nume

Continut

System.Drawing

O mare parte din clasele implicate in randarea continutului grafic pe


ecran. Este principalul spatiu de nume utilizat in programarea grafica.

System.Drawing.Design

Clase care expun functionalitati aditionale pentru operatiile grafice.

System.Drawing.Drawing2D

Clase care transpun efecte vizuale avansate.

System.Drawing.Imaging

Clase care permit manipularea avansata a fisierelor imagine.

System.Drawing.Printing

Clase care faciliteaza printarea continuturilor textuale sau grafice.

System.Drawing.Text

Clase care faciliteaza manipularea avansata a fonturilor.

Majoritatea claselor care faciliteaza randarea grafica sunt incluse in spatiul de nume
System.Drawing. Pentru randare avansata, se utilizeaza clase din spatiul de nume
System.Drawing.2D, iar pentru implementarea unor functionalitati de printare, clase din
System.Drawing.Printing.
Clasa Graphics
Clasa Graphics, localizata in spatiul de nume System.Drawing, este principala clasa
utilizata pentru randare grafica. Un obiect Graphics reprezinta suprafata grafica a unui
element vizual, cum ar fi o forma, un control sau un obiect Image. Deci, o forma are
asociat un obiect Graphics utilizat pentru a desena in interiorul formei; un control are
asociat un obiect Graphics folosit pentru a desena in interiorul controlului, s.a.m.d.
Page 122 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Obiectul Graphics este, deci, responsabil de randarea elementelor vizuale.


Deoarece fiecare obiect Graphics trebuie asociat cu un element vizual, nu se poate
efectua o instantiere directa a acestuia. In schimb, un obiect Graphics se creaza direct
pornind de la elementul vizual respectiv. Clasele derivate din Control (incluzand Form)
expun o metoda CreateGraphics care permite preluarea unei referinte a obiectului
Graphics asociat controlului.
Urmatorul exemplu demonstreaza crearea unui obiect Graphics pentru o forma aForm:
System.Drawing.Graphics firstGraphics;
firstGraphics = aForm.CreateGraphics();
Obiectul Graphics astfel creat poate fi ulterior utilizat pentru vizualizarea elementelor
grafice pe forma.
In cazul imaginilor, se poate utiliza metoda statica Graphics.FromImage pentru a crea
un obiect Graphics asociat unui obiect particular Image. Obiectul Image poate fi orice
obiect derivat din clasa Image, de exmplu, Bitmap. Exemplu: crearea unui obiect
Bitmap utilizand un fisier existent si apoi asocierea unui obiect Graphics:
Bitmap aImage = new Bitmap("C:\\someImage.bmp");
System.Drawing.Graphics secondGraphics;
secondGraphics = Graphics.FromImage(aImage);
!
Imaginea nu trebuie sa fie vizibila pentru a se putea crea obiectul Graphics asociat sau
pentru a il putea manipula.
Coordonate
Randarea se efectueaza pe ecran in regiunea determinata de marginile controlului.
Acesta regiune este masurata in coordonate bidimensionale, constand in valori (x, y).
Implicit, originea coordonatelor sistemului pentru fiecare control este data de coltul din
stanga sus, care are coordonatele (0,0). Coordonatele sunt masurate in pixeli. Spatiul
de nume System.Drawing contine o varietatea de structuri utilizate pentru a descrie
locatii sau regiuni din acdrul sistemului de coordonate. Tabelul urmator sumarizeaza
aceste structuri:
Structura

Descriere

Point

un punct reprezentat prin doua valori Integer (int), x si y

PointF

un punct reprezentat prin doua valori Single (float), x si y

Size

o suprafata rectangulara specificata printr-o pereche de intregi Height


si Width

SizeF

o suprafata rectangulara specificata printr-o pereche de valori Single


(float), reprezentand Height si Width

Rectangle

o reprezentare a unei regiuni rectangulare prin patru valori intregi Top,


Bottom, Left si Right

Dezvoltare de aplicatii in Visual Studio .NET

Page 123 of 203

ibm.com/developerWorks

RectangleF

Presented by developerWorks, your source for great tutorials

o reprezentare a unei regiuni rectangulare prin patru valori flotante


Top, Bottom, Left si Right

Exemplu:
// conversie de la o structura punct reprezentata
// prin valori float la un punct
// reprezentat prin intregi
Point aPoint;
PointF aPointF = new PointF(10.9F,31.23F);
aPoint = new Point((int)aPointF.X, (int)aPointF.Y);
Exemplu:
crearea unei structuri Rectangle prin specificarea unui structuri Size si a unei structuri
Point:
Point pointOrigin = new Point(100, 50);
Size aSize = new Size(40, 50);
// se creaza un Rectangle 40 pe 50 avand
// coltul din stanga sus specificat de Point(100,50)
Rectangle aRectangle = new Rectangle(pointOrigin, aSize);
Desenarea formelor
Orice obiect Graphics incapsuleaza o varietate de metode pentru randarea formelor
simple si complexe pe ecran. Acestea sunt incadrate in doua categorii generale:
- metode de tip Draw - linii, arce, contururi ale formelor;
- metode de tip Fill - forme solide - dreptunghiuri, elipse sau poligoane
Metode pentru desenarea structurilor bazate pe linii:
Metoda

Descriere

DrawArc

deseneaza un arc reprezentand o portiune a unei elipse

DrawBezier

deseneaza o curba Bezier

DrawBeziers

deseneaza o serie de curbe Bezier

DrawClosedCurve

deseneaza o curba inchisa pe baza unei serii de puncte

DrawCurve

deseneaza o curba deschisa pe baza unei serii de puncte

DrawEllipse

deseneaza o elipsa pe baza unui dreptunghi

DrawLine

deseneaza o linie conectata prin doua puncte

DrawLines

deseneaza o serie de linii pe baza unui tablou de puncte

Page 124 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

DrawPath

deseneaza un obiect GraphicsPath care reprezinta o forma


complexa

DrawPie

deseneaza o forma de tip pie ca sector de elipsa

DrawPolygon

deseneaza un poligon pe baza unei serii de puncte

DrawRectangle

deseneaza un dreptunghi

DrawRectangles

deseneaza o serie de dreptunghiuri

Metode pentru desenarea formelor solide:


Metoda

Descriere

FillClosedCurve

deseneaza o curba inchisa specificata printr-un tablou de


puncte

FillEllipse

deseneaza o elipsa plina

FillPath

reda un obiect solid GraphicsPath reprezentand o forma


complexa

FillPie

deseneaza o forma pie solida

FillPolygon

reda un poligon solid specificat printr-un tablou de puncte

FillRectangle

deseneaza un dreptunghi solid

FillRectangles

o serie de dreptunghiuri solide

FillRegion

umple un obiect Region care corespunde de obicei unei


forme complexe

Fiecare dintre aceste metode primesc diversi parametri care specifica coordonatele
punctelor si locatia formelor care se vor desena. Fiecare metoda necesita un obiect
care sa efectueze randarea. Pentru structuri liniare, se utilizeaza un obiect Pen. Pentru
forme solide, se folosesc obiecte Brush.
Color, Brush si Pen
Aceste tipuri sunt utilizate pentru a determina modul de randare a unei imagini grafice.
Obiectele Pen redau linii si arce, obiectele Brush redau forme solide, iar obiectele de
tip Color definesc culorile folosite in vizualizare.
Color
Structura Color reprezinta o singura culoare si se gaseste in spatiul de nume
System.Drawing. Culorile individuale sunt derivate din patru valori: Alpha - gradul de
transparenta, Red, Green si Blue, cuprinse intre 0 to 255. O noua culoare se poate
crea folosind metoda Color.FromArgb:
Color aColor;
aColor = Color.FromArgb(128, 255, 12, 50);
Pentru culori opace, parametrul Alpha se omite:

Dezvoltare de aplicatii in Visual Studio .NET

Page 125 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Color aColor;
aColor = Color.FromArgb(255, 12, 43);
Exista un set de culori definite in .NET Framework. Exemplu:
Color aColor;
aColor = Color.Tomato;
Brush
Obiectele Brush sunt sunt folosite pentru randarea formelor solide. Toate aceste
obiecte sunt derivate din clasa abstracta de baza Brush si furnizeaza implementari
diferite ale obiectelor utilizate pentru randarea obiectelor solide, in diferite stiluri.
Tipuri de obiecte Brush:
Tip

Spatiu de nume

Descriere

SolidBrush

System.Drawing

o singura culoare solida

TextureBrush

System.Drawing

umple obiecte inchise cu o


imagine

HatchBrush

System.Drawing.Drawing2D

hasureaza interiorul
obiectelor

LinearGradientBrush System.Drawing.Drawing2D

combina doua culori pe baza


unui gradient

PathGradientBrush

randarea de efecte vizuale


complexe

System.Drawing.Drawing2D

Crearea unui SolidBrush:


SolidBrush sBrush = new SolidBrush(Color.PapayaWhip);
Constructorii altor tipuri de obiecte brush necesita parametri aditionali.
Pen
Obiectele de acest tip sunt utilizate pentru a desena linii si arce, putand fi utilizate
pentru aplicarea unei varietati de efecet speciale structurilor bazate pe linii. Clasa Pen
nu poate fi mostenita direct. Exemplu de creare a unui obiect Pen:
Pen aPen = new Pen(Color.BlanchedAlmond);
Grosimea implicita este 1. O alta grosime poate fi specificata prin intermediul
constructorului, ca in exemplul urmator:
Pen aPen = new Pen(Color.Red, 5);
Crearea unui pen pe baza unui obiect brush existent:
Pen aPen = new Pen(aBrush);
Anumite aplicatii trebuie sa aiba interfete grafice care sa aiba aceleasi caracteristici ca
Page 126 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

si interfata sistemului pe care va rula aplicatia. .NET Framework pune la dispozitie


culori specifice sistemului prin intermediul clasei SystemColors. Aceasta clasa contine
un set de membri statici care contini culorile utilizate de sistem. Deci, se pot defini
elemente ale interfetei utilizator care sa foloseasca culori preluate la executie din setul
de culori puse la dispozitie de sistemul pe care ruleaza aplicatia. Exemplu:
Color aColor = SystemColors.HighlightText;
Similar, exista clasele SystemPens si SystemBrushes.
Randarea formelor simple
Toate metodele care redau forme simple, bazate pe linii, necesita un obiect valid de tip
Pen. Metodele specializate in vizualizarea formelor solide au ca parametru un obiect
Brush. Exemplu:
// un obiect Rectangle
Rectangle aRectangle = new Rectangle(0, 0, 30, 50);
// crearea obiectului Graphics asociat formei
Graphics g = this.CreateGraphics();
g.DrawRectangle(SystemPens.ControlDark, aRectangle);
// dealocarea obiectului Graphics
g.Dispose();
Exemplu 2:
SolidBrush aBrush = new SolidBrush(Color.MintCream);
Graphics g = this.CreateGraphics();
// o elipsa care va fi inscrisa intr-un dreptunghi
Rectangle aRectangle = new Rectangle(0, 0, 50, 20);
g.FillEllipse(aBrush, aRectangle);
g.Dispose();
aBrush.Dispose();
!
Este indicata apelarea metodei Dispose pentru obiectele Graphics, deoarece acestea
sunt mari consumatoare de resurse.
Vizualizarea textelor
Se utilizeaza metoda DrawString a obiectelor Graphics, care vizualizeaza un string
reprezentand un text pe ecran. Textul este vizualizat folosit un font specificat si este
redat printr-un obiect Brush. Trebuie specificate, de asemenea, coordonatele la care se
va face afisarea. Exemplu:
Graphics g = this.CreateGraphics();
Dezvoltare de aplicatii in Visual Studio .NET

Page 127 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

String aString = "Salut, anul 4!";


Font aFont = new Font("Times New Roman", 40, FontStyle.Regular);
g.DrawString(aString, aFont, SystemBrushes.Highlight, 20, 30);
g.Dispose();
Vizualizarea formelor complexe
Vizualizarea formelor complexe necesita parcurgerea catorva pasi in proiectare.
Principalul obiect utilizat pentru randarea formelor complexe este o instanta a clasei
GraphicsPath. Membru al spatiului de nume System.Drawing.Drawing2D, clasa
GraphicsPath poate descrie orice fel de obiecte inchise sau multimi de forme
complexe.
Crearea unui GraphicsPath
Se utilizeaza unul din constructorii clasei GraphicsPath. Exemplu 1: constructorul fara
parametru.
GraphicsPath aPath = new Drawing2D.GraphicsPath();
Exemplul 2: constructor cu parametri care specifica un set de puncte din cadrul formei
si caracteristicile anumitor sectiuni ale formei:
GraphicsPath aPath = new GraphicsPath(new Point[]
{new Point(1, 1), new Point(38, 70), new Point(33, 20)}, new
byte[] {
(byte)PathPointType.Start, (byte)PathPointType.Line,
(byte)PathPointType.Bezier});
Dupa creare, se pot adauga figuri obiectului GraphicsPath. O astfel de figura reprezinta
o forma inchisa - forme simple (elipse, dreptunghiuri) sau complexe (curbe neregulate
s.a.).
Clasa GraphicsPath contine mai multe metode care permit adaugarea de figuri la
obiectul respectiv. Aceste metode sunt sintetizate in tabelul urmator:
Metoda

Descriere

AddClosedCurve

adauga o curba inchisa descrisa printr-un tablou de puncte

AddEllipse

adauga o elipsa

AddPath

adauga o instanta GraphicsPath la instanta curenta

AddPie

adauga o forma de tip pie

AddPolygon

adauga un poligon descris printr-un tablou de puncte

AddRectangle

adauga un dreptunghi

AddRectangles

adauga o multime de dreptunghiuri

AddString

adauga o reprezentare grafica a unui string, cu un font


specificat

Page 128 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

O figura poate fi creata si pas cu pas, prin adaugare de linii, arce si curbe (se utilizeaza
metodele din tabelul de mai jos). Primul pas in crearea figurii este aplearea metodei
GraphicsPath.StartFigure. Se adauga apoi elemente la figura respectiva, apelandu-se,
in final, metoda GraphicsPath.CloseFigure pentru inchiderea figurii. Exemplu:
GraphicsPath somePath = new GraphicsPath();
somePath.StartFigure();
// adaugare de elemente ...
somePath.CloseFigure();
O figura pentru care s-a apelat StartFigure, fara a se apela CloseFigure, va ramane
deschisa.
!
La run-time, o figura deschisa se va inchide prin adaugarea unei linii intre primul si
ultimul punct ale figurii.
Metode GraphicsPath pentru adaugarea de elemente liniare la o figura:
Metoda

Descriere

AddArc

adauga un arc

AddBezier

adauga o curba Bezier

AddBeziers

adauga o serie de curbe Bezier

AddCurve

adauga o curba descrisa de un tablou de puncte

AddLine

adauga o linie

AddLines

adauga o serie de linii conectate

Sinteza
- Graphics
- Pen, Brush, Color
- SystemPens, SystemBrushes, SystemColors
- GraphicsPath

2. Controale utilizator
Programarea Windows Forms este bazata pe controale. Controalele permit
incapsularea unui set de unitati functionale discrete si furnizeaza utilizatorului o
reprezentare grafica a acestor functionalitati. .NET Framework pune la dispozitie o
varietate de unelte si tehnici care ajuta la crearea controalelor personalizate din cadrul
aplicatiei utilizator.
Dezvoltare de aplicatii in Visual Studio .NET

Page 129 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

In .NET Framework, controale sunt clase specializate care includ cod pentru randarea
unei interfete grafice. Exista mai multe surse posibile pentru controalele utilizate in
aplicatii. Controalele incluse in Microsoft Visual Studio .NET acopera o gama larga de
functionalitati si permit dezvoltarea de aplicatii cu o serie intreaga de caracteristici. Pot
fi utilizate, de asemenea, o serie de controale implementate de alti programatori sau
pot fi folosite controale ActiveX.
Controale personalizate - privire de ansamblu
Toate controalele din .NET Framework sunt derivate direct sau indirect din clasa de
baza Control. Acesta clasa pune la dispozitie functionalitatea de baza necesara unui
control. De exemplu, clasa Control implementeaza logica tratarii input-ului utilizatorului
prin interactiunea cu tastatura si mouse-ul si logica interactiunii cu mediul Windows. In
plus, un control derivat din clasa Control contine un set de proprietati, metode si
evenimente comune tuturor controalelor. Crearea functionalitatii specifice controlului,
precum si vizualizarea grafica a acestuia sunt sarcini ce revin utilizatorului.
Exista trei tehnici de baza pentru crearea unui control:
- derivarea dintr-un control existent :
reprezinta cel mai rapid si facil mod de dezvoltare a unui control; noul control contine
toata functionalitatea controlului de baza si poate actiona ca baza pentru alte controale,
mostenind reprezentarea vizuala a controlului din care de deriveaza. Aceasta tehnica
este folosita atunci cand este necesara duplicarea functionalitatii unui control Windows
Forms si adaugarea de functionalitati specifice sau definirea unui aspect vizual nou.
Majoritatea controalelor Windows Forms pot fi utilizate drept clase de baza pentru
crearea de controale noi. Exemplu: crearea unui TextBox cu validare implicita
(functionalitate specifica) sau crearea unui Button cu colturile rotunjite (aspect vizual
specific).
- derivarea din clasa UserControl:
tehnica utilizata pentru crearea de controle care inglobeaza un numar de controale
Windows Form sub forma unei singure unitati functionale. Se deriveaza din clasa
UserControl care pune la dispozitie o functionalitate de baza, la care se pot adauga
proprietati, metode, evenimente si alte controale. Dupa adaugarea controalelor
componente, se scrie cod pentru implementarea functionalitatilor specifice. Rezultatul
este un control proiectat de utilizator, alcatuit dintr-un set de controale care se
comporta ca o singura unitate functionala. Majoritatea modificarilor vizuale aduse
controalelor componente constau in simpla configurare si repozitionare a controalelor
constituente.
- derivarea din clasa Control:
utilizata in cazul in care este necesara o interfata vizuala sau/si o functionalitate
complexa care nu pot fi implementate prin intermediul unui user-control sau a unui
control derivat. Controalele personalizate sunt derivate din clasa Control, clasa de baza
a tuturor controalelor. Pasii necesari dezvoltarii unuii astfel de control pot fi
consumatori de timp, oferind insa posibilitatea implementarii unui control personalizat,
cu functionalitate si aspect vizual specifice.

Adaugarea de membri unui control

Page 130 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Se pot adauga proprietati, metode, campuri si evenimente controalelor in aceeasi


maniera in care se adauga membri unei clase. Pot fi declarati membri cu diverse nivele
de acces, iar forma care gazduieste controlul va putea apela orice membru public al
controlului.
Proprietatile publice adaugate controalelor sunt vizualizate automat in fereastra
Properties la design-time. Deci, acestea pot fi editate si configurate de orice utilizator al
aplicatiei. Daca nu se doreste vizualizarea unei proprietati in fereastra Properties, se
seteaza atributul Browsable la false. Exemplu:
[System.ComponentModel.Browsable(false)]
public int CustomNumber
{
// cod...
}
Crearea unui control derivat
Un control derivat contine toata functionalitatea pusa la dispozitie de clasa de baza si
poate servi, de asemenea, ca baza pentru alte controale. Un control derivat se creaza
specificand un control Windows Forms drept clasa de baza pentru noul control. Acesta
pastreaza acelasi aspect si functionalitate ca si controlul de baza. Exemplu:
public class DerivedButton : System.Windows.Forms.Button
{
// implementare...
}
Adaugarea de noi functionalitati unui control derivat
Acest lucru se poate realiza prin suprascrierea membrilor clasei de baza. De exemplu,
pentru crearea unui text box care accepta numai numere ca input, se suprascrie
metoda OnKeyPress, ca in exemplul urmator:
// nu se permite transmiterea focusului unui alt
// control daca se introduc alte caractere
// decat cifre in textBox
public class NumberBox :
System.Windows.Forms.TextBox
{
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (char.IsNumber(e.KeyChar) == false)
e.Handled = true;
Dezvoltare de aplicatii in Visual Studio .NET

Page 131 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
}
Modificarea aspectului vizual al unui control
Se suprascrie motoda OnPaint. Pentru modificarea formei unui control, se seteaza
proprietatea Region a controlului in metoda OnPaint. Region este o clasa care descrie
o regiune regulata sau neregulata de pe ecran, similar unui GraphicsPath. O regiune
poate fi creata pe baza unui GraphicsPath. Exemplu - un buton care este vizualizat sub
forma unui string:
public class TextButton :
System.Windows.Forms.Button
{
protected override void OnPaint(PaintEventArgs pe)
{
System.Drawing.Drawing2D.GraphicsPath aPath = new
System.Drawing.Drawing2D.GraphicsPath();
aPath.AddString("Cool", Font.FontFamily,
(int)Font.Style, 72, new PointF(0, 0),
StringFormat.GenericDefault);
// se creaza o noua regiune pornind de la aPath
Region aRegion = new Region(aPath);
// se asigneaza regiunea proprietatii Region a controlului
this.Region = aRegion;
}
}
!
- butonul astfel creat nu este rectangular, ci are forma determinata de literele
cuvantului "Cool". Pentru a executa clic pe buton, trebuie utilizata regiunea determinata
de literele acestui cuvant;
- exista controale pentru care nu se lanseaza evenimentul Paint, fiind desenate de
forma parinte.
Crearea unui user-control
Un astfel de control consta in unul sau mai multe controale legate sub forma unei
singure unitati. Controalele componente pot fi adaugate controlului utilizator la
design-time. Un control utilizator poate fi adaugat la proiect utilizand optiunea Add User
Control din meniul Project.
Exemplu, crearea unui control utilizator format din doua TextBox-uri si un Label care
Page 132 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

afiseaza automat suma celor doua numere introduse in TextBox-uri. Pentru aceasta,
se suprascrie metoda OnKeyPress pentru fiecare TextBox:
protected override void OnKeyPress(object sender,
KeyPressEventArgs e)
{
// se verifica daca s-a tastat o cifra
if (char.IsNumber(e.KeyChar) == false)
e.Handled = true;
Label1.Text = (int.Parse(TextBox1.Text) +
int.Parse(TextBox2.Text)).ToString();
}
La crearea unui control utilizator in Visual Studio .NET, controalele constituente sunt
tratate implicit ca private. Pentru a permite altor utilizatori sa modifice proprietatile
controalelor constitutive, acestea trebuie expuse prin intermediul proprietatilor
controlului utilizator parinte. Exemplu:
public Color ButtonColor
// proprietate a controlului parinte
// Button1 este un constituent al acestuia
{
get
{
return Button1.BackColor;
}
set
{
Button1.BackColor = value;
}
}
Expunerea completa a unui control constituent se poate efectua prin intermediul
proprietatii Modifiers, disponibila in fereastra Properties, numai in faza de design.
Crearea unui control custom
Controalele de acest tip confera cel mai inalt nivel de configurabilitate si personalizare,
dar sunt si cele mai consumatoare de timp in faza de dezvoltare. Deoarece clasa
Control nu furnizeaza o reprezentare vizuala, utilizatorul are sarcina de a scrie cod
care sa redea vizualizarea grafica a controlului. In cazurile in care este necesara o
reprezentare vizuala complexa, aceasta faza poate ocupa cea mei mare perioada de
Dezvoltare de aplicatii in Visual Studio .NET

Page 133 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

timp in procesul de dezvoltare a controlului.


Procesul vizualizarii unui control pe o suprafata se numeste painting. Atunci cand un
control primeste instructiuni de desenare, se lanseaza evenimentul Paint. Aceasta
determina executia handlerelor evenimentului Paint. Pentru clasa Control, handlerul
implicit al evenimentului Paint este metoda OnPaint.
Metoda OnPaint are un singur argument, o instanta PaintEventArgs. Acesta clasa
contine informatii despre suprafata de desenare disponibila controlului.
Membri PaintEventArgs:
- Graphics - un obiect Graphics care reprezinta suprafata de desenare a controlului
- ClipRectangle - o suprafata rectangulara disponibila controlului pentru desenare. La
prima desenare a controlului, obiectul ClipRectangle defineste marginile intregului
control. Uneori, anumite regiuni ale controlului pot fi acoperite de alte controale. La
redesenarea controlului, obiectul ClipRectangle reprezinta numai regiunea care trebuie
redesenata, fiind folosit, deci, pentru determinarea marimii controlului. Coordonatele, in
interiorul unui control, sunt masurate relativ la coltul din stanga sus, considerat drept
origine. Exemplu de custom-control:
// o elipsa
protected override void OnPaint(PaintEventArgs e)
{
Brush aBrush = new SolidBrush(Color.Red);
Rectangle clientRectangle = new
Rectangle(new Point(0,0), this.Size);
e.Graphics.FillEllipse(aBrush, clientRectangle);
}
La redimensionarea unui control, membrul ClipRectangle este modificat, dar controlul
nu este neaparat redesenat. Pentru redesenarea controlului la fiecare redimensionare,
se apeleaza metoda Control.SetStyle pentru a seta flagul ResizeRedraw la true. Acest
apel trebuie plasat in constructor. Exemplu:
SetStyle(ControlStyles.ResizeRedraw, true);
Ca alternativa, se poate apela metoda Refresh, ori de cate ori se doreste redesenarea:
Refresh();
Sinteza:
- controale derivate (derived controls)
- controale utilizator (user controls)
- controale personalizate (custom controls)

Page 134 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

3. Gestionarea, utilizarea, configurarea controalelor


Adaugarea controalelor la Toolbox
Dupa crearea unui control, acesta va putea fi utilizat in proiecte de dezvoltare.
Adaugarea unui control in Toolbox va permite utilizarea acestuia in proiecte.
Adaugarea unui control la Toolbox se face prin intermediul optiunii Customize Toolbox.
(.NET Framework Controls, Browse, se alege fisierul DLL sau EXE asociat controlului).
Controlul este, in urma selectarii fisierului asociat, adaugat in lista afisata de optiunea
Customize Toolbox. Controlul este adaugat astfel la Toolbox.
In Visual Studio .NET 2003, controalele utilizator construite ca parte a unui proiect sunt
adaugate automat in Toolbox, in lista de controale My UserControls. Pot fi adaugate si
controale derivate sau controale custom folosind procedura de mai sus.
Asocierea unui Toolbox Bitmap unui control
Visual Studio .NET asociaza un icon implicit care apare in dreptul controlului in
Toolbox. Se poate specifica un icon dorit, in format bitmap. Pentru aceasta se
utilizeaza clasa ToolboxBitmapAttribute. Acasta este o clasa specializata bazata pe
atribute, o clasa care contine metadate despre un control. Folosind
ToolboxBitmapAttribute, se poate specifica fie un bitmap de dimensiune 16 pe 16, fie
type. Daca se specifica type, controlul va avea asociat acelasi bitmap ca si controlul
.NET avand acel tip (type) specificat.
Exemple care ilustreaza cele doua situatii:
// icon specificat printr-un fisier bitmap
[ToolboxBitmap(@"C:\some.bmp")]
public class SomeUserControl : Control
{
// implementare...
}
[ToolboxBitmap(typeof(Label))]
public class UserLabelControl : Label
{
// implementare...
}
Debugging-ul unui control
In orice proiect de dezvoltare, poate aparea necesitatea debugging-ului controalelor.
Deoarece acestea nu sunt proiecte de sine statatoare, ele trebuie gazduite in cadrul
unei forme Windows pe durata debugging-ului.
Dezvoltare de aplicatii in Visual Studio .NET

Page 135 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Controlul trebuie construit (built) inainte de a putea fi testat. Odata ce proiectul care
contine controlul a fost construit, controlul poate fi adaugat la o forma si testat ca in
cazul oricarui alt proiect.
In cazul in care controlul face parte dintr-un proiect executabil, precum un proiect
Windows Forms, se poate adauga o noua forma la proiect care sa gazduiasca
controlul. In cazul in care controlul face parte dintr-un proiect non-executabil, cum ar fi
o librarie de clase sau un control Windows, trebuie creat un proiect aditional pentru a
putea testa controlul (se adauga proiectul continand controlul ca referinta a noului
proiect creat - Solution Explorer - References - Add Reference ).
Gazduirea unui control in Internet Explorer
Orice control Windows Forms poate fi incarcat in Internet Explorer; pentru a profita de
aceasta posibilitate, se creaza pagini HTML care contin controale Windows Forms.
Pentru a putea incarca un control in Internet Explorer, acesta trebuie instalat in Global
Assembly Cache (vezi cursul 10...) sau trebuie plasat in acelasi director virtual in care
se gaseste pagina HTML care utilizeaza controlul.
Adaugarea unui control Windows Forms intr-o pagina HTML se efectueaza utilizand
tagul <OBJECT>. Acest tag specifica faptul ca un obiect compilat va fi inserat in
pagina. Tagul <OBJECT> examineaza proprietatea classid a obiectului pentru a
identifica tipul obiectului care va fi incarcat. Deci, in proprietatea classid se va specifica
propriul control Windows Forms.
classid-ul unui control Windows Forms consta in doua parti. Prima parte este calea
catre fisierul care contine controlul, cea de-a doua este numele complet al controlului.
Separarea celor doua parti se face utilizand caracterul #. Exemplu: utilizarea tagului
<OBJECT> pentru un control din fisierul ControlLibraryExample.dll (aflat in acelasi
director ca si pagina HTML) avand numele ControlLibraryExample.firstControl:
<OBJECT id="firstControl"
classid="http:ControlLibraryExample.dll#ControlLibraryExample.firstControl
VIEWASTEXT>
</OBJECT>
Sinteza
- adaugarea controalelor utilizator la Toolbox prin intermediul optiunii Customize
Toolbox
- asocierea unui bitmap controalelor utilizand clasa ToolboxBitmapAttribute
- debugging-ul controalelor
- incarcarea controalelor in Internet Explorer utilizand tagul <OBJECT>

Page 136 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

4. Atribute
Atributele sunt entitati din program utilizate pentru a asocia informatii, cum ar fi
adnotari, tipurilor C# definite de utilizator. Aceste informatii sunt arbitrare, adica nu sunt
dependente de limbaj in sine, utilizatorul avand libertatea de a crea si asocia informatii
de orice tip.
Utilizari:
- furnizarea de informatii la design-time (documentatii)
- furnizarea de informatii la run-time (de exemplu numele unei coloane dintr-o tabela)
- stabilirea de comportamente la run-time (stabilirea caracteristicilor unei entitati din
program, configurari etc)
Definirea atributelor
Un atribut este, de fapt, o clasa derivata din clasa System.Attribute.
Exemplu:
public class FirstAttribute: Attribute
{
public FirstAttribute(string s)
{
// cod...
}
// alte campuri, proprietati, metode...
}
Aplicare:
[First("John")] // lipseste prefixul Attribute
public class Test
{
// clasa Test are asociat atributul First,
cu valoarea "John"
}
Interogarea atributelor
Se utilizeaza mecanismul de Reflection - determinarea dinamica la run-time a
caracteristicilor tipurilor dintr-o aplicatie. Exemplu: determinarea listei tuturor claselor,
tipurilor si metodelor definite intr-o aplicatie.
Dezvoltare de aplicatii in Visual Studio .NET

Page 137 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Atribute asociate claselor:


- se asociaza atributul
- interogarea se executa folosind metoda GetCustomAttributes din clasa Type:
...
Type t = typeof(MyAttribClass)
// clasa careia i se aplica atributele
foreach (Attribute attr in t.GetCustomAttributes(true))
// do something
...
Atribute asociate metodelor
- se aplica atributele metodei.
Exemplu:
...
[InputMethod]
public ReadNumbers()
{
...
}
- se interogheaza atributele folosind metoda GetMethods din clasa Type si, apoi,
metoda GetCustomAttributes din clasa MethodInfo.
Atribute asociate campurilor
- se aplica atributele campului.
Exemplu:
...
[InputField("Popescu")]
public string nume;
{
...
}
- se interogheaza atributele folosind metoda GetFields din clasa Type si, apoi, metoda
GetCustomAttributes din clasa FieldInfo.
Exista, desigur, un set de alte utilizari si aspecte legate de utilizarea atributelor. De
Page 138 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

retinut este ca atributele furnizeaza practic facilitati nelimitate, fiind foarte utile in faza
de reflection si introspectie a aplicatiei.

Dezvoltare de aplicatii in Visual Studio .NET

Page 139 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 9. Programare folosind fire de executie - VIII


1. Fir de executie - definitie, abordare .NET
Framework
Un fir de executie este unitatea minimala (atomul) careia un procesor ii aloca timpi de
executie. Mecanismul gestionarii firelor de executie este urmatorul:
- procesorul executa un thread atat timp cat mai exista timp alocat;
- dupa scurgerea timpului, firului de executie curent ii este salvat contextul (registri,
stiva, etc);
- procesorul restaureaza contextul urmatorului fir de executie (firele de executie
suspendate sunt pastrate intr-o coada)
. Deoarece unitatile de timp alocate fiecarui fir de executie sunt mici (marimea lor
depinde de sistemul de operare si de procesor), exista impresia unor executii paralele
chiar si pe o masina cu un singur procesor.
Fire de executie
Clasa prin care sunt abstractizate firele de executie .NET este
System.Threading.Thread. Aceasta clasa pune la dispozitie metode si proprietati
pentru crearea, suspendarea, trezirea sau distrugerea unui fir de executie. Mai mult,
sunt permise operatii de control a starii sau de planificare a unui thread.
Un proces poate crea unul sau mai multe fire de executie care sa execute o sectiune
din codul programului asociat procesului. Pentru a specifica codul programului executat
de un thread, se utilizeaza un delegat ThreadStart.
Pe durata existentei sale, un thread se gaseste intotdeauna in una sau mai multe din
starile definite de ThreadState. Object.GetHashCode identifica firele de executie
managed. Pe durata de viata a unui thread, nu vor exista coliziuni (in sens hash) cu
alte fire de executie, indiferent de domeniul de aplicatie utilizat pentru a obtine valoarea
hash.
Application Domain
Un AppDomain este un proces logic in cadrul unui proces fizic. La formarea unui
AppDomain se creaza un fir de executie, dar la un moment dat, in cadrul unui
AppDomain pot exista mai multe fire (derivate in cele din urma din firul initial).
Dintr-un AppDomain pot fi apelate metode sau invocate obiecte care fac parte dintr-un
alt AppDomain, spre deosebire de platforma Win32, in care un thread face parte
dintr-un singur proces si nu poate apela o metoda dintr-un thread din alt proces (vezi
clasa AppDomain).
Exemplu: vezi resurse, curs 8.

Page 140 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

2. Mai multe despre clasa Thread


Membri ai clasei Thread
IsAlive - proprietate, contine o valoare care indica starea executiei firului curent
IsBackground - proprietate, contine o valoare care indica daca firul se executa sau
nu in background
Name - proprietate, contine numele firului de executie
Priority - proprietate, stabileste prioritatea firului de executie; valorile posibile sunt
continute de enumerarea Thread.Priority
Priority - proprietate, enumerare cu urmatoarele valori: AboveNormal,
BelowNormal, Highest, Lowest, Normal; valoarea implicita este Normal; ordinea
planificarii firelor: Highest, AboveNormal, Normal, BelowNormal, Lowest
ThreadState - proprietate, enumerare care contine valori indicand starile firului de
executie curent
abort - metoda, stopeaza firul de executie, lansand o exceptie ThreadAbortException
GetDomain - metoda, returneaza o instanta AppDomain, reprezentand domeniul
curent, in care ruleaza firul de executie
Interrupt - metoda, intrerupe un thread aflat in starea WaitSleepJoin
Join - metoda, blocheaza firul apelant, pana la terminarea unui alt fir
Resume - metoda, reia executia unui fir, suspendat anterior
Sleep - metoda, blocheaza executia firului curent pentru un numar specificat de
milisecunde
Start - metoda, schimba starea firului la valoarea ThreadState.Running
Suspend - metoda, suspenda firul curent

Dezvoltare de aplicatii in Visual Studio .NET

Page 141 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 10. .NET Framework Advanced - IX


1. Functionalitati avansate de printare
Printarea (tiparirea) datelor si documentelor constituie o sarcina comuna oricarui mediu
de dezvoltare de aplicatii complexe. .NET Framework pune la dispozitie componenta
PrintDocument pentru a facilita tiparirea si pentru a gazdui alte clase care ofera suport
si posibilitati de configurare a setarilor printerului.
Printarea va fi, fara indoiala, o componenta indispensabila a oricarei aplicatii complexe.
Cu toate ca dispozitivele electronice de stocare a datelor se bucura de o popularitate
crescanda, materialele tiparite nu vor putea fi inlocuitere in viitorul apropiat. Deci, orice
programator trebuie sa fie capabil sa implementeze propriile functionalitati de tiparire in
aplicatiile pe care le dezvolta. .NET Framework ofera clase si componente care permit
implementarea rapida si facila in programe a suportului de printare.
Componenta PrintDocument
Un document care urmeaza si/sau va fi tiparit este reprezentat in .NET Framework prin
componenta PrintDocument. Desi aceasta nu are o reprezentare vizuala, ea poate fi
gasita in tabul Windows Forms din Toolbox, de unde poate fi adaugata la aplicatie in
mod design.
Un obiect PrintDocument incapsuleaza toata informatia necesara printarii unei pagini.
- proprietatea PrinterSettings contine informatii despre functionalitatea si setarile
printerului;
- proprietatea DefaultPageSettings incapsuleaza configurarile pentru printarea unei
pagini;
- proprietatea PrintController descrie modalitatea in care fiecare pagina este gestionata
in procesul de printare.
Prin intermediul acestor proprietati, se poate atinge un nivel avansat de control asupra
procesului de printare.
Crearea unui obiect PrintDocument
- in mod design - prin adaugarea unei instance PrintDocument direct din Toolbox
- utilizand scrierea de cod
// using System.Drawing.Printing;
PrintDocument firstPrintDocument = new PrintDocument();
O instanta PrintDocument creata in cod este configurata automat la setarile implicite
ale printerului sistemului.
Cum functioneaza printarea?
Page 142 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

In modelul de printare .NET Framework, continutul care va fi printat este furnizat direct
de logica aplicatiei. Un proces de printare este initiat utilizand metoda
PrintDocument.Print. Aceasta starteaza procesul si lanseaza unul sau mai multe
evenimente PrintPage. Daca nu exista metode client pentru tratarea acestui
eveniment, printarea nu va avea loc. Furnizand o metoda care sa trateze evenimentul,
se poate specifica continutul care va fi printat.
Daca continutul care va fi printat contine mai multe pagini, se va lansa cate un
eveniment PrintPage pentru fiecare pagina din procesul de printare. Acest lucru
cauzeaza event-handlerului asociat evenimentului PrintPage sa se execute de mai
multe ori. Deci, aceasta metoda trebuie sa implementeze functionalitati care sa
gestioneze procesul de printare si sa asigure faptul ca sunt printate, succesiv, paginile
anumit document. Altfel, prima pagina a documentului va fi printata de mai multe ori.
Evenimentul PrintPage
Evenimentul PrintPage este principalul eveniment implicat in printarea documentelor.
Pentru transmiterea efectiva a continutului care va fi printat catre printer, trebuie
implementata o procedura de tratare a acestui eveniment, in cadrul careia sa se scrie
cod pentru redarea continutului care va fi printat in formatul dorit. Toate obiectele si
informatiile necesare transmiterii continutului catre printer sunt incapsulate in obiectul
PrintPageEventArgs, primit ca parametru de event handler. Acest obiect contine
proprietatile listate in tabelul urmator:
Proprietate

Descriere

Cancel

indica daca un proces de printare va fi sau nu


anulat

Graphics

obiectul Graphics utilizat pentru redarea


continutului paginilor care vor fi printate

HasMorePages

gestioneaza o valoare indicand daca vor fi


printate pagini aditionale

MarginBounds

returneaza un obiect Rectangle care reprezinta


portiunea din pagina obtinuta excluzand
marginile

PageBounds

returneaza un obiect Rectangle care reprezinta


intreaga suprafata a paginii

PageSettings

gestioneaza setarile PageSettings pentru


pagina curenta

Continutul care va fi printat este redat prin intermediul obiectului Graphics continut de
instanta PrintPageEventArgs. In acest caz, pagina printata se va comporta ca o forma,
ca un control sau ca orice alta suprafata de desenare care poate fi reprezentata
printr-un obiect Graphics. Pentru a reda continutul, se utilizeaza aceleasi metode ca in
cazul utilizarii formelor. Exemplu, printarea unei elipse:
// acesta metoda va trata evenimentul PrintPage
public void PrintEllipse(object sender,

Dezvoltare de aplicatii in Visual Studio .NET

Page 143 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawEllipse(Pens.Black, e.MarginBounds);
}
Proprietatile MarginBounds si PageBounds reprezinta dimensiunile care definesc
suprafata paginii. Se poate specifica ca printarea sa aiba loc in interiorul limitelor
paginii calculand coordonatele de printare pe baza dreptunghiului definit de
MarginBounds. Printarea care se va efectua inafara limitelor marginilor, ca in cazul
antetelor sau notelor din subsolul paginilor, poate fi specificata calculand coordonatele
de printare pe baza dreptunghiului definit de PageBounds. Similar desenarii pe ecran,
coordonatele de printare sunt specificate, implicit, in pixeli.
Se poate specifica faptul ca un proces de printare contine mai multe pagini utilizand
proprietatea HasMorePages. Implicit, aceasta proprietate este setata la false. Atunci
cand, prin logica programului, se stabileste ca vor fi mai multe pagini de printat in
cazdrul unui astfel de proces, se seteaza aceasta proprietate la valoarea true. Atunci
cand ultima pagina este printata, proprietatea trebuie resetata la false.
!
Metoda care trateaza evenimentul PrintPage trebuie sa tina cont de numarul de pagini
din proces, in caz contrar, putandu-se obtine comportamente nedorite ale aplicatiei. De
exemplu, daca se omite resetarea proprietatii HasMorePages la valoarea false dupa ce
ultima pagina a fost printata, aplicatia va continua sa lanseze evenimente PrintPage.
Un proces de printare poate fi oprit, fara a fi necesara terminarea printarii paginii
curente, prin setarea proprietatii Cancel la valoarea true.
Crearea unei metode de tratare a evenimentului PrintPage: prin dublu-clic pe instanta
PrintDocument in mod design sau prin declararea in codul programului.
Printarea
Initierea unui proces de printare se realizeaza, simplu, prin apelul metodei
PrintDocument.Print. Ramane de indeplinit sarcina selectarii continutului care este
trimis la printer.
Printarea elementelor grafice
Acesta implica randarea elementelor grafice pe ecran. Se utilizeaza obiectul Graphics
din cadrul instantei PrintPageEventArgs pentru a randa elementele grafice pe ecran.
Se pot printa forme simple sau forme complexe, utilizand System.Drawing sau
System.Drawing.Drawing2D.
Exemplu: printarea unei forme complexe utilizand un obiect GraphicsPath:
// event handler pentru PrintPage
public void PrintGraphics(object sender,
System.Drawing.Printing.PrintPageEventArgs e)

Page 144 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

{
System.Drawing.Drawing2D.GraphicsPath myPath = new
System.Drawing.Drawing2D.GraphicsPath();
myPath.AddPolygon(new Point[] {new Point(1, 1),
new Point(12, 55), new Point(34, 8), new Point(52, 53),
new Point(99, 5)});
myPath.AddRectangle(new Rectangle(33, 43, 20, 20));
e.Graphics.DrawPath(Pens.Black, myPath);
}
Pentru a printa elemente grafice care ocupa mai multe pagini, se divide, prin logica
programului, continutul care va fi printat. De exemplu, urmatoarea metoda va desena o
elipsa pe doua pagini:
bool FirstPagePrinted = false;
// event handler pentru PrintPage
public void PrintBigEllipse(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
if (FirstPagePrinted == false)
{
FirstPagePrinted = true;
e.HasMorePages = true;
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(0, 0,
e.PageBounds.Width, e.PageBounds.Height * 2));
}
else
{
e.HasMorePages = false;
FirstPagePrinted = false;
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(0,
-(e.PageBounds.Height), e.PageBounds.Width,
e.PageBounds.Height * 2));
}
}

Dezvoltare de aplicatii in Visual Studio .NET

Page 145 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Acest exemplu utilizeaza variabila FirstPagePrinted pentru a stabili pagina care se


printeaza: prima sau a doua pagina. ! Acesta pagina este declarata inafara procedurii.
Daca aceasta metoda ar fi fost declarata in interiorul metodei, s-ar fi reinitializat la
fiecare apel al metodei, returnand intotdeauna false. Dupa ce programul printeaza
fiecare pagina, se redeseneaza imaginea de fiecare data, schimband pozitia
dreptunghiului care incadreaza elipsa, pentru a orienta corect elipsa pe cele doua
pagini.
Printarea textelor
Un text se printeaza in aceeasi maniera in care este redat pe ecran. Se utilizeaza
metoda Graphics.DrawString pentru a trimite textul catre printer. In mod uzual, se
specifica un font pentru a randa textul, textul de randat, un obiect Brush si
coordonatele la care se printeaza. De exemplu:
Font afont = new Font("Arial", 36, FontStyle.Regular,
GraphicsUnit.Pixel);
string Hello = "Hello Soccer Team!";
e.Graphics.DrawString(Hello, afont, Brushes.Red, 50, 50);
!
La printarea textului, trebuie eliminata posibilitatea printarii inafara marginilor paginii.
Daca se incearca acest lucru, continutul dinafara marginilor paginii nu va fi printat.
Printarea textelor pe mai multe linii
La printarea mai multor linii de text, ca in cazul tablourilor de stringuri sau a liniilor citite
din fisiere text, trebuie inclusa in program o logica de calculare a spatierii dintre linii. Se
poate calcula numarul liniilor de pe o pagina impartind inaltimea spatiului de printare la
inaltimea fontului. Similar, se poate calcula pozitia fiecarei linii multiplicand numarul
liniei cu inaltimea fontului. Exemplu: printarea unui tablou de stringuri myStrings:
// pozitia curenta din tablou
// declarare inafara procedurii
int ArrayCounter = 0;
private void PrintStrings(object sender, PrintPageEventArgs e)
{
// variabile care vor gestiona
// spatierea si paginarea
float LeftMargin = e.MarginBounds.Left;
float TopMargin = e.MarginBounds.Top;
float MyLines = 0;

Page 146 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

float YPosition = 0;
int Counter = 0;
string CurrentLine;
// numarul de linii pe pagina
MyLines = e.MarginBounds.Height/myFont.GetHeight(e.Graphics);
// printeaza fiecare linie,
// oprindu-se la sfarsitul fiecarei pagini
while (Counter < MyLines and ArrayCounter <=
myStrings.GetUpperBound(0))
{
CurrentLine = myStrings[ArrayCounter];
YPosition = TopMargin + Counter *
myFont.GetHeight(e.Graphics);
e.Graphics.DrawString(CurrentLine, myFont, Brushes.Black,
LeftMargin, YPosition, new StringFormat());
Counter +=1;
ArrayCounter +=1;
}
// daca mai sunt linii de printat,
// se trece la o alta pagina
if (!(ArrayCounter == myStrings.GetUpperBound(0)))
e.HasMorePages = true;
else
e.HasMorePages = false;
}
Daca printerul ofera suport pentru folosirea culorilor, aplicatia trebuie sa tina cont de
acest lucru. Proprietatea PrinterSettings.SupportsColor poate fi consultata pentru a
determina daca printerul suporta sau nu utilizarea culorilor. Pentru a forta printarea
alb-negru, chiar daca printerul este color, se seteaza proprietatea
DefaultPageSettings.Color la false. Exemplu:
// using System.Drawing,
// System.Drawing.Drawing2D si System.Drawing.Printing...
Brush BrushOne;
Brush BrushTwo;
Dezvoltare de aplicatii in Visual Studio .NET

Page 147 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

if (printDocument1.PrinterSettings.SupportsColor == true)
{
// color...
BrushOne = Brushes.Red;
BrushTwo = Brushes.Blue;
}
else
{
// alb-negru...
BrushOne = new HatchBrush(HatchStyle.DarkVertical, Color.Black);
BrushTwo = new HatchBrush(HatchStyle.DashedHorizontal,
Color.Black);
}
PrintPreviewControl
.NET Framework implementeaza un control PrintPreviewControl care permite
efectuarea unei previzualizari grafice a continutului care va fi printat inainte ca acesta
sa fie trimis catre printer. Controlul PrintPreviewControl se gaseste in tabul Windows
Forms din Toolbox, putandu-se adauga o instanta a sa prin drag-and-drop pe o forma.
Pentru a putea previzualiza o pagina, controlul PrintPreviewControl trebuie asociat unei
instante PrintDocument. Aceasta asociere se creaza prin setarea proprietatii
PrintPreviewControl.Document:
aPrintPreview.Document = aPrintDocument;
Din acest moment, controlul PrintPreviewControl va putea afisa continutul care va fi
printat. Acest lucru se realizeaza prin apelarea metodei care trateaza evenimentul
PrintDocument.Print si preluand outputul grafic al acelei metode. Acest output este
apoi redat prin intermediul controlului PrintPreviewControl.
Pe masura ce conditiile din program se modifica, docuentul printat se poate modifica,
de asemenea. Actualizarea previzualizarii se poate realiza prin apelarea metodei
InvalidatePreview:
aPrintPreview.InvalidatePreview();
O alta proprietate importanta a controlului PrintPreviewControl este proprietatea Zoom.
Valoarea 1 determina vizualizarea la dimensiunea maxima. O valoare fractionara va
reduce imaginea, iar o valoare supraunitara o va mari.
PrintPreviewDialog
Acest control reprezinta o resursa pentru previzualizarea documentelor printate si
crearea de previzualizari personalizate. .NET Framework implementeaza un control
Page 148 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

PrintPreviewDialog standard care expune o serie de functionalitati uzuale legate de


previzualizarea continutului care va fi printat.
Odata vizualizat, controlul PrintPreviewDialog ofera posibilitatea vizualizarii mai multor
pagini, redimensionarii sau printarii documentului. Ca in cazul oricarei alte forme,
vizualizarea unei ferestre de dialog PrintPreviewDialog se realizeaza prin apelarea
metodelor Show sau ShowDialog. Exemplu: asocierea unei componente
PrintPreviewDialog cu o componenta PrintDocument si vizualizarea ferestrei de dialog
PrintPreviewDialog.
// using System.Drawing.Printing;
PrintDocument aDocument = new PrintDocument();
PrintPreviewDialog aDialog = new PrintPreviewDialog();
aDialog.Document = aDocument;
aDialog.ShowDialog();
Configurarea printarii
Interfata .NET Framework care contine functionalitatile pe printare pune la dispozitie o
gama bogata de optiuni de configurare. Proprietatea PrintDocument.PrinterSettings
contine informatii legate de dispozitivele de printare disponibile in sistem. Proprietatea
PrintDocument.DefaultPageSettings contine setarile legate de paginare care vor fi
utilizate implicit. La crearea unui obiect PrintDocument, configuratia implicita a
printerului implicit este incarcate in proprietatea PrinterSettings, iar setarile implicite de
paginare sunt incarcate in proprietatea DefaultPageSettings. Deci, se poate crea si
executa un proces de printare fara a modifica configuratia implicita.
PrintDialog
Fereastra de dialog PrintDialog permite utilizatorilor sa seteze proprietatea
PrinterSettings a unui obiect PrintDocument la run-time.
// vizualizarea ferestrei PrintDialog
PrintDialog1.ShowDialog();
Un PrintDialog trebuie asociat unui obiect PrintDocument. La vizualizare, fereastra
PrintDialog este legata de proprietatea PrinterSettings a obiectului PrintDocument
specificat de proprietatea Document si furnizeaza o interfata grafica pentru a permite
utilizatorului stabilirea unei configuratii. Exemplu:
// using System.Drawing.Printing;
PrintDocument aDocument = new PrintDocument();
PrintDialog aDialog = new PrintDialog();
aDialog.Document = myDocument;
aDialog.ShowDialog();
PageSetupDialog
Dezvoltare de aplicatii in Visual Studio .NET

Page 149 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Fereastra PageSetupDialog este similara ferestrei PrintDialog, furnizand i interfata


grafica care permite utilizatorilor configurarea setarilor legate de paginare la run-time.
Se poat modifica orientarea in pagina, formatul utilizat, marginile, s.a.
Exemplu:
// using System.Drawing.Printing;
PrintDocument aDocument = new PrintDocument();
PageSetupDialog aDialog = new PageSetupDialog();
aDialog.Document = aDocument;
aDialog.ShowDialog();
Configurarea PageSettings la run-time
Setarile de paginare pot fi modificate la run-time utilizand proprietatea
PrintPageEventArgs.PageSettings. Acesta proprietate contine setarile asociate
paginilor care sunt printate. Modificarile efectuate acestei proprietati sunt utilizate
pentru a printa pagina curenta, dar nu vor fi pastrate pentru celelalte pagini.
Exemplu: modificarea formatului unei pagini la landscape.
// variabila e este o instanta
// PrintPageEventArgs
e.PageSettings.Landscape = true;
Sinteza
- un document printat este reprezentat de o instanta a clasei PrintDocument
- proprietatea PrinterSettings specifica setarile printerului
- proprietatea DefaultPageSettings specifica setarile implicite de paginare
- printarea unui document: prin apelul metodei PrintDocument.Print
- Evenimentul PrintPage lansat la apelul metodei PrintDocument.Print
- obiectul PrintPageEventArgs contine toate informatiile si functionalitatea necesare
randarii outputului catre printer
- controlul PrintPreviewControl permite previzualizarea unui document care va fi printat
- fereastra de dialog PrintPreviewDialog
- PrintDialog si PageSetupDialog

2.Facilitati de help in aplicatii Visual Studio .NET


Adesea, existenta unei documentatii elaborate in program este foarte importanta.
Page 150 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Furnizarea de help in aplicatii permite utilizatorilor sa inteleaga mai usor aplicatia, ceea
ce conduce la cresterea productivitatii.
Pentru aplicatii complexe si dificile, este necesara scrierea de help built-in , integrat in
aplicatie. Help-ul poate fi scris in fisiere HTML care contin un set informatii accesibile
prin linkuri sau in fisiere CHM (Compressed HTML) care se pot crea cu Microsoft
HTML Help Workshop. Ambele abordari permit vizualizarea dinamica a informatiile
accesibile prin linkuri.
Clasa Help
O aplicatie poate vizualiza fisiere HTM sau CHM prin intermediul clasei Help. Aceasta
clasa incapsuleaza HTML Help 1 engine si pune la dispozitie metode statice care
permit vizualizarea fisierelor de help. Cele doua metode expuse de clasa Help sunt
ShowHelp si ShowHelpIndex.
Metoda ShowHelp afiseaza un fisier de help pentru un anumit control. Controlul care
contine fereastra de dialog HelpDialog trebuie sa fie vizualizat pentru a putea afisa
fisierul de help specificat printr-un URL. URL-ul poate fi un fisier (de exemplu,
C:\fileHelp.htm) sau un HTTP URL (de exemplu,
http://someserver.com/someHelp.htm). Pentru ca metoda ShowHelp este statica, nu
este necesara crearea unei instante a clasei Help pentru a o putea utiliza. De fapt,
clasa Help nu poate fi instantiata.
Exemplu:
Help.ShowHelp(someForm, @"C:\someHelpFile.htm");
Aditional, se poate specifica un parametru HelpNavigator. Acesta specifica care dintre
elementele fisierului de help vor fi vizualizate. Acest parametru poate fi setat la
TableOfContents, Find, Index sau Topic. Se poate specifica, de asemenea, un cuvant
de cautare, ca in exemplul urmator:
Help.ShowHelp(someForm, @"C:\someHelpFile.htm", "HelpMenu");
Clasa Help contine metoda ShowHelpIndex care vizualizeaza indexul unui fisier de
help specificat. Apelul metodei ShowHelpIndex se executa in aceeasi maniera ca si
metoda ShowHelp.
Help.ShowHelpIndex(someForm, @"C:\someHelpFile.htm");
Metodele clasei Help pot fi apelate ca raspuns la o varietate de evenimente lansate de
interactiunea cu interfata utilizator. De exemplu, mai multe aplicatii includ un meniu de
Help sau meniuri care pot fi accesate prin clic dreapta pe un anumit control. De aceea,
aplicatiile trebuie sa ofere facilitati de help organizate intr-o maniera logica si eficienta.
Componenta HelpProvider
Componenta HelpProvider permite furnizarea de help pentru controalele din interfata
utilizator. HelpProvider este un extender provider; deci, coordoneaza si mentine
proprietati pentru fiecare control adaugat pe o forma. Se poate specifica un HelpString
pentru fiecare control de pe forma. Acest string este vizualizat atunci cand controlul
Dezvoltare de aplicatii in Visual Studio .NET

Page 151 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

primeste focusul si se tasteaza F1. Se poate specifica, de asemenea, un


HelpNameSpace care specifica URL-ul fisierului de help asociat HelpProvider-ului.
Componenta HelpProvider asociaza trei proprietati fiecarui control de pe forma parinte:
- HelpString
- HelpKeyWord
- HelpNavigator
Aceste proprietati pot fi setate in fereastra Properties pentru fiecare control sau prin
scrierea de cod:
aHelpProvider.SetHelpString(Button1, "Apasati si veti fi
multumit...");
Daca proprietatea HelpNameSpace nu este setata, se va vizualiza stringul continut de
HelpString si celelalte doua proprietati sunt ignorate. Daca proprietatea
HelpNameSpace este setata la un fisier de help, se vizualizeaza fisierul de help
specificat utilizand parametrii proprietatilor HelpNavigator si HelpKeyword. Proprietatea
HelpNavigator poate fi setata la una din urmatoarele valori:
- TableOfContents - vizualizeaza scheletul continutului help-ului
- Find - afiseaza pagina de cautare
- Index - vizualizeaza indexul
- Topic - afiseaza un anumit element de help (topica)
- AssociatedIndex - vizualizeaza indexul unei topici specificate
- KeywordIndex - afiseaza rezultatul cautarii dupa un anumit cuvant cheie
Daca este setata proprietatea HelpNameSpace, nu se mai afiseaza stringul din
HelpString atunci cand se apasa tasta F1, dar acesta poate fi returnat prin alte
modalitati. Se poate obtine HelpString-ul asociat unui anumit control prin apelarea
metodei HelpProvider.GetHelpString ca in exemplul urmator:
someHelpProvider.GetHelpString(Button1);
Sinteza:
- clasa Help
- metoda Help.ShowHelp
- componenta HelpProvider
- proprietatile HelpString, HelpKeyWord si HelpNavigator
- HelpNameSpace

Page 152 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

3. Globalizare si localizare
.NET Framework pune la dispozitia programatorilor un suport bogat pentru scrierea de
aplicatii accessibile global. Se pot crea aplicatii care se adapteaza la diverse limbaje,
formate monetare, calendaristice sau alte informatii legate de cultura.
In cazul dezvoltarii de aplicatii pentru o companie care face afaceri pe plan
international, trebuie avut in vedere faptul va vor exista utilizatori provenind dintr-o
variatate de culturi. Utilizatorii din anumite regiuni ale lumii pot fi nefamiliarizati cu
standardele legate de monede sau date calendaristice din tara din care provine
dezvoltatorul aplicatiei, sau nu pot intelege limba engleza, de exemplu. Integrand
suport international in aplicatii, se largeste aria de utilizare a aplicatiei.
Globalizare si localizare
Globalizarea si localizarea sunt procese interdependente dar diferite. Globalizarea
implica aplicarea formatarii datelor existente pe baza specificului unei anumite culturi,
in timp ce localizarea implica extragerea anumitor date pe baza unei culturi.
Exemplu:
* Globalizare: scrierea numerelor reprezentand sume de bani este in anumite tari
implica utilizarea (.) ca separator pentru mii si o virgula ca separator zecimal. O
aplicatie globalizata formateaza numerele reprezentand sume de bani pe baza regulilor
de acest gen din regiunea respectiva.
* Localizare: titlul unei forme este afisat intr-un anumit limbaj, dependent de tara in care
este utilizata aplicatia. O aplication localizata preia stringul potrivit si il afiseaza in
functie de locatie.
Culture
Intr-o aplicatie, termenul cultura se refera la informatia culturala legat de regiunea in
care este utilizata aplicatia. In .NET Framework, culturile sunt identificate utilizand un
cod cultural care reprezinta limba curenta folosita in mediul de lucru. Un cod de cultura
poate, de asemenea, specifica informatii despre o anumita regiune. In general, codul
culturii este fie un cod din doua litere, care specifica limba, fie un cod din doua litere,
urmat de o liniuta si alte doua litere care specifica regiunea. Codurile care specifica
numai limbajul se numesc culturi neutre,in timp ce codurile care specifica limba si
regiunea sunt cunoscute drept culturi specifice. Exemple:
* en - limba engleza, nici o regiune
* en-CA - limba engleza, Canada
* ro - limba romana
Lista completa a codurilor culturale poate fi consultata utilizand documentatia aferenta
clasei CultureInfo in the .NET Framework.
Setarea culturii curente

Dezvoltare de aplicatii in Visual Studio .NET

Page 153 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Orice aplicatie citeste automat setarile legate de cultura sistemului si le


implementeaza. Se poate medifica cultura curenta dintr-o aplicatie setand, in mod
programatic, cultura curenta la o noua instanta a clasei CultureInfo. Acesta clasa
contine informatii despre o cultura si despre modalitatea in care va interactiona cu
aplicatia. De exemplu, clasa CultureInfo contine informatii despre tipul de calendar,
formatarea monetara, formatul datei, s.a.m.d. pentru o cultura specificata. Stabilirea
unei culturi: setand proprietatea CurrentThread.CurrentCulture la o noua instanta a
clasei CultureInfo. Clasa CultureInfo are un constructor care primeste ca parametru un
string reprezentand codul culturii respective. Exemplu:
System.Threading.Thread.CurrentThread.CurrentCulture = new
System.Globalization.CultureInfo("fr-CA");
Returnarea culturii curente se se realizeaza prin accesarea clasei
CultureInfo.CurrentCulture dupa cum urmeaza:
// using System.Globalization
CultureInfo theCurrentCulture;
theCurrentCulture = CultureInfo.CurrentCulture;
Implementarea globalizarii
Atunci cand proprietatea Thread.CurrentThread.CurrentCulture este setata la o noua
instanta CultureInfo, toate datele formatate de aplicatie sunt modificate pe baza noului
format. Datele neformatate nu vor fi afectate in vreun fel. Sa consideram o forma cu un
contro Label. Sa presupunem ca urmatoarea atribuire:
label1.Text = "$1000.00";
Daca se schimba cultura la en-GB , eticheta va afisa exact acelasi lucru, contrar
asteptarilor. Setarile legate de cultura au efect numai pentru informatiile formatate. Pe
de alta parte, sa presupunem ca textul etichetei a fost formatat in felul urmator:
label1.Text = (1000).ToString("C");
Setarea culturii la en-GB , va face ca eticheta sa afiseze L1000.00. Valoarea este
formatata pe baza comventiilor monetare locale. Nu se executa, insa, nici un fel de
conversie monetara.
Implementarea localizarii
.NET Framework faciliteaza localizarea prin crearea de fisiere de resurse care retin
datele pentru forme alternative asociate culturilor pe care le suporta aplicatia. La
run-time, se incarca o anumita forma, pe baza proprietatii CultureInfo.CurrentUICulture.
Setarea UI-culturii curente
O UI-cultura este reprezentata de o instanta CultureInfo, si este diferita de proprietatea
CultureInfo.CurrentCulture. Setarile CurrentCulture determina formatarile care vor fi
aplicate datelor, in timp ce CurrentUICulture specifica resurse pentru forme localizate
care vor fi incarcate la run-time. Se poate prelua instanta CurrentUICulture accesand
proprietatea CultureInfo.CurrentUICulture, dupa cum urmeaza:

Page 154 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

// using System.Globalization
CultureInfo theCurrentCulture;
theCurrentCulture = CultureInfo.CurrentUICulture;
UI-cultura curenta se seteaza in acceasi maniera ca si cultura curenta: accesand
Thread-ul curent. De exemplu:
System.Threading.Thread.CurrentThread.CurrentUICulture = new
System.Globalization.CultureInfo("th-TH");
La setarea culturii curente, sistemul de operare incarca resursele specifice acelei
culturi, in cazul in care sunt disponibile. Daca resursele specifice nu sunt disponibile,
interfata utilizator vizualizeaza resursele pentru cultura respectiva.
!
UI-cultura trebuie setata inainte de o forma sa poata vizualiza resursele localizate.
Daca UI-cultura se seteaza programatic, ea trebuie setata in constructorul formei
principale sau in metoda main a aplicatiei.
Crearea formelor localizate
Crearea formelor localizate in .NET Framework este un proces facil. Fiecare forma
contine o proprietate Localizable care determina daca forma este localizata sau nu.
Setarea acestei proprietati la true permite localizarea. In acest caz, Visual Studio .NET
creaza automat fisierele resursa necesare, utilizand proprietatea Language a formei.
Atunci cand aceasta proprietate este setata la (Default), pot fi editate toate
UI-proprietatile sau controalele pentru a furniza o reprezentare a UI-culturii curente.
Pentru a crea o versiune localizata a formei, se poate seta proprietatea Language la o
alta valoare, diferita de (Default). Visual Studio .NET va crea un fisier resursa pentru
noul limbaj si va stoca in acel fisier toate valorile UI-specifice setate.
!
Desi, de obicei, UI-elementele sunt siruri de caractere, orice proprietate poate fi
localizata. Deci, putem avea, de exemplu, butoane care isi modifica dimensiunile
pentru a putea vizualiza corect texte in diverse limbi. Aceste fisiere pot fi vizualizate in
Solution Explorer, existand cate un fisier resursa pentru fiecare limbaj pentru care
forma are o versiune.
Atunci cand CurrentUICulture este setata la o cultura localizata, aplicatia va incarca
versiunea corespunzatoare a formei consultand fisierele resursa aferente. Daca nu
exista fisierele resursa necesare, se va vizualiza UI-cultura implicita.
Validarea input-ului cu specific international
se pot utiliza metodele de validare din structura Char pentru a valida inputul introdus
(acesta poate contine caractere specifice unei anumite limbi). Metodele Char.IsDigit,
Char.IsLetter si altele vor returna true sau false, independent de caracterele utilizate.
Deci, validarile de acest gen vor functiona corect, fara alte modificari speciale.
Formatari specifice culturilor
Dezvoltare de aplicatii in Visual Studio .NET

Page 155 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Se pot specifica valori pentru anumiti membri ai clasei CultureInfo pentru a croi
aplicatia astfel incat sa raspunda unor necesitati cu specific cultural. De exemplu, sa
consideram o aplicatie pentru un client care colaboreaza cu un grup din Japonia, dar
moneda utilizata in aplicatie este dolarul american. Aplicatia trebuie sa implementeze o
formatare cu specific japonez pentru anumite elemente.
Membri ai clasei CultureInfo care specifica formatari legate de globalizare:
* DateTimeFormat - formatarea datelor calendaristice si a timpului
* NumberFormat - formatarea datelor numerice si financiare
* TextInfo - formatarea textelor
Exemplu:
// using System.Globalization
// using System.Threading
CultureInfo modJPCulture = new CultureInfo("jp-JN");
modJPCulture.NumberFormat.CurrencySymbol = "$";
// se foloseste caracterul $
Thread.CurrentThread.CurrentCulture = modJPCulture;
Implementarea scrierii de la dreapta la stanga
Anumite limbaje folosesc o astfel de scriere. Formele Windows tandard contin o
proprietate RightToLeft care permite implementarea unei interfete cu un astfel de
specific.
Valori posibile ale proprietatii RightToLeft : Yes, No si Inherit, ultima fiind valoarea
implicita, caz in care afisarea este determinata de valoarea setata pentru controlul
parinte.
Efectul setarii proprietatii RightToLeft a unui control la valoarea Yes:
- aliniera textului este inversata
- pentru o forma, titlul va fi aliniat la dreapta
- barele de derulare verticale vor aparea pe partea stanga
- barele de derulare orizontale sunt initializate cu slider-ul in partea dreapta
- check-box-urile vor avea proprietatea CheckAlign inversata
- butoanele taburilor vor fi inversate
- la fel, alinierea elementelor in list box si combo box
Pe short, formatarea fiecarui control consta in oglindirea continutului acestuia.
Continutul unui control RightToLeft ramane, totusi, neschimbat.
Conversia caracterelor codificate
.NET Framework utilizeaza o reprezentare Unicode UTF-16 a caracterelor. Un caracter
Page 156 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Unicode este un standard universal standard de reprezentare a caracterelor, acoperind


o multime foarte mare de caractere, cu posibilitate de extindere.
.NET Framework permite conversii ale datelor din alte formate in date reprezentate in
Unicode. Aceste conversii sunt indeplinite de clasa Encoding, din spatiul de nume
System.Text. Aceasta clasa nu poate fi instantiata direct, dar se poate obtine o instanta
a acestei clase utilizand metoda statica Encoding.GetEncoding, pentru a obtine o
codificare specifica:
// using System.Text
Encoding jpEncoding;
// pagina de coduri 932 reprezinta caracterele japoneze
jpEncoding = Encoding.GetEncoding(932);
Dupa ce a fost creata o instanta a unei codificari, poate fi utilizata pentru a converti
caractere din aceasta codificare in caractere in format Unicode si vice versa. Exemplu:
// using System.Text
byte[] tgtData;
Encoding srcEncoding;
UnicodeEncoding tgtEncoding = new UnicodeEncoding();
srcEncoding = Encoding.GetEncoding(932);
// caracterele japoneze sursa
// tgtData contine acum un tablou de bytes care reprezinta
codificarea
// Unicode a tabloului myData
tgtData = Encoding.Convert(srcEncoding, tgtEncoding, myData);
Sinteza:
- globalizare
- localizare
- cultura
- UI-cultura
- conversii de caractere

Dezvoltare de aplicatii in Visual Studio .NET

Page 157 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 11. Assemblies. Aplicatii - configurare,


securizare, instalare, rulare - X
1. Assemblies si resurse
Un assembly reprezinta unitatea primara de dezvoltare intr-o aplicatie Microsoft .NET
Framework, constand intr-o colectie de tipuri si resurse care sunt interconectate pentru
a crea o unitate functionala logica. Assembly-urile sunt auto-descriptive si contin toata
informatia solicitata de common language runtime pentru a interpreta continutul si
pentru a configura executia acestora.
Pe scurt, un assembly este un proiect care este compilat intr-un fisier executabil sau
intr-un fisier DLL. Structura interna a unui assembly este, intrucatva, diferita de cea a
fisierelor .exe sau .dll create cu unelte de dezvoltare anterioare. Un assembly contine
patru sectiuni interne:
- un manifest (metadata)
- metadate despre tipuri
- limbajul intermediar al assembly-ului
- fisiere de resurse
Manifestul assembly-ului contine metadata care descrie assembly-ul in contextul CLR.
Common language runtime utilizeaza aceste informatii pentru a lua decizii legate de
executia assembly-ului. Un manifest contine urmatoarele informatii:
- identitate: contine numele si numarul versiunii assembly-ului, putand contine
informatii optionale, cum ar fi semnatura aplicatiei
- tipuri si resurse: lista tuturor tipurilor continute, precum si informatii despre
modalitatea de accesare a tipurilor
- fisiere: lista tuturor fisierelor din assembly, precum si informatii legate de
dependentele dintre acestea
- permisiuni de securitate: descriu restrictiile de securitate impuse la executia
assembly-ului
Identitatea unui assembly este continuta in fisierul AssemblyInfo.vb sau .cs din cadrul
proiectului, putand fi modificata de catre utilizator.
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]

Page 158 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
Informatiile legate de identitatea assembly-ului pot fi modificate prin setarea valorilor
acestor atribute in fisierul AssemblyInfo. Urmatorul exemplu de cod demonstreaza cum
se poate seta atributul AssemblyTitle:
[assembly: AssemblyTitle("Acesta este un assembly!")]
Crearea assembly-urilor de tip biblioteca de clase (class library)
Acestea reprezinta o multime de tipuri care pot fi referentiate si utilizate in alte
assembly-uri. De exemplu, un control personalizat care va fi utilizat in alte aplicatii va fi
construit in cadrul unui assembly de aces tip. Un astfel de assembly nu este executabil,
trebuind adaugat ca referinta intr-o alta aplicatie executabila.
Tipurile de proiecte asociate unui astfel de assembly sunt Class Library sau Windows
Control Library. Se scrie codul, se seteaza informatiile legate de identitatea
assembly-ului in fisierul AssemblyInfo si se executa Build.
Resurse si assembly-uri de resurse
O mare parte dintre aplicatii utilizeaza resurse. Acestea reprezinta date
non-executabile partajate in cadrul aplicatiei. Exemple de resurse: siruri de caractere
vizualizate in cadrul interfetei utilizator pe baza culturii setate in aplicatie sau un set de
imagini. Impachetarea acestor date in fisiere resursa permit modificarea datelor
necesare programului fara a recompila intreaga aplicatie.
Crearea fisierelor de resurse
Aplicatia ResEditor din .NET Framework poate fi utilizata pentru a crea fisiere resursa
care contin texte si imagini. ResEditor este o aplicatie de sine statatoare, nefiind
integrata in Visual Studio .NET. Ea va fi rulata separat, utilizand command prompt-ul
Visual Studio .NET. ResEditor permite crearea de fisiere .resources sau .resx care
contin siruri de caractere sau imagini. Se pot specifica tipul si numele resurselor din
cadrul fisierului. Dupa adaugarea elementelor din cadrul fisierului, se pot specifica
valori ale sirurilor de caractere resursa sau imaginile care vor fi adaugate in cadrul
resurselor de imagini. In final, fisierele pot fi salvate ca fisiere binare de tip .resources
sau fisiere XML de tip .resx.
Odata create, fisierele .resources sau .resx pot fi adaugate la proiect din meniul
Project, optiunea Add Existing Item si selectand apoi fisierul resursa dorit. Executand
Build, resursele vor fi partajate corespunzator in cadrul proiectului.
Crearea assembly-urilor de resurse
Pot fi create assembly-uri care contin numai resurse. Acest lucru este util in situatia in
care este necesara modificarea datelor continute in fisiere resursa fara a recompila
aplicatia pentru modificarea efectiva a acestora.
Un assembly de tip resursa se poate crea prin adaugarea de fisiere resursa la un
Dezvoltare de aplicatii in Visual Studio .NET

Page 159 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

proiect vid. Atunci cand se va executa build, resursele vor fi compilate intr-un assembly
comun care va putea fi apoi referentiat si accesat.
Crearea unui assembly satelit
La crearea aplicatiilor internationalizate, este necesara furnizarea diferitelor multimi de
resurse pentru culturile utilizate in aplicatie. Assembly-urile satelit permit acestor
multimi de resurse sa fie incarcate automat, pe baza setarii CurrentUICulture pentru
firul de executie curent.
Pentru a fi incorporata intr-un assembly satelit, un fisier resursa trebuie sa se supuna
unei scheme specifice de nume, bazata pe cultura pentru care a fost proiectat. Numele
unui fisier resursa specific unei culturi este similar numelui fisierului resursa pentru
cultura invarianta, avand inserat, in plus, codul culturii respective intre numele de baza
si extensie. Deci, daca exista un fisier de resurse fileResources.resx, un fisier resursa
care va contine resurse pentru cultura neutra fr (Franta) va avea numele
fileResources.fr.resx. Pentru culturi specifice, un exemplu ar putea fi:
anotherFileResources.en-CA.resx.
Dupa adaugare, Visual Studio .NET va compila aceste fisiere resursa alternative in
assembly-uri satelit, creandu-se o structura de directoare asociata. La run-time,
resursele specifice culturii curente vor fi localizate automat de catre common language
runtime.
Interogarea resurselor la run-time
La run-time, se poate utiliza clasa ResourceManager pentru a returna resursele
partajate. Un ResourceManager gestioneaza accesul si interogarea resurselor
partajate in assembly. Fiecare instanta a clasei ResourceManager este asociata cu un
assembly care contine resurse.
Un ResourceManager se poate crea prin specificarea a doi parametri: numele de baza
al fisierului resursa si assembly-ul in care se gaseste acest fisier. Noul
ResourceManager va fi dedicat fisierului resursa specificat. Numele de baza specificat
este numele spatiului de nume care contine fisierul, urmat de numele fisierului, fara a
specifica extensiile. De exemplu, un fisier resursa denumit fileResources.de-DE.resx
intr-un spatiu de nume Namespace1 va avea numele de baza
Namespace1.fileResources.
Al doilea parametru refera assembly-ul in care este localizat fisierul resursa. Daca
assembly-ul care contine resursele este acelasi assembly care contine obiectul in
cadrul caruia de creaza ResourceManager-ul, se poate obtine o referinta la assembly
utilizand tipul obiectului respectiv. De exemplu:
// crearea unui ResourceManager pentru
// a accesa fisiere resursa dintr-un fisier partajat
// myResources.resx
// intr-un namespace myNamespace si acelasi assembly in care
// se gaseste obiectul curent
// se utilizeaza System.Resources
Page 160 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ResourceManager myManager = new ResourceManager


("myNamespace.myResources", this.GetType().Assembly);
Daca resursele care vor fi accesate se gasesc intr-un alt assembly, cum ar fi un
assembly de resurse, assembly-ul trebuie incarcat inainte de a accesa resursele
continute. Acest lucru se poate realiza prin intermediul unui obiect Assembly din spatiul
de nume System.Reflection. Exemplu:
// using System.Resources
System.Reflection.Assembly myResources;
// numele assembly-ului ca parametru
myResources =
System.Reflection.Assembly.Load("ResourceAssembly");
ResourceManager myManager = new
ResourceManager("ResourceAssembly.Resources",
myResources);
Proiectul trebuie sa contina o referinta la assembly-ul care va fi accesat. Odata ce a
fost creat un manager de resurse, acesta poate fi utilizat pentru a returna siruri de
caractere si obiecte continute in fisierul de resurse. Pentru a accesa un sir de
caractere, se utilizeaza metoda ResourceManager.GetString, specificand numele
resursei care va fi accesata. Imaginile sau alte obiecte dintr-un fisier resursa pot fi
obtinute prin metoda ResourceManager.GetObject. Aceasta metoda returneaza un
obiect corespunzator numelui specificat. In plus, trebuie executata o conversie explicita
pentru a obtine rezultatul scontat. Exemplu:
System.Drawing.Image myImage;
myImage =
(System.Drawing.Image)myManager.GetObject("ImageResource");
Assembly-uri partajate
Assembly-urile pot fi private sau partajate:
- un assembly privat este un assembly utilizat de o singura aplicatie
- un assembly partajat poate fi utilizat de mai multe aplicatii
Majoritatea assembly-urilor care se creaza sunt assembly-uri private, find create
implicit. Un astfel de assembly poate fi utilizat de o singura aplicatie, fiind integrat si
disponibil numai acelei aplicatii. Din aceste motive, nu exista informatii legate de
versiunea sau identitatea assembly-ului.
Toate assembly-urile cu care ne-am obisnuit pana acum au fost private. La adaugarea
unei referinte catre un assembly privat in proiect, Visual Studio .NET creaza o copie a
DLL-ului care contine assembly-ul si aceasta este copiata in directorul proiectului. Deci,
mai multe proiecte pot referentia acelasi DLL si utiliza tipurile pe care le contine, dar
Dezvoltare de aplicatii in Visual Studio .NET

Page 161 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

fiecare proiect are propria sa copie a DLL-ului, acesta fiind, deci, un assembly privat.
Pentru ca mai multe aplicatii sa partajeze un assembly, acesta trebuie instalat in Global
Assembly Cache. Avantaje:
- locatie partajata
- securitate (assembly-ul este instalat in directorul sisteului de operare)
- versionare (pot fi instalate mai multe versiuni ale aceluiasi assembly
Partajarea unui assembly si instalarea in Global Assembly Cache implica semnarea
assembly-ului cu un strong name.
Strong Naming
Un strong name este un nume care garanteaza identitatea assembly-ului. Acesta
contine informatii despre assembly, cum ar fi numele, numarul versiunii, informatia
legata de cultura si o pereche de chei publica/privata. Aceste informatii sunt incriptate
utilizand cheia privata si pot fi decriptate folosind cheia publica. Dezvoltatorul aplicatiei
este singurul care detine cheia privata, ceea cea determina securitatea aplicatiei.
O pereche de chei poate fi generata prin intermediul aplicatiei sn.exe (strong name).
Un fisier care contine astfel de chei are extensia .snk. Exemplu:
sn k myKey.snk
Pentru a semna un assembly cu un strong name: - se deschide fisierul AssemblyInfo
din cadrul proiectului
- se verifica numarul versiunii assembly-ului:
[assembly: AssemblyVersion("1.0.1.1")]
- se specifica fisierul care contine cheile de criptare. Exemplu:
[assembly: AssemblyKeyFile("..\\..\\myKey.snk")]
Se executa build. Strong name-ul va fi generat si aplicat assembly-ului.
Instalarea in Global Assembly Cache
Se utilizeaza aplicatia Global Assembly Cache utility (gacutil.exe):
gacutil /i mypath\myAssembly.dll
Sinteza:
- assembly - manifest, tipuri de date, fisiere de cod si reurse
- assembly-uri de tip biblioteca de clase
- resurse
- assembly-uri de resurse
- resurse asociate culturilor
Page 162 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

- clasa ResourceManager
- assembly-uri private si partajate
- Global Assembly Cache
- strong name
- aplicatiile sn.exe si gacutil.exe

2. Configurarea si optimizarea aplicatiilor


.NET Framework pune la dispozitie unelte de configurare si optimizare a aplicatiei dupa
ce aceasta a fost instalata. Fisierele de configurare permit specificarea locatiei sau
informatiilor legate de versiune assembly-urilor si permit configurarea proprietatilor
aplicatiei.
Pentru orice aplicatie se poate crea un fisier de configurare. Acesta permite
configurarea proprietatilor aplicatiei dupa ce aceasta a fost instalata, fara a recompila
codul. Fisierul de configurare este un fisier XML care contine informatii despre
comportamente care vor fi imprimate aplicatiei.
Crearea fisierului de configurare
Un fisier de configurare este un fisier XML care contine o serie de taguri specifice si un
nume care trebuie sa respecte anumite regului. Un fisier de configurare pentru o
aplicatie va avea numele <name>.<extension>.config, unde <name> este numele
aplicatiei, iar <extension> este extensia aplicatiei (de exemplu .exe). Un fisier de
configurare trebuie sa se afle in acelasi director ca si assembly-ul asociat aplicatiei
pentru care se face configurarea.
Structura de baza a unui fisier de configurare este urmatoarea:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<...elemente de configurare...>
</configuration>
Inafara primului element, care specifica versiunea XML si codificarea, si a ultimului
element, <configuration>, nu exista elemente obligatorii pentru un fisier de configurare.
Toate celelalte elemente sunt optionale.
In C#, fisierul de configurare .config trebuie creat manaul, cu ajutorul unui editor, pe
baza schemei descrise mai sus, adaugand o serie de elemente.
Schema fisierului de configurare .config

Dezvoltare de aplicatii in Visual Studio .NET

Page 163 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Elemente ale schemei fisierului de configurare:


<startup>- contine numai elementul <requiredRuntime>, care permite specificarea
versiunii common language runtime utilizate
<runtime> - permite configurarea informatiilor legate de executia assembly-ului si
conportamentul garbage colectorului
<system.runtime.remoting> - contine informatii despre configurarea canalelor de
comunicatie si a obiectelor de tip remote
<system.net> - contine informatii despre aplicatii pe Internet
<mscorlib> - contine un tag <cryptographySettings> care permite configurarea
elementelor criptografice din cadrul aplicatiei
<configSections> - contine configurari personalizate
<system.diagnostics> - informatii de configurare a claselor Trace si Debug din cadrul
aplicatiei
Configurarea aplicatiei utilizand proprietati dinamice
Proprietatile dinamice permit configurarea valorilor de startup ale obiectelor din cadrul
aplicatiei. Se poate realiza o mapare a proprietatilor specifice ale obiectelor la
elemente din cadrul fisierului de configurare file si returnarea dinamica a acestora la
run-time. Proprietatile dinamice sunt utile in cazul resurselor externe care se pot
modifica pe durata timpului de viata a aplicatiei, cum ar fi un string de conectare la o
baza de date. Consultand valoarea unei astfel de proprietati dinamice, se poate
reconfigura aplicatia fara a fi necesara recompilarea si reinstalarea.
Configurarea proprietatilor dinamice utilizand ferestrea Properties
Fereastra Properties corespunzatoare fiecarui control din interfata utilizator contine un
nod expandabil care permite utilizatorului setarea proprietatilor care vor fi tratate ca
proprietati dinamice. Proprietatile care vor fi legate la resurse externe sunt adaugate
implicit la acest nod, putandu-se adauga si alte proprietati (Advanced ...).
Pentru a putea consulta o proprietate dinamica din fisierul .config, trebuie mai intai
definita o cheie. Aceasta cheie este scrisa in fisierul .config si corespunde valorii
corespunzatoare care va fi returnata din fisierul .config. La setarea unei chei pentru o
proprietate dinamica, cheia si valoarea proprietatii sunt scrise automat in fisierul
.config. Exemplu: transformarea proprietatii Button1.Text in proprietate configurabila.
<add key="Button1.Text" value="Button1" />
Cheia (Button1.Text) este utilizata de aplicatie pentru a returna valoarea (Button1) la
run-time. Deoarece cheile sunt citite de utilizatori, trebuie sa primeasca valori care sa
respecte un pattern consistent. Pattern-ul implicit este <control>.<propertyname>, unde
control este numele controlului, iar propertyname este numele proprietatii.
Dupa ce programul a fost instalat, pot fi configurate proprietatile dinamice prin editarea
directa a fisierului de configurare. La urmatoarea rulare a aplicatiei, modificarile
efectuate isi vor face simtite efectul.
!

Page 164 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Nu toate proprietatile sunt disponibile in fereastra Dynamic Properties. Pot fi


configurate doar proprietatile reprezentate ca siruri de caractere sau tipuri care pot fi
convertite explicit de la tipul string.
Setarea si consultarea manuala a proprietatilor dinamice
Uneori, este util ca si alte proprietati, inafara proprietatilor din interfata utilizator, sa
poata fi configurabile. Sa consideram exemplul unei clase instantiate la run-time. Pot fi
stabilite proprietati implicite pentru obiecte create dinamic in fisierul de configurare;
acestea pot fi setate si consultate dinamic la run-time utilizand clasa
AppSettingsReader.
Clasa AppSettingsReader se gaseste in spatiul de nume System.Configuration si
utilizeaza chei pentru a returna valori din fisierul de configurare. Principala metoda a
acestei clase este GetValue. Prametri: un string reprezentand cheia si un tip care
reprezinta valoarea returnata. Desi se specifica un tip, valoarea este returnata ca un
Object si trebuie convertita explicit la tipul corect de date. Exemplu:
// crearea unui obiect AppSettingsReader
System.Configuration.AppSettingsReader myReader = new
System.Configuration.AppSettingsReader();
// crearea unui obiect utilizator
Widget myWidget = new Widget();
// returnarea valorii unei proprietati dinamice
// DynamicWidget.Text repreinta cheia,
// valoarea este returnata ca un string
// urmeaza o conversie explicita
myWidget.Text = myReader.GetValue("DynamicWidget.Text",
typeof(System.String)).ToString();
La incercarea de utilizare a unei chei inexistente in fisierul de configurare, se arunca o
exceptie de tipul InvalidOperationException. Elementele continand perechi de tipul
key/data se adauga prin intermediul tagului <add> si vor fi introduse drept copii ai
tagului <appSettings>. Exemplu:
<appSettings>
<... setari ale proprietatilor configurabile etc... >
<... Example: <add key="settingName" value="settingValue"/>... >
<add key="Widget.Visible" value="True" />
<add key="Widget.Text" value="I love my Widget!" />
</appSettings>
Optimizarea performantei aplicatiiilor
Dezvoltare de aplicatii in Visual Studio .NET

Page 165 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Optimizare in faza de dezvoltare


Un cod eficient, optimizat este rezultatul unei bune planificari si a unei experiente
bogate in scrierea de cod. Cateva idei mai importante legate de tehnica scrierii de cod:
- evitarea legarii tarzii (late binding) - evitarea, pe cat posibil, a folosirii tipului object si,
deci, a conversiilor
- evitarea utilizarii variabilelor globale
- traterea atenta a structurilor iterative - reprezinta structurile de program care implica
executia unui numar foarte mare de operatii
Optimizarea este un proces iterativ
Planul general de optimizare a codului este urmatorul:
* masurarea datelor legate de performanta
* identificarea bottleneck-urilor
* rafinarea codului
Masurarea performantei
Windows 2000 si Windows XP includ un utilitar denumit perfmon.exe care poate
monitoriza o serie de parametri legati de performanta aplicatiei. Rezultatele pot fi
redate in forma grafica sau salvate sub forma de log-uri.Exista, de asemenea,
posibilitatea optimizarii aplicatiei prin setari ale compilatorului.
Sinteza:
- fisiere de configurare
- proprietati dinamice
- clasa AppSettingsReader
- tagul <add>
- utilitarul perfmon.exe
- optimizari in faza de compilare

3. Securitatea aplicatiilor
Securitate inseamna protectie. Pot fi utilizate facilitatile de securitate puse la dispozitie
de .NET Framework pentru a proteja codul aplicatiilor fata de utilizatori neautorizati si
pentru a proteja sistemul in cazul utilizarii neautorizate a anumitor fragmente de cod.
Administratorul sistemului seteaza politica de securitate a sistemului. Acesta decide
tipurile de cod care vor putea fi utilizate de o masina, daca un anumit assembly poate fi
rulat pe o masina, s.am.d. Politica de securitate setata de administratorul sistemului nu
poate fi suprascrisa in cod: ea confera cel mai inalt nivel de securitate pe o anumita

Page 166 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

masina.
Permisiuni
O permisiune este un obiect care reprezinta un utilizator, o identitate sau o resursa
(cod). Obiectele de tip permisiune sunt utilizate intr-o varietate de functii legate de
securitate.
Interfata IPermission
Orice permisiune de securitate in .NET Framework trebuie sa implementeze interfata
IPermission, care contine un nivel de functionalitate comun tuturor obiectelor de
securitate deci, arareori va fi necesara o implementare efectiva a acestei interfete.
Metodele membre ale interfetei IPermission sunt descrise in continuare:
* Copy - creaza si returneaza o copie identica a permisiunii
* Demand - parcurge stiva de apeluri si arunca o exceptie de tipul SecurityException
daca un apelant de pe stiva nu are permisiunea sa execute apelul respectiv
* Intersect - creaza si returneaza o permisiune care reprezinta intersectia a doua
permisiuni
* IsSubsetOf - determina daca permisiunea curenta este un subset al unei permisiuni
specificate
* Union - creaza o permisiune care reprezinta reuniunea permisiunii curente cu o alta
permisiune specificata.
Configurarea autorizarilor bazate pe roluri
Securitatea role-based reprezinta garantarea sau blocarea accesului la o aplicatie sau
resursa pe baza unei identitati sau rol al unui utilizator. De exemplu, sa presupunem ca
pentru o aplicatie utilizata in mediu universitar, numai profesorii vor avea acces la o
anumita sectiune a aplicatiei. Autorizarea bazata pe roluri implementeaza securitatea
de acest tip.
Clasa Principal
In .NET Framework, utilizatorii care se autentifica sunt reprezentati de obiecte
Principal. Acestea contin informatii despre identitatea sau rolul utilizatorului si poate fi
folosit pentru validarea identitatii fata de un obiect PrincipalPermission, utilizat pentru a
proteja partile sensibile ale unei aplicatii fata de utilizatori neautorizati.
Exemplu de implementare a unui model de securitate built-in:
// WindowsPrincipal reprezinta identitatea
// utilizatorului curent
AppDomain.CurrentDomain.SetPrincipalPolicy
(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal contine o referinta la un obiect WindowsIdentity care reprezinta

Dezvoltare de aplicatii in Visual Studio .NET

Page 167 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

utilizatorul curent. Se pot obtine informatii despre utilizatorul curent accesand


proprietatea Identity a obiectului WindowsPrincipal. WindowsPrincipal returneaza
proprietatea Identity ca o interfata IIdentity, va fi nevoie, deci, de o conversie explicita
la un obiect WindowsIdentity. Exemplu:
WindowsPrincipal myPrincipal;
myPrincipal = (WindowsPrincipal)
System.Threading.Thread.CurrentPrincipal;
WindowsIdentity myIdentity;
// se preia identitatea WindowsIdentity
myIdentity = (WindowsIdentity)myPrincipal.Identity;
// se afiseaza numele utilizatorului curent
MessageBox.Show(myIdentity.Name);
Securitate role-based imperativa (la run-time)
Se utilizeaza obiecte PrincipalPermission. Un astfel de obiect poate specifica o
identitate si un rol, putand impune faptul ca utilizatorul curent trebuie sa aiba numele si
rolul specificat de obiectul PrincipalPermission. Metoda Demand verifica concordanta
intre obiectul Principal si numele si rolul specificate de PrincipalPermission. Exemplu:
// constructorul are ca parametri
// numele si rolul utilizatorului ca stringuri
PrincipalPermission myPermission = new
PrincipalPermission("John",
"Manager");
// CurrentPrincipal trebuie sa contina user-ul John,
// cu rol de manager
myPermission.Demand();
Utilizarea metodei Union pentru a crea permisiuni care combina doua permisiuni
existente. Exemplu:
PrincipalPermission Permission1 = new
PrincipalPermission("John",
"Manager");
PrincipalPermission Permission2 = new
PrincipalPermission("Smith",
"Group Manager");
PrincipalPermission Permission3;
// reuniunea celor doua permisiuni
Page 168 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Permission3 =
(PrincipalPermission)Permission2.Union(Permission1);
// John sau Smith vor putea accesa codul programului
Permission3.Demand();
La crearea unui obiect PrincipalPermission, se poate specifica null pentru nume sau
rol. Aceasta permite crearea unei permisiuni care valideaza numai numele sau numai
rolul permisiunii. Exemplu: validarea rolului obiectului CurrentPrincipal (fara validarea
numelui):
// utilizatorul trebuie sa aiba rol de manager
PrincipalPermission myPermission = new
PrincipalPermission(null, "Manager");
Intersectia a doua permisiuni:
PrincipalPermission Permission1 = new PrincipalPermission(null,
"Manager");
PrincipalPermission Permission2 = new
PrincipalPermission("John",
null);
PrincipalPermission Permission3;
// intersectia permisiunilor
// Permission1 si Permission2
Permission3 =
(PrincipalPermission)Permission2.Intersect(Permission1);
// Principal-ul care acceseaza acest cod trebuie sa fie John
// cu rol de manager
Permission3.Demand();
Verificarea apartenentei utilizatorilor la roluri stabilite de sistemul de operare:
// se utilizeaza sintaxa cu doua backslash-uri (\\)
PrincipalPermission myPermission = new
PrincipalPermission("John", "BUILTIN\\Administrators");
Securitate role-based declarativa (in cadrul manifestului assembly-ului)
Orice obiect Permission are un atribut corespunzator. Aceste atribute pot fi atasate
claselor si/sau membrilor si sunt utilizate pentru a controla accesul la aceste clase si
membri. In contextul securitatii declarative, atributele de permisiune sunt atasate
membrilor protejati. Administratorul poate lua o decizie care sa permita executia
Dezvoltare de aplicatii in Visual Studio .NET

Page 169 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

assembly-ului pe baza metadatei. Fiecare atribut de permisiune contine ca parametru


al constructorului un obiect SecurityAction care indica actiunea care se va executa. In
securitate role-based , acesta este de obicei o actiune Demand. Exemplu: securitate
pentru o metoda myMethod.
[PrincipalPermission(SecurityAction.Demand, Name="John",
Role="Student")]
public void myMethod()
{
// Method implementation omitted
}
Configurarea securitatii accesului la cod
Securitatea accesarii codului previne executia apelurilor neautorizate catre anumite
fragmente de cod. Se pot stabili, de asemenea, nivele de securitate care sa comunice
cerintele de securitate administratorului de sistem.
La fel ca in cazul securitatii bazate pe roluri, securitatea accesului la cod se bazeaza
pe permisiuni. In acest context, o permisiune reprezinta resursele sistemului si
controlul accesarii acestor resurse. Un exemplu foarte bun este sistemul de fisiere. In
cazul unei aplicatii care utilizeaza scrierea in fisiere, trebuie sa ne asiguram ca
apelurile neautorizate nu sunt capabile sa utilizeze anumite resurse, evitandu-se astfel
producerea de erori in structura de fisiere.
Permisiuni de accesare a codului
Fiecare permisiune reprezinta o resursa. Majoritatea permisiunilor se gasesc in spatiul
de nume System.Security. Cele mai importante permisiuni referitoare la accesarea
codului:
* DirectoryServicesPermission - controleaza accesul la Active Directory
* EnvironmentPermission - controleaza accesul la variabilele de mediu
* EventLogPermission - controleaza scrierea/citirea in/din loguri de evenimente
* FileDialogPermission - controleaza accesul la fisiere sau directoare prin intermediul
unei ferestre de dialog
* FileIOPermission - controleaza crearea, citirea si scrierea in sistemul de fisiere
* OleDbPermission - stabileste accesul la o baza de date OleDb
* PrintingPermission - controleaza accesul la dispozitivele de printare
* ReflectionPermission - controleaza abilitatea claselor din System.Reflection de a
extrage informatii despre tipuri la run-time
* RegistryPermission - controleaza citirea/scrierea din/in registri
* SecurityPermission - stabileste drepturi, incluzand dreptul de a executa cod,
controleaza manipularea firelor de executie si a obiectelor Principals, si apelurile de
code unmanaged
Page 170 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

* SQLClientPermission - stabileste accesul la baze de date Microsoft SQL Server


* UIPermission - controleaza accesul la interfata utilizator
Crearea permisiunilor de acces la cod
Fiecare permisiune contine un anumit set de constructori care permit specificarea
resurselor protejate. O permisiune care permite accesul nerestrictionat la resurse este
descrisa de flagul PermissionState.Unrestricted. PermissionState.None permite
crearea unei permisiuni care restrictioneaza total accesul la resursele specificate.
Exemplu:
// acces nerestrictionat la resurse Reflection
ReflectionPermission myPermission = new
ReflectionPermission(PermissionState.Unrestricted);
// acces complet restrictionat la resurse UI
UIPermission anotherPermission = new
UIPermission(PermissionState.None);
Fiecare permisiune contine constructori aditionali care permit configurari specifice ale
permisiunii. Exemplu: crearea unei permisiuni care reprezinta dreptul de a scrie intr-un
singur fisier din sistemul de fisiere:
FileIOPermission myPermission = new
FileIOPermission(FileIOPermissionAccess.Write, "C:\\aFile.txt");
Membrii clasei CodeAccessPermission
Toate permisiunile de acces la cod sunt derivate din clasa CodeAccessPermission.
Metode ale clasei CodeAccessPermission
: * Assert - se presupune ca fragmentul de cod care apeleaza aceasta metoda poate
accesa resursele reprezentate de permisiune chiar daca apelantii aflati la un nivel
superior in stiva de executie nu au aceasta permisiune
* Demand - impune faptul ca toti apelantii de la un nivel superior in stiva au
permisiunea de a accesa resursa reprezentata de aceasta permisiune
* Deny - interzice codului apelant al acestei metode sa acceseze resursa reprezentata
de aceasta permisiune
* PermitOnly - Interzice codului apelant sa acceseze resursa reprezentata de
permisiune, cu exceptia unui subset al resursei specificat de permisiune
* RevertAll - elimina efectul tuturor metodelor Assert, Deny si PermitOnly apelate
anterior
* RevertAssert - elimina apelurile Assert anterioare
* RevertDeny - elimina apelurile Deny anterioare

Dezvoltare de aplicatii in Visual Studio .NET

Page 171 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

* RevertPermitOnly - elimina apelurile PermitOnly anterioare


Securitate imperativa de acces la cod
Securitatea imperativa actioneaza la run-time.
Metoda Demand este si, in acest caz, metoda principala utilizata. Permisiunea de a
accesa resurse protejate este verificata de common language runtime, care consulta
politica de securitate a assembly-ului setata de administratorul sistemului. La apelul
metodei Demand a unui obiect de tip permisiune, se verifica in stiva de executie daca
fiecare dintre apelantii de pe nivele superioare au garantata permisiunea de a accesa
resursele reprezentate de permisiune. Deci, un assembly poate avea o metoda care
apeleaza o alta metoda protejata de o permisiune de acces la cod. Daca apelul catre
cea de-a doua metoda provine de la un assembly securizat (trusted), apelul va fi
permis si resursa protejata va putea fi utilizata. In cazul unui assembly untrusted, care
nu are permisiunea necesara, apelul se va solda cu esec.
Exemplu:
// permisiune care reprezinta acces
// nerestrictionat la sistemul de fisiere
FileIOPermission myPermission = new
FileIOPermission(PermissionState.Unrestricted);
// toti apelantii acestui cod au permisiune pentru
// acces nerestrictionat la sistemul de fisiere
myPermission.Demand();
Metoda Deny interzice apelantilor codului accesul la resursa protejata, chiar daca
permisiunea era garantata de common language runtime. De exemplu:
FileIOPermission myPermission = new
FileIOPermission(PermissionState.Unrestricted);
myPermission.Deny();
Metoda PermitOnly interzice accesul la resurse, cu exceptia celor specificate de
permisiune. Exemplu:
// o permisiune care garanteaza accesul la un
// fisier specific
FileIOPermission myPermission = new
FileIOPermission(FileIOPermissionAccess.Write,
"C:\\myFile.txt");
myPermission.PermitOnly();

Page 172 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Metoda Assert. Exemplu:


// acces nerestrictionat la
// sistemul de fisiere
FileIOPermission myPermission = new
FileIOPermission(PermissionState.Unrestricted);
// asertiune: acces la sistemul de fisiere
myPermission.Assert();
Metoda statica Revert: elimina toate apelurile Deny, Assert sau PermitOnly anterioare.
Exemplu:
ReflectionPermission.RevertAll();
EnvironmentPermission.RevertDeny();
FileIOPermission.RevertAssert();
MessageQueuePermission.RevertPermitOnly();
Securitate declarativa de acces la cod
Ca si in cazul securitatii role-based , fiecare permisiune de acces la cod are un atribut
corespunzator care poate fi atasat metodelor sau claselor pentru a specifica actiuni de
securitate. Aditional, se pot specifica permisiuni pentru intregul assembly.
Se specifica in cadrul atributelor o valoare SecurityAction (nu un rol, cum era in cazul
securitatii role-based).
Exemplu:
[FileIOPermission(SecurityAction.Deny)]
public class aClass
{
// Class implementation omitted
}
Flagurile SecurityAction.Demand, SecurityAction.Deny, SecurityAction.Assert si
SecurityAction.PermitOnly corespund metodelor Demand, Deny, Assert si PermitOnly.
Exista si actiuni aditionale de securitate, in contextul securitatii declarative.
SecurityAction.LinkDemand impune primului apelant al clasei sau metodei sa aiba
permisiunea ceruta. SecurityAction.InheritanceDemand verifica daca clasele derivate
ale acestei clase sau care suprascriu metoda au permisiunea potrivita.
Flag-uri asociate intregului assembly:
- SecurityAction.RequestMinimum executa o cerere catre common language runtime
Dezvoltare de aplicatii in Visual Studio .NET

Page 173 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

sa indeplineasca o anumita permisiune. In cazul unui raspuns negativ, assembly-ul nu


se va executa.
- SecurityAction.RequestOptional este similar, dar assembly-ul va rula chiar daca
permisiunea nu este indeplinita.
- SecurityAction.RequestRefuse cere assembly-ului sa interzica permisiunea
specificata. Pentru aceste actiuni, se utilizeaza directiva assembly:
[assembly: FileIOPermission(SecurityAction.RequestMinimum)]
[FileIOPermission(SecurityAction.Assert,
Write="C:\\myFile.txt")]
public void WriteFile()
{
// implementare...
}
Sinteza
* securitate role-based
* securitate de acces la cod
* clasa Permission
* interfata IPermission
* securitate imperativa si declarativa
* obiecte Principal (pentru securitate role-based )
* resurse sistem (pentru acces la cod)
* directiva assembly

4. Instalarea si rularea aplicatiilor


Dupa fazele de proiectare, dezvoltare, compilare si executie a unei aplicatii Visual
Studio .NET, urmeaza, in mod firesc, o procedura de instalare si rulare a aplicatiilor pe
o anumita masina. Iata, pe scurt, scenarii posibile in cadrul unei astfel de proceduri:
* In anumite conditii, o aplicatie .NET se poate instala utilizand comanda XCOPY
pentru a copia directorul principal si toate subdirectoarele aplicatiei pe o anumita
masina. Acest lucru este posibil (va avea efectul scontat) numai daca pe masina
respectiva este instalat .NET Framework si daca aplicatia nu are referinte catre
assembly-uri sau resurse partajate. In multe circumstante, XCOPY nu constituie o
modalitate viabila de instalare a aplicatiilor.

Page 174 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

* Utilizand Visual Studio .NET, se pot crea Windows Installer setup projects sau
Windows Installer merge modules. Un proiect de setup poate fi executat pe un
calculator care are instalat Windows Installer 1.5 si care contine toata informatia
necesara instalarii unei aplicatii pe un calculator client. Un merge module este utilizat
pentru impachetarea fisierelor DLL si nu poate fi instalat aparte, ci numai prin
concatenare la un proiect de setup.
Setup Project Wizard permite crearea unui proiect de setup care poate fi apoi,
eventual, configurat intr-un mediu integrat de dezvoltare (IDE). Pentru a asocia un
proiect de setup unei aplicatii, se selecteaza meniul File, Add Project, New Project,
Setup And Deployment Projects, Setup Project Wizard. Se creaza astfel un proiect de
setup, specificandu-se tipul outputului proiectului si alte fisiere aditionale care vor fi
adaugate la proiect.
* Pot fi configurate proprietatile de Build ale proiectului, utilizand Setup Property Pages.
Se poate specifica modalitatea de impachetare a fisierelor, setarile de compresie, daca
se va crea sau nu un bootstrapper, directorul de instalare si setarile Authenticode
(referitoare la semnatura aplicatiei).
- Output File Name: reprezinta locatia in care va fi plasat fisierul de instalare rezultat in
ultima construirii proiectului de setup. Acest fisier are extensia .msi, in cazul aplicatiilor
Windows Installer si .msm, pentru Windows Installer merge modules.
- gruparea si compresia fisierelor - se pot utiliza fisiere de tip Cabinet (.cab), pentru
integrarea fisierelor de instalare in fisiere de o anumita dimensiune (de exemplu,
salvarea fisierelor de instalare in fisiere .cab de dimensiune 1.44M)
- optiunea Bootstrapper - se selecteaza in cazul in care pe masina pe care se va
instala proiectul nu exista Windows Installer 1.5, avand ca efect instalarea acestui
program, adaugand la proiectul de instalare 4 fisiere aditionale: Setup.exe,
InstMsiA.exe, InstMsiW.exe si Setup.ini.
* Dupa ce proiectul de instalare a fost construit, poate fi distribuit intr-o varietate de
moduri: cd-uri, dvd-uri, dischete, prin retea, pe web etc.
Aplicatiile de tip setup prezinta un nivel inalt de configurabilitate. Pot fi setate
proprietatile care furnizeaza informatii legate de originea aplicatiei care va fi instalate si
comportamentul aplicatiei la design-time, in fereastra Properties.
proprietate Register ofera posibilitatea inregistrarii unei componente COM sau a unui
font pe durata instalarii aplicatiei
File System Editor permite editarea sistemului de fisiere de pe masina pe care se
instaleaza aplicatia (target)
Registry Editor permite adaugarea/editarea intrarilor din registrii masinii target
File Types Editor permite crearea asocierilor dintre fisiere si programe de pe masina
target (exemplu: specificarea programului care va deschide implicit fisiere de tip .wav
- Winamp, Media Player etc).
User Interface Editor faciliteaza personalizarea interfetei programului de instalare
Custom Actions Editor permite stabilirea unor actiuni personalizate pe durata
instalarii (fragmente de cod care se vor executa ca raspuns la anumite evenimente
lansate pe durata instalarii)
Launch Conditions Editor permite adaugarea de criterii/conditii de cautare si executie
Dezvoltare de aplicatii in Visual Studio .NET

Page 175 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

(conditiile sunt impuse masinii target, se pot cauta fisiere, intrari in registri sau
componente Windows Installer; in functie de respectarea conditiilor impuse si/sau
rezultatele cautarii, se permite sau nu executia anumitor actiuni la instalare)
utilitarul Ngen.exe permite crearea unei imagini native a aplicatiei/assembly-ului (la
jit-compilare, fisierele sunt compilate in cod nativ, ceea ce permite maximum de
eficienta, viteza si utilizare a resurselor; Ngen.exe creaza o imagine nativa a
aplicatiei, ceea ce duce la posibilitatea obtinerii acestor avantaje)
utilitarul Permview.exe permite vizualizarea permisiunilor asociate unui assembly

Page 176 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 12. XML, Web Services - XI


1. Visual Studio .NET si XML
XML
Xml (eXtensible Markup Language) este un limbaj care permite definirea documentelor
ce contin informatii intr-un mod structurat. Informatia structurata dintr-un document xml
are atat continut (cuvinte, imagini, etc.), cat si o indicatie despre rolul pe care il are acel
continut (de exemplu continutul din sectiunea header are alt rol fata de cel din footer,
care la randul lui e diferit de continutul dintr-un tabel al unei baze de date). Toate
documentele au o anumita structura. Aceste structuri se construiesc utilizand
marcatori. W3.org se ocupa de standardizarea XML-ului, si specificatiile complete ale
acestui limbaj se afla la adresa http://www.w3.org/TR/WD-xml .
XML e la fel cu HTML?
Nu. In HTML, atat multimea de tag-uri (marcatori), cat si semantica asociata fiecarui
tag sunt predefinite. Spre exemplu <H1> va reprezenta intotdeauna un header de nivel
1, iar tag-ul <documentHTML> nu are nici un sens (nu are asociata nici o valoare
semantica). Standardul XML nu specifica nici semantica si nici multimea de tag-uri ale
limbajului. De fapt XML este un metalimbaj pentru definirea limbajelor bazate pe
marcatori (markup language). Cu alte cuvinte XML permite definirea de tag-uri precum
si relatia dintre acestea. Deoarece nu exista o multime de tag-uri predefinita, nu exista
nici o semantica asociata cu acestea. Definirea semantica documentelor XML este o
sarcina a aplicatiilor care folosesc documentelor respective sau a foilor de stiluri
(stylesheet).
Definitii XML
* DTD - validarea unui document XML este realizata folosind DTD (Document Type
Definition)
* XSL - Extensible Style Language este un limbaj de stiluri care permite asocierea unei
semantici fiecarui nod dintr-un document XML
* XML Pointer Language (XPointer) and XML Linking Language (XLink) - aceste
doua tehnologii definesc o metoda standard pentru reprezentarea legaturilor dintre
resurse. Spre deosebire de asocierile simple, cum ar fi tagul HTML <a>, XML
implementeaza un mecanism de a defini legaturi intre mai multe resurse. XPointer
descrie modul de adresare a acestor resurse, in timp ce XLink descrie modul in care
pot fi asociate doua sau mai multe resurse.
Avantaje XML
- XML descrie continutul si modul de afisare al continutului;
- informatia este mai usor de gasit si manipulat daca este in format XML;
- XML ofera facilitati multiple si imbunatatite de prezentare (de exemplu folosind
browserele)

Dezvoltare de aplicatii in Visual Studio .NET

Page 177 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

XML si .Net .Net Framework pune la dispozitia programatorilor un set de clase pentru
manipularea documentelor XML. Aceste clase se afla, in marea lor majoritate, in spatiul
de nume System.Xml.
Principalele clase din System.Xml sunt:
* XmlTextReader - permite accesul rapid, forward only, la continutul unui document
XML;
* XmlNodeReader - clasa care furnizeaza un XmlReader pentru un subarbore DOM;
* XmlValidatingReader - permite validarea documentelor XML folosind scheme DTD,
XSD si XDR;
* XmlTextWriter - clasa folosita pentru generarea de documente XML;
* XmlDocument - clasa care implementeaza specificatiile DOM
* XmlDataDocument - furnizeaza o implementare a unui XmlDocument care poate fi
asociat cu un DataSet. Acest document poate fi apoi manipulat folosind atat
reprezentarea relationala furnizata de DataSet, cat si reprezentarea sub forma de
arbore a unui XmlDataDocument;
* XPathDocument - permite procesari XSLT rapide asupra unui document XML;
* XslTransform - permite transformari XSLT asupra unui document XML;
* XmlSchema - permite crearea, pe durata rularii programului, a schemelor XSD,
respectand specificatiile W3C XSD;
* XmlSchemaCollection - furnizeaza o multime de scheme XSD si XDR (XMl Data
Reduced). Aceste scheme, incarcate in memorie, permit o validare rapida pe durata
parsarii pentru XmlValidatingReader.
Citirea unui fisier XML
Clasa XmlReader furnizeaza un API (Application Program Interface) pentru parsarea
documentelor XML. O implementare a acestei clase este XmlTextReader. De obicei,
se foloseste XmlTextReader daca se doreste accesul rapid la un document XML, fara
overheadul introdus de construirea arborelui DOM.
XmlTextReader reader = new XmlTextReader ("books.xml");
In exemplul anterior, documentul XML este incarcat dintr-un fisier. XmlTextReader
furnizeaza constructori si pentru incarcarea din stream-uri. Un stream este o
reprezentare abstracta a unui dispozitiv de intrare/iesire, care este sursa sau destinatia
datelor. Un stream este independent de dispozitivul din care citeste/scrie astfel nct
programul nu necesita modificari daca sursa streamului se schimba. In exemplul
urmator este prezentata metoda de incarcare a unui document XML dintr-un stream:
StringReader stream;
XmlTextReader reader = null;
try
{

Page 178 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

stream = new StringReader ("<?xml version='1.0'?>" +


"<book>some book</book>");
reader = new XmlTextReader (stream);
//proceseaza documentul incarcat
if (reader != null)
reader.Close();
}
In acelasi timp, un document XML poate fi incarcat de pe web, furnizand ca sursa o
adresa web:
private const string URLString = "http://localhost/books.xml";
XmlTextReader reader = new XmlTextReader (URLString);
O data incarcat fisierul, XmlTextReader citeste secvential (folosind metoda Read())
continutul xml. Metoda Read() returneaza valoarea false cand nu mai este nimic de
citit:
while (reader.Read())
{
// do something... ;
}
Pentru a procesa informatiile XML, fiecare inregistrare (nod) citita din fisier are un tip
(ce poate fi obtinut folosind proprietatea NodeType).
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
Console.Write ("<" + reader.Name);
while (reader.MoveToNextAttribute())
Console.Write(" " + reader.Name + "='" + reader.Value + "'");
Console.Write (">");
break;
case XmlNodeType.DocumentType:
Console.WriteLine (reader.NodeType + "<" + reader.Name + ">" +
reader.Value);
break;
Dezvoltare de aplicatii in Visual Studio .NET

Page 179 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

}
}
Valoarea intoarsa de NodeType depinde de clasa care este utilizata. De exemplu,
XmlTextReader nu intoarce niciodata XmlNodeType care reprezinta un nod Document,
DocumentFragment, Entity, EndEntity sau Notation. Tipul continut de NodeType este
conform specificatiilor W3C DOM. Proprietatea Depth intoarce nivelul nodului curent in
arborele Xml. Aceste informatii sunt utilizate in formatarea unui document XML. Nodul
radacina are Depth = 0. Combinand informatiile furnizate de proprietatile Name, Value
si Depth, se poate executa scrierea formatata a unui document XML la consola sau
intr-un fisier.
Sinteza:
- XmlTextReader furnizeaza acces rapid, forward only, la continutul XML;
- XmlTextReader implementeaza specificatiile W3C;
- XmlTextReader furnizeaza constructori pentru citirea unui document XML dintr-un
fisier, stream sau XmlReader;
- metoda Read citeste secvential toate nodurile din documentul XML;
- pentru nodurile element, atributele pot fi obtinute folosind metoda
MoveToNextAttribute(), ceea ce furnizeaza tot o citire secventiala a atributelor;
- atributele sunt reprezentate ca o lista atasata nodului curent;
Scrierea unui fisier XML
Pentru scrierea unui document XML, se folosesc clase derivate din XmlWriter.
XmlWriter furnizeaza un API care permite scrierea intr-un fisier, intr-un stream sau
intr-un TextWriter. O clasa derivata din XmlWriter este XmlTextWriter. XmlTextWriter
nu construieste arborele DOM, furnizand astfel un acces rapid la output (fisier, stream,
etc) si inlaturand overhead-ul introdus de arborele DOM. Aceasta clasa executa o serie
de verificari si validari ale documentului xml, pentru a asigura structura corecta a
documentului care este scris. Atunci can una din aceste validari esueaza (documentul
nu este un document xml valid), se arunca o exceptie, fiind recomandata specificarea
de handleri care sa trateze aceste exceptii.
XmlTextWriter myXmlTextWriter = new XmlTextWriter ("books.xml",
null);
Cel de-al doilea parametru al contructorului precizeaza care este encoding-ul fisierului.
Daca acesta este null, se considera ca fisierul este scris in format UTF-8 . Exemplul
urmator demonstreaza modul in care poate fi scris un singur element (book) intr-un
fisier xml:
myXmlTextWriter.Formatting = System.Xml.Formatting.Indented;
myXmlTextWriter.WriteStartDocument(false);
myXmlTextWriter.WriteDocType("bookstore", nothing, "books.dtd",
nothing);
myXmlTextWriter.WriteComment("Cartile lui Mark Twain");
Page 180 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

myXmlTextWriter.WriteStartElement("bookstore");
myXmlTextWriter.WriteStartElement("book", null);
myXmlTextWriter.WriteAttributeString("genre","autobiography");
myXmlTextWriter.WriteAttributeString("publicationdate","1979");
myXmlTextWriter.WriteAttributeString("ISBN","0-7356-0562-9");
myXmlTextWriter.WriteElementString("title", null, "The
Autobiography of Mark Twain");
myXmlTextWriter.WriteStartElement("Author", null);
myXmlTextWriter.WriteElementString("first-name", "Mark");
myXmlTextWriter.WriteElementString("last-name", "Twain");
myXmlTextWriter.WriteEndElement();
myXmlTextWriter.WriteElementString("price", "7.99");
myXmlTextWriter.WriteEndElement();
myXmlTextWriter.WriteEndElement();
//Scrie tot textul XML si inchide fisierul
myXmlTextWriter.Flush();
myXmlTextWriter.Close();
Scrierea diverselor elemente ale unui document xml se face folosind functii
specializate: WriteDocType, WriteComment, WriteStartElement, WriteAttributeString,
WriteElementString, WriteEndElement, etc. Se observa ca exista o corespondenta intre
apelul functiilor WriteStart... si apelul functiilor WriteEnd....
Sinteza
- XmlTextWriter permite scrierea de documente XML care respecta specificatiile W3C;
- XmlTextWriter are constructori care permit scrierea intr-un fisier, stream sau
TextWriter;
- pentru fiecare tip de nod exista o functie permite scrierea acestuia.
Validarea unui document XML in timpul citirii
Utilizand clasa XmlValidatingReader se poate face validarea unui document XML in
timpul citirii sale. Validarea se poate face conform definitiilor dintr-un fisier DTD, XSD
sau XDR. Pentru a specifica exact tipul de validare se foloseste proprietatea
ValidationType, astfel (tip de validare - descriere): - Auto: implicit
- None: nu se face validare in timpul parsarii
- DTD: validare conforma definitiilor DTD
- Schema: validare conform definitiilor XSD
- XDR: validare conform definitiilor XDR

Dezvoltare de aplicatii in Visual Studio .NET

Page 181 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Exemplu:
XmlTextReader myXmlTextReader = new XmlTextReader (document1);
XmlValidatingReader myXmlValidatingReader = new
XmlValidatingReader(myXmlTextReader);
myXmlValidatingReader.ValidationType = ValidationType.DTD;
Parserul nu se opreste la erorile de validare, ci in cazul in care documentul XML nu
este bine format (nu respecta standardul XML). Datorita acestui fapt este permisa
detectarea tuturor erorilor de validare printr-o singura parsare, si nu este necesara
reparsarea documentului. In exemplul urmator este prezentat modul in care este
apelata o metoda handler atunci cnd se intalneste o eroare la validare. Atasarea
acestui handler se face folosind clasa ValidationEventHandler inainte de a incepe
citirea documentului XML. Daca nu este furnizat un astfel de handler,
XmlValidatingReader arunca o exceptie de tipul XmlSchemaException atunci cand se
intalneste prima eroare.
private void Validate ()
{
try
{
// setarea handler-ului pentru erorile la validare
myXmlValidatingReader.ValidationEventHandler += new
ValidationEventHandler (ValidationEvent);
while (myXmlValidatingReader.Read())
{
// instructiuni...
}
}
catch (Exception e)
{
Console.WriteLine ("Exception: {0} ", e.ToString());
}
}
private void ValidationEvent (object, errorID,
ValidationEventArgs) args)
{
Console.Write ("Eroare la validare: " + args.Message);
Page 182 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

}
Sinteza:
- validarea poate fi efectuata folosind scheme DTD, XSD si XDR
- validarea are loc pe durata efectuarii operatiilor de citire si parsare
- handlerul ValidationEventHandler trebuie initializat pentru a primi toate notificarile
legate de erorile de validare aparute
- erorile de validare nu stopeaza parsarea documentului XML

2. Servicii Web
Introducere...
XML Web services reprezinta componente program care permit construirea de aplicatii
scalabile, independente de platforma. Serviciile Web permit aplicatiilor sa interschimbe
mesaje utilizand protocoale standard cum ar fi HTTP, XML, XSD, SOAP si WSDL.
Pot fi create servicii web care sa ofere functionalitati specifice aplicatiilor client pe web.
Mediul de dezvoltare integrat Visual Studio .NET ofera posibilitatea crearii de proiecte
pentru aplicatii desktop distribuite, aplicatii Web applications si servicii XML Web.
Dupa crearea unui serviciu Web, acesta trebuie instalat pe un server Web pentru a
deveni disponibil aplicatiilor care doresc sa utilizeze acest serviciu. Instalarea unui
serviciu Web pe un Web server se poate realiza prin copierea fisierelor asociate pe
serverul Web.
Mecanismul de descoperire a serviciilor XML Web permite aplicatiilor client sa
localizeze documentele care descriu unserviciu XML Web service. Se returneaza,
astfel, catre client, un document care descrie serviciul web. Acest document este scris
in WSDL (Web Service Description Language) si contine informatii despre capabilitatile
serviciului XML Web, locatia si modalitatea in care se poate interactiona cu acesta.
Dupa crearea si instalarea unui serviciu XML Web, orice aplicatie va avea, teoretic,
permisiunea de a accesa si consuma servicul respectiv. Aplicatia care consuma un
serviciu Web este cunoscuta sub numele de client al serviciului Web. Un client poate fi
o componenta, serviciu sau o aplicatie desktop.
Crearea unui serviciu web in Visual Studio .NET
Crearea unu serviciu web este foarte usoara. De fapt, folosind Visual Studio se poate
crea un serviciu web fara sa fie necesara scrierea de cod. Exemplul urmator va crea un
serviciu web numit MyService, in directorul WebServices.
La crearea proiectului, se alege ca optiune Web Service. Va fi creat un nou
namespace, numit MyService, si cateva clase care vor oferi functionalitatea serviciului
Dezvoltare de aplicatii in Visual Studio .NET

Page 183 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

web.
Implicit sunt create urmatoarele clase:
- Global (in fisierul Global.asax) - derivata din HttpApplication (acest fisier este
echivalent cu fisierul Global.asa din ASP)
- WebService1 (in fisierul WebService1.cs) - clasa derivata din
System.Web.Services.WebService; aceasta este clasa care implementeaza logica
serviciului web care urmeaza a fi realizat. Metodele din aceasta clasa vor fi apelate
ulterior. Componenta webservice va fi creata in directorul bin si se va numi
MyService.dll. Initial, clasa creata de Visual Studio .Net arata astfel:
namespace MyService
{
...
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace="http://tempuri.org",
Description="This is a demonstration WebService.")]
public class WebService1 : System.Web.Services.WebService
{
public WebService1()
{
//CODEGEN: This call is required by the ASP+ Web Services
Designer
InitializeComponent();
}
...
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
Implicit este creata si o metoda HelloWorld (comentata). Daca se decomenteaza
aceasta metoda avem un prim serviciu web functional (care va afisa un simplu mesaj).
Page 184 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Orice serviciu web trebuie asociat cu un namespace. Implicit namespace-ul este


http://tempuri.org. Daca proiectul este compilat in starea actuala vom primi un mesaj
prin care ni se cere sa alegem un alt namespace. De obicei acest namespace este
numele site-ului/serverului unde acest serviciu web este disponibil. Pentru a testa
proiectul, se executa click dreapta pe fisierul WebService1.asmx in Solution Explorer si
din meniu se alege "View in Browser". Este afisata o pagina web care are un buton
"Invoke". La apasarea acestui buton, este apelata functia HelloWorld care intoarce un
string.
In continuare vom extinde acest exemplu. Vom defini o metoda care intoarce un vector
de structuri definite de cadrul aplicatiei. Intai vom defini structura:
public struct ClientData
{
public String Name;
public int ID;
}
si apoi o metoda GetClientData. De remarcat, folosirea atributului WebService pentru
aceasta metoda. Acesta atribut face ca metoda sa poata fi accesibila dintr-un serviciu
web.
[WebMethod]
public ClientData[] GetClientData(int Number)
{
ClientData[] Clients = null;
if (Number > 0 and Number <= 10)
{
Clients = new ClientData[Number];
for (int i = 0 to Number)
{
Clients[i].Name = "Client " + i.ToString();
Clients[i].ID = i;
}
}
return Clients;
}
Daca deschidem fisierul .asmx dupa compilare, vom vedea un formular care permite
introducerea unei valori pentru parametru. Introducand o valoare care nu reprezinta un
numar intreg, va fi generata o eroare. Daca se introduce o valoare care nu este in
Dezvoltare de aplicatii in Visual Studio .NET

Page 185 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

intervalul 0-10, se va obtine un vector nul. Introducand o valoare intre 0-10 se va obtine
un xml cu elemente de tipul:
<clientData>
<Name>Client 0</Name>
<ID>0</ID>
</clientData>
Crearea unui serviciu web folosind Visual Studio .Net este o operatie relativ facila, cu
un grad mare de utilitate.

Page 186 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 13. ASP.NET - XII


1. Introducere
Odata cu aparitia Internetului si a infrastructurii World-Wide-Web nascuta in anii 90,
ideea si solutia aplicatiilor distribuite a capatat o alta culoare. Aplicatiile distribuite au
luat nastere in urma vizualizarii clare a lumii informatice, a imposibilitatii de a avea
dispozitive informatice care sa ruleze aplicatii monopost complexe, lucru care evident
nu a condus decat la o centralizare a informatiei si a aplicatiilor in general. Bazata pe
modelul client/server, platforma WWW ofera o infrastructura viabila si testata ca
serviciu al retelei Internet si promite la nivel de client o interfata standardizata, chiar
independenta de platforma, comuna pentru vizualizarea informatiilor Web, interfata
cunoscuta sub numele de browser sau navigator Web.
Modelul de realizare a aplicatiior Web a cunoscut o intreaga evolutie a tehnologiilor de
programare la nivel de server.
Putem enumera astfel:
* solutia CGI (Common Gateway Interface) reprezinta o serie de script-uri executate pe
serverul WWW. Acestea pot fi scrise in orice limbaj de programare (interpretat sau
compilat) cu respectarea urmatoarelor restrictii: programul scrie datele la iesirea
standard si genereaza antete care permit serverului Web sa interpreteze corect iesirea
scriptului, conform specificatiilor HTTP (de exemplu, se pot folosi limbaje precum bash,
Perl, C/C++, Delphi). Neajunsul CGI-urilor il reprezinta faptul crearii unui nou proces pe
serverul Web pentru fiecare cerere si restrictionarea task/fisier executabil.
* solutia ISAPI (Internet Server API) reprezinta o alternativa CGI pe platforme
Windows. Dezvoltatorii Win32 pot scrie un program care sa comunice direct cu aceasta
interfata pentru a face orice lucru posibil cu CGI, pot folosi ISAPI pentru a obtine date
din formulare si pentru a trimite continut HTML la client. Codul la nivel de server poate
fi scris in oricare limbaj cu suport pentru DLL-uri Windows, ca C/C++, Java, Visual
Basic, rezultatul compilarii fiind un fisier .dll. Fata de CGI, ISAPI ruleaza in acelasi
spatiu de adrese cu serverul HTTP, are acces la toate resursele serverului HTTP, pot fi
incluse mai multe task-uri intr-un .dll si nu creeaza procese aditionale pentru rezolvarea
cererilor clientilor Web. O alternativa la ISAPI este NSAPI-utilizabila in cadrul serverului
Web Netscape.
* solutia PHP (1994) sau ASP (1996) marcheaza un salt in dezvoltarea aplicatiilor
Web. Desi difera din punct de vedere al sintaxei, ambele limbaje sunt interpretate,
codul lor fiind stocat in fisiere externe cu extensia .php/.asp. De fapt, ASP nu ofera un
limbaj nou, ci se bazeaza pe limbajele VBScript si JScript. Un fisier PHP/ASP poate fi
combinat cu date de tip text, marcatori HTML si comenzi script. in momentul executiei,
in urma cererii unui client Web, fisierul este procesat, fiecare script din cadrul lui este
interpretat si rezultatul executiei este introdus inapoi in fisierul static HTML inainte ca
rezultatul sa fie trimis catre browser. Mai mult, in sprijinul programatorului, limbajele
pun la dispozitia acestuia o serie de metode si obiecte care usureaza lucrul cu
cookie-uri, cu bazele de date (Oracle, MSSQL, MySQL, etc.), care preiau elegant
intrarile unui formular HTML si le proceseaza pe server, care preiau informatii despre
utilizator (clientul Web), care trimit informatii la utilizator, care stocheaza informatii
despre sesiunea unui utilizator (Session), care partajeaza informatii intre utilizatorii unei
Dezvoltare de aplicatii in Visual Studio .NET

Page 187 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

aplicatii (Application) s.a.m.d.. Mai nou, din partea PHP-ului, incepand cu versiunea
4.0, acesta ofera suport pentru programarea obiectuala: incapsularea datelor,
mostenirea si polimorfismul. Aceste modele completeaza destul de bine suportul
dezvoltarii aplicatiilor Web, insa aduc unele limitari: sunt lente deoarece la fiecare
accesare fisierele sunt procesate si interpretate (in loc sa fie compilate), nu sunt
capabile sa construiasca controale reutilizabile care sa incapsuleze functionalitati
complexe pentru interactiunea cu utilizatorul.
* JSP (JavaServer Pages) face parte din familia Java si reprezinta o tehnologie care
permite crearea de aplicatii Web independente de platforma. JSP separa interfata
utilizator de continutul generat dinamic permitand schimbarea intregului sablon al
site-ului WEB fara a altera informatiile afisate. Tehnologia utilizeaza marcatori XML si
scripturi scrise in limbajul de programare Java pentru a incapsula logica aplicatiei care
genereaza continutul paginilor WEB. JSP-urile sunt o extensie a tehnologiei Java
Servlet. Servlet-urile sunt independente de platforma 100% si reprezinta module la
nivel de server care se integreaza in cadrul unei aplicatii Web si care pot fi utilizate
pentru a extinde capabilitatile unui server WEB. Tehnologia JSP si servlet-urile ofera o
alternativa pentru crearea aplicatiilor WEB fata de alte limbaje de scripting/programare
a aplicatiilor WEB, oferind independenta de platforma, performanta, separarea logicii
aplicatiei de partea de interfata utilizator, administrare usoara si extensibilitate.
Astfel, odata cu aparitia noii platforme .NET, Microsoft a adus o noua tehnologie in
programarea si dezvoltarea aplicatiilor dinamice pentru Web, si anume, ASP.NET. Desi
nu putem spune clar ca ASP.NET este o versiune urmatoare a ASP-ului, acesta
pastreaza compatibilitatea cu aplicatiile scrise in ASP.

2. Aplicatii ASP.NET. WebForms


Anatomia unei aplicatii ASP.NET
O aplicatie Web in ASP.NET include un numar diferit de fisiere si directoare, acestea
incluzand la randul lor pagini ASP.NET, controale utilizator, fisiere ale serviciilor Web
XML, fisiere de configurare si assembly-uri. Un assembly este formula atomica prin
care o aplicatie este reprezentata la runtime.
Paginile ASP.NET, numite si WebForms-formulare Web, permit crearea de interfete
utilizator pentru aplicatiile Web, prezentand informatia catre orice browser sau
dispozitiv client. Ele reprezinta un model scalabil de programare la nivelul serverului
pentru a genera dinamic pagini Web.
WebForms-modelul formularelor Web in ASP.NET
Pentru a prezenta informatii in navigatorul clientului folosim formularele Web ASP.NET
care ofera o abstractizare in modelul de programare, un model orientat obiect si bazat
pe evenimente. Acest mediu de lucru beneficiaza de toate facilitatile oferite de
platforma .NET (siguranta tipurilor, mediu de executie controlat, mostenire) si
reprezinta o inlocuire a clasicelor formulare HTML.
Asemanator modelului de programare WinForms (oferit de aplicatiile clasice in Visual
C++ sau Visual Basic) o pagina WebForms este formata din doua parti: componenta
Page 188 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

vizuala (furnizand interfata cu utilizatorul) si logica aplicatiei (oferind implementarea


efectiva).
Componenta vizuala este reprezentata de un fisier cu extensia .aspx-actionand ca un
container pentru HTML, text static si controale server care pot fi afisate in browser, iar
logica aplicatiei este reprezentata de un fisier cu extensia .cs (pentru limbajul Visual
C#) sau .vb (pentru Visual Basic.NET). Fisierele .aspx mai sunt referite ca pagini
ASP.NET. Aceasta tehnica de separare a codului de partea de prezentare este numita
"code-behind programming", metoda care elimina anumite disfunctionalitati de
programare aducand robustete si dezvoltare usoara a paginilor. Solutia oferita permite
detectarea erorilor de programare in timpul compilarii si nu in timpul primei accesari ale
paginii Web si elimina codul "spagetti" dintr-un fisier HTML imbricat cu script-uri care
era greu de scris si de intretinut.
Logica aplicatiei reprezinta in fapt o clasa care extinde functionalitatea clasei
System.Web.UI.Page. Aceasta clasa contine metode care trateaza diferite evenimente
ce apar in timpul executiei formularului Web la server (de exemplu, daca metoda
Page_Load este conectata la evenimentul Load al clasei de baza Page, atunci aceasta
este apelata la fiecare acces al unui formular Web), proprietati (de exemplu, prin
proprietatea IsPostBack putem afla daca o pagina Web este la primul acces sau la
accesari ulterioare), atribute corespunzatoare unor controale din pagina WebForms si
alte date membre necesare implementarii aplicatiei.
In ASP.NET, cu putine modificari, oricare pagina Web Forms poate fi reutilizata in alta
pagina ca un control server, numit prin extensie user controls. Controalele utilizator
ofera la randul lor acelasi model abstract de programare, orientat pe obiecte si bazat
pe evenimente, insa nu este posibila accesarea lor independenta, fiind necesare a fi
incluse intr-o pagina WebForms. Clasa pe care o extinde un control utilizator este
System.Web.UI.UserControls, iar fisierul care implementeaza un astfel de control are
extensia .ascx. Asemanator WebForm-urilor, controalele utilizator sunt compilate la
primul acces si stocate in memoria serverului pentru a reduce timpul de raspuns
cererilor succesive. Toate fisierele care fac parte din logica aplicatiei din cadrul
paginilor Web- codul din spate-sunt compilate intr-o biblioteca dinamica .dll, fiecare
pagina Web fiind reprezentata de o clasa derivata din clasa System.Web.UI.Page.
Pentru fisierele .aspx, la prima cerere a browser-ului, runtime-ul ASP.NET genereaza o
a doua bilblioteca dinamica .dll, temporara, care contine o clasa ce mosteneste clasa
corespunzatoare din primul assembly (.dll), iar in momentul rularii (executiei), cand un
utilizator face o cerere a unei pagini, se executa .dll-urile asociate si rezultatul executiei
este trimis la client intr-unul din limbajele HTML, XML, WML si ECMAScript (Jscript,
JavaScript). Acest rezultat este influentat de capabilitatile navigatorului client, care
poate fi chiar un dispozitiv mobil, astfel paginile WebForms transmit cod HTML
compatibil browser-ului. De altfel, in functie de browser, pentru Internet Explorer 5 sau
ulterior paginile WebForms pot fi programate pentru a beneficia de toate facilitatile
acestuia.
Arhitectura ASP.NET suporta si un model asemanator ASP-ului, in care elementele de
interfata si codul se afla in acelasi fisier, functionalitatea fiind aceeasi cu cea oferita de
modelul cu doua fisiere. Totusi, exista mici diferente, la compilare codul din pagina nu
mai este compilat intr-un fisier separat, clasa din .dll-ul asociat paginii .aspx deriva
direct din clasa System.Web.UI.Page. Acest model are avantajul ca poate fi usor de
utilizat in dezvoltarea paginilor Web.

Dezvoltare de aplicatii in Visual Studio .NET

Page 189 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Modelul de executie
Modelul de executie al paginilor .aspx este format din mai multe etape, pornind de la
cererea clientului pana la procesul executat de server. Vom observa ca viteza de
raspuns a unei cereri este optimizata dupa prima accesare.
La prima accesare a unei pagini .aspx, procesul de raspuns al serverului ASP.NET
este alcatuit din mai multi pasi. Acestia sunt:
- procesarea si interpretarea codului sursa
- trimiterea acestuia compilatorului
- ASP.NET invoca compilatorul in urma caruia rezulta unul sau mai multe assembly-uri
(cod intermediar-IL), plasat apoi in assembly cache
- mediul de executie incarca in memorie si executa codul intermediar, iar rezultatul este
trimis la client
Elementele constitutive ale unui WebForm
O pagina WebForms contine un numar de comenzi denumite directive la nivel de
pagina care pot fi stocate in fisierele .aspx. Aceste directive au sintaxa @ <nume
directiva> si sunt incadrate de simbolurile <% si %> (reminiscenta ASP), pozitia lor
fiind la inceputul paginii .aspx. Rolul lor este de a specifica anumite configuratii cand
este procesata o pagina WebForms.
Paginile WebForms suporta urmatoarele directive:
@ Page - defineste atribute specifice paginii WebForms care sunt utilizate de analizor
si compilator (doar pentru fisiere .aspx).
@ Control - defineste atribute specifice controalelor utilizator care sunt utilizate de
analizor si compilator (doar pentru fisiere .ascx).
@ Import - importa un spatiu de nume explicit intr-o pagina sau control utilizator.
@ Implements - indica unei pagini sau control utilizator ca implementeaza o interfata
specifica .NET Framework.
@ Register - inregistreaza controale utilizator si controale obisnuite pentru a fi utilizate
intr-un WebForms.
@ Assembly - creeaza legaturi catre assembly-uri in timpul compilarii, facand
disponibile clasele si interfetele din assembly-uri pentru a fi folosite in pagina.
@ OutputCache - declara politici de caching pentru controale dintr-o pagina sau user
control.
@ Reference - adauga referinte catre un fisier .aspx sau .ascx extern.
Ciclul de viata al unei pagini WebForms
Intr-o aplicatie Web, datorita naturii protocolului HTTP, procesul in care un browser
acceseaza o resursa Web se rezuma la urmatorii pasi:
* se stabileste o legatura cu serverul Web care primeste cererea resursei;

Page 190 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

* resursa este procesata de server in functie de caracteristicile ei (e.g. script-uri ASP);


* rezultatul executiei este trimis la client;
* resursele ocupate de serverul Web la procesarea cererii sunt eliberate din memorie;
conexiunea de la primul pas poate fi eliberata.
Datorita acestui model, paginile Web pot fi considerate lipsite de stari (stateless). De
obicei, un navigator prezinta informatii unui client intr-un formular electronic. Acesta
(clientul) interactioneaza cu elementele din formular modificand anumite stari ale
controalelor, lucru care cauzeaza in final o trimitere a paginii pe server pentru a fi
procesate informatiile curente. Serverul proceseaza pagina conform modificarilor, apoi
returneaza formularul browser-ului. Aceasta secventa este cunoscuta si sub numele de
round trip.
Singurul eveniment provocat de utilizator pentru trimiterea formularului la server este
rezultatul selectarii unui buton care cauzeaza un round trip. Din acest motiv,
evenimentele in ASP.NET sunt limitate la evenimente de tip click, multe dintre
controalele ASP.NET implementandu-le pentru diferite actiuni ale utilizatorului.
O pagina WebForms, la procesarea pe serverul Web, poate fi privita ca un program
executabil pentru care iesirea standard o reprezinta browserul sau dispozitivul client. In
acest model, pagina trece printr-o serie de stagii de procesare: initializare, procesare si
eliberare. In ordinea aparitiei, acestea sunt:
* Init, eveniment care initializeaza pagina si in care proprietatile controalelor sunt
actualizate. Aici este corect sa initializam controale care se adauga dinamic la pagina
sau variabile necesare inainte de initializarea paginii;
* Load poate fi numit locul in care utilizatorul isi initializeaza codul. Evenimentul este
generat de fiecare data cand pagina este incarcata dupa ce controalele au fost
initializate la pasul anterior;
* Tratarea evenimentelor utilizator, reprezinta stagiul in care sunt tratate evenimentele
generate de client cum ar fi: schimbarea unui text intr-un control, apasarea unui buton
etc. Trebuie retinut ca aceste evenimente nu sunt tratate intr-o anumita ordine pe
server, iar tratarea lor are loc dupa aparitia unui eveniment Click care trimite formularul
la server (a unui submit);
* PreRender, eveniment care poate fi folosit pentru a face ultimile actualizari asupra
paginii Web inainte ca aceasta sa fie generata la client;
* Render, eveniment care genereaza la client reprezentarea HTML a paginii Web
ASP.NET incarcata la server;
* Unload este ultimul eveniment care se executa inainte ca pagina sa fie eliberata.
Evenimentul este util de folosit atunci cand dorim sa efectuam ultimele operatii de
eliberare a resurselor: inchiderea fisierelor, a conexiunilor la baza de date si eliberarea
obiectelor din memorie.

3. Controale
Dezvoltare de aplicatii in Visual Studio .NET

Page 191 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Controale server
Unul din aspectele care vor duce la o dezvoltare rapida a interfetelor utilizator pentru
paginile WebForms il reprezinta controalele server. Putem prognoza un viitor
asemanator evolutiei componentelor COM. Controalele server sunt folosite pentru a
crea interfata-utilizator in paginile WebForms. Caracteristicile acestora pot fi rezumate
astfel: expun un model orientat obiect, incapsuleaza un mecanism de persistenta a
starilor intre round-trip-uri, genereaza evenimente client care sunt tratate la server, la
executie genereza cod compatibil browser-ului sau dispozitivului destinat (detectat in
mod automat).
Exista doua tipuri de baza in care pot fi impartite controalele:
* HTML Controls, reprezinta elemente HTML care pot fi programate la nivelul serverului
si expun un model obiectual restrictionat la capabilitatile elementelor HTML pe care le
afiseaza;
* Web Controls, aduc facilitati superioare controalelor HTML incluzand controale mult
mai complexe, cum ar fi controlul calendar, iar modelul obiect nu reflecta neaparat
sintaxa HTML.
Prin extensie, se definesc alte doua tipuri de controale, si anume:
- controale de validare incapsuleaza functionalitati care permit validarea intrarilor
utilizatorului. Acestea se ataseaza controalelor de intrare ale utilizatorului si furnizeaza
mai multe tipuri de verificari ale datelor. Functionalitatea controalelor de validare poate
fi dedusa usor din numele claselor de care sunt reprezentate: CompareValidator,
CustomValidator, RangeValidator, RegularExpressionValidator,
RequiredFieldValidator. - controale utilizator sunt similare paginilor WebForms, diferind
de acestea prin faptul ca fisierele au extensia .ascx si nu contin tagurile <HTML>,
<BODY>, <FORM>, aceste elemente aflandu-se in pagina gazda.
Controale HTML
Primul set de controale, HTML Controls, reprezinta elemente HTML care contin
atribute facand posibila programarea lor pe server. Fiecare element HTML poate fi
programat pe server prin adaugarea atributului runat="server" si asignarea unui atribut
ID pentru a putea fi referit controlul ca membru de clasa in codul de pe server (aceasta
abordare este posibila si la ASP). Acest ID trebuie sa fie unic in cadrul paginii Web
pentru a nu aparea conflicte de nume in tratarea lor pe server. Controalele HTML sunt
instante ale claselor definite in spatiul de nume System.Web.UI.HtmlControls si sunt
derivate direct/indirect din clasa de baza HtmlControl.
De exemplu, urmatorul cod creeaza un control de editare text care este reprezentat la
runtime de clasa System.Web.UI.HtmlControls.HtmlInputText:
ASP.NET furnizeaza controale HTML predefinite, de la formulare pana la controale
pentru introducerea de informatii text pe una sau mai multe linii, de la checkbox-uri
pana la controale de selectie, butoane de tip submit, list box-uri, tabele, imagini si alte
controale corespunzatoare elementelor HTML.
Cand un WebForms continand controale HTML este procesat pe server, se creeaza
cate o instanta pentru fiecare control, iar atributele acestora devin proprietati ale
claselor corespunzatoare. Atributele nerecunoscute sunt ignorate, dar sunt accesibile
Page 192 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

pe server folosind colectia Attributes a clasei controlului.


Controalele HTML ASP.NET sunt utile atunci cand dorim sa convertim o aplicatie
clasica HTML sau ASP la ASP.NET pentru a putea programa controalele la nivel de
server. Mai mult, ele sunt o alegere buna atunci cand dorim sa programam controlul
atat la client cat si la server deoarece sintaxa lor, in ambele parti, este identica (sunt
tratate ca text simplu). In schimb, acestea prezinta si dezavantaje, cum ar fi faptul ca
toate valorile controalelor sunt siruri de caractere, deci nu se aplica siguranta tipurilor
oferita de platforma .NET, iar suportul pentru detectarea tipului navigatorului client
lipseste.
Tabel: corespondenta dintre elementele HTML si controalele HTML ASP.NET
Tag

Control HTML
corespunzator

<a runat="server">

HtmlAnchor

<button runat="server">

HtmlButton

<form runat="server">

HtmlForm

<img runat="server">

HtmlImage

<input type="button" runat="server">

HtmlInputButton

<input type="reset" runat="server">

HtmlInputButton

<input type="submit" runat="server">

HtmlInputButton

<input type="checkbox" runat="server">

HtmlInputCheckBox

<input type="file" runat="server">

HtmlInputFile

<input type="hidden" runat="server">

HtmlInputHidden

<input type="image" runat="server">

HtmlInputImage

<input type="radio" runat="server">

HtmlInputRadioButton

<input type="password" runat="server">

HtmlInputText

<input type="text" runat="server">

HtmlInputText

<select runat="server">

HtmlSelect

<table runat="server">

HtmlTable

<td runat="server">

HtmlTableCell

<th runat="server">

HtmlTableCell

<tr runat="server">

HtmlTableRow

<textarea runat="server">

HtmlTextArea

Orice alt tag cu atributul runat="server"

HtmlGenericControl

Controale Web avansate


Pentru a abstractiza mai mult modelul de programare al paginilor WebForms,
Dezvoltare de aplicatii in Visual Studio .NET

Page 193 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

ASP.NET defineste un al doilea tip de controale - Web Controls. Numite si controale


inteligente, ele pot fi caracterizate prin:
* ofera un bogat si consistent model obiectual de programare;
* detecteaza automat tipul navigatorului, iar afisarea la client va fi optimizata in functie
de capabilitatile acestuia;
* pentru unele controale se pot defini sabloane (template-uri) de afisare;
* posibilitatea de a controla generarea evenimentelor pe server;
* posibilitatea de a trimite evenimente unui container din interiorul acestuia (de
exemplu, un control de tip buton in interiorul unui tabel);
* legarea la surse de date a tuturor proprietatilor controalelor pentru a influenta afisarea
la executie.
Sunt definite in spatiul de nume System.Web.UI.WebControls si mostenesc, direct sau
indirect, clasa de baza WebControl.
Adaugarea controalelor Web Controls in paginile WebForms se face in acelasi mod in
care se adauga un element HTML. Totusi, sintaxa de reprezentare a unui control
intr-un fisier .aspx (.ascx) respecta urmatoarele criterii:
* conform sintaxei XML sunt declarate elemente care refera spatiul de nume asp;
* toate elementele trebuie sa aiba marcaj de sfarsit;
* includ atributul runat= "server";
* au definit atributul ID care permite programarea controlului la nivel de server;
* proprietatile controalelor sunt declarate ca atribute.

Label
Folosita pentru a afisa text static sau text conectat la o sursa de date in pagina:
<asp:Label runat="server" Text="un text" Font-Italic="true"
Font-Name="Arial" Font-Size="12"></asp:Label>
TextBox
Permite editarea textului folosind mai multe moduri de utilizare prin proprietatea
TextMode (implicit SingleLine): editare pe o singura linie, pe linii multiple si pentru
introducerea unei parole:
<asp:TextBox runat="server" id="email" Text="exemplu:
utilizator@domeniu.ro" Font-Name="Tahoma" Width="200px"/>
<asp:TextBox runat="server" id="adresa" Font-Name="Tahoma"
TextMode="Multiline" Rows="3">str., bl., apt...</asp:TextBox>
<asp:TextBox runat="server" id="parola" TextMode="Password"
Page 194 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Width="200px"/>
CheckBox
Creeaza o caseta de marcare care permite selectarea unei stari true sau false. Pentru
utilizarea mai multor controale CheckBox exista alternativa controlului CheckBoxList cu
posibilitati de legare la o sursa de date. Se pot specifica formate de afisare folosind
proprietatile RepeatLayout si RepeatDirection.
<asp:CheckBox id="asigurat" runat="server" AutoPostBack="True"
Text="Asigurat medical" TextAlign="Right" />
Proprietatea AutoPostBack="True" este folosita pentru a trimite starea controlului pe
server imediat ce acesta a fost selectat/deselectat.
<asp:CheckBoxList id="checkboxlist1" CellPadding="5"
CellSpacing="5" RepeatColumns="2" RepeatDirection="Vertical"
RepeatLayout="Flow" TextAlign="Right" runat="server">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem>Optiunea 4</asp:ListItem>
</asp:CheckBoxList>
RadioButton
Ca si controlul CheckBox, acesta permite selectarea unui singur buton dintr-un grup
definit (excludere mutuala):
<asp:RadioButton runat="server" Text="Casatorit"
GroupName="StareCivila" />
<asp:RadioButton runat="server" Text="Necasatorit"
GroupName="StareCivila" Checked="true" />
RadioButtonList
Furnizeaza dezvoltatorului o singura selectie a unui buton radio dintr-un grup care
poate fi generat dinamic dintr-o sursa externa de date (de exemplu,. o baza de date).
<asp:RadioButtonList id=RadioButtonList1 runat="server"
RepeatLayout="Flow" RepeatColumns="2"
RepeatDirection="Horizontal">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem> Optiunea 4</asp:ListItem>
</asp:RadioButtonList>
Dezvoltare de aplicatii in Visual Studio .NET

Page 195 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

DropDownList Este utilizata pentru selectarea unei optiuni dintr-un numar de optiuni
afisate ca o lista drop-down . Aceasta lista poate fi conectata la o sursa de date
externa.
<asp:DropDownList runat="server">
<asp:ListItem>Selecteaza 1</asp:ListItem>
<asp:ListItem>Selecteaza 2</asp:ListItem>
<asp:ListItem>Selecteaza 3</asp:ListItem>
</asp:DropDownList>
ListBox
Este folosit pentru a genera o lista cu bara de derulare din care se pot selecta una sau
mai multe optiuni.
<asp:ListBox runat="server" SelectionMode="Multiple">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem>Optiunea 4</asp:ListItem>
<asp:ListItem>Optiunea 5</asp:ListItem>
<asp:ListItem>Optiunea 6</asp:ListItem>
</asp:ListBox>
Urmatoarele controale sunt utilizate pentru trimiterea informatiilor introduse in formular.
Atunci cand sunt apasate, continutul intregii pagini WebForms este trimis la serverul
Web. Acestea genereaza evenimentul Click la server care poate fi tratat in codul
programatorului.
Button
Creeaza un buton 3-D de submisie a unei pagini WebForms.
<asp:Button runat="server" Text="OK"></asp:Button>
LinkButton
Are aceeasi functionalitate ca a unui control Button, doar ca este afisat ca un hiperlink
in pagina.
<asp:LinkButton runat="server"
Text="Inregistrare"></asp:LinkButton>
HyperLink
Folosit pentru crearea unei legaturi catre un alt URL.

Page 196 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

<asp:HyperLink runat="server" Text="Viziteaza site-ul Facultatii


de Informatica, Iasi"
NavigateUrl="http://www.infoiasi.ro"></asp:HyperLink>
Controlul poate fi afisat ca text folosind proprietatea Text sau ca imagine utilizand
proprietatea ImageUrl.
Image
Permite afisarea unei imagini in cadrul paginii Web. Daca navigatorul nu poate afisa
imagini, se poate specifica un text in locul imaginii prin atributul AlternateText.
<asp:Image runat="server" ImageUrl="10.jpg"
AlternateText="Facultatea de Informatica"></asp:Image>
Panel
Reprezinta un container pentru alte controale si este util de folosit in situatia in care
trebuie adaugate dinamic controale in pagina Web sau trebuie ascunse/afisate un grup
de controale. De retinut ca acest control nu este vizual, doar grupeaza logic un grup de
controale din interiorul acestuia.
<asp:Panel id="partea1" runat="server"> Ai asigurare
medicala?<asp:CheckBox id="asigurat1" runat="server"
AutoPostBack="True" Text="Da" TextAlign="Right" />
Selecteaza starea civila:
<asp:RadioButton runat="server" Text="Casatorit"
GroupName="StareCivila" />
<asp:RadioButton runat="server" Text="Necasatorit"
GroupName="StareCivila" Checked="true" />
</asp:Panel>
Table, TableRow, TableCell
Aceste controale permit construirea unui tabel HTML dinamic folosind acelasi model
abstract orientat obiect pentru construirea altor controale Web.
<asp:Table id="Table1" runat="server" CellPadding=10
GridLines="Both" HorizontalAlign="Center">
<asp:TableRow>
<asp:TableCell>Linia 0, Coloana 0</asp:TableCell>
<asp:TableCell>Linia 0, Coloana 1</asp:TableCell>
</asp:TableRow>
<asp:TableRow>
<asp:TableCell>Linia 1, Coloana 0</asp:TableCell>
<asp:TableCell>Linia 1, Coloana 1</asp:TableCell>
</asp:TableRow>

Dezvoltare de aplicatii in Visual Studio .NET

Page 197 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

</asp:Table>
Calendar
Selectarea datei poate fi facuta acum mult mai elegant, solutie oferita de controlul
Calendar. Acesta permite afisarea unei singure luni, selectarea datei, trecerea de la o
luna la alta. Pune la dispozitia programatorului diferite proprietati pentru specificarea
stilului de afisare si a modului de selectare a datei. Folosind proprietatea
SelectionMode se poate specifica selectarea unei singure zile, a unei saptamani sau a
intregii luni. Controlul suporta toate tipurile de calendar definite in spatiul de nume
System.Globalization (Gregorian, Japonez, Korean, Hijri, Hebrew, Julian).
<asp:Calendar id="datai" runat="server" BackColor="LightGreen"
Font-Name="Verdana" Font-Size="10pt" />
La ora actuala, majoritatea aplicatiilor Web folosesc un sistem de gestiune al bazelor
de date in spatele aplicatiei. In sprijinul unei bune prezentari a acestor surse de date,
platforma .NET include un set de trei controale ce fac posibila afisarea unor mari
cantitati de date foarte usor. Sursa de date reprezinta o multime specifica de date care
poate fi reprezentata de un server de baze de date (MS SQL Server), un fisier XML
sau o colectie de date care implementeaza interfata System.Collections.IEnumerable.
Repeater
Reprezinta o simpla lista conectata la o sursa de date care foloseste sabloane pentru
afisarea informatiilor. Fara un sablon predefinit, programatorul este nevoit sa-si
defineasca propriul model de afisare folosind elemente HTML. In schimb, controlul este
singurul care ofera libertate maxima in definirea modului de afisare, a stilului si
formatarii.
<asp:Repeater runat="server" id="list1">
<HeaderTemplate> <ol> </HeaderTemplate>
<ItemTemplate>
<li><a href='mailto:<%# DataBinder.Eval(Container.DataItem,
"Email") %>'><%# DataBinder.Eval(Container.DataItem, "Nume")
%></a>
</li>
</ItemTemplate>
<FooterTemplate> </ol> </FooterTemplate>
</asp:Repeater>
DataList
In completarea unor functionalitati predefinite, controlul DataList afiseaza inregistrarile
unei surse de date folosind sabloane existente, dand posibilitatea totodata sa ne
definim propriile modele de afisare, sa selectam si sa editam articolele.
<asp:DataList id="list2" runat="server" BorderColor="black"
CellPadding="3" Font-Name="Verdana" Font-Size="8pt">
Page 198 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

<HeaderStyle BackColor="#aaaadd" />


<AlternatingItemStyle BackColor="Gainsboro" />
<HeaderTemplate>Studenti:</HeaderTemplate>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "Nume") %>
</ItemTemplate>
</asp:DataList>
DataGrid
Controlul afiseaza inregistrari conectate la o sursa de date in format tabular, oferind
optiuni pentru selectarea, sortarea, paginarea si editarea datelor. Fiecare camp din
baza de date este afisat in coloane separate in ordinea aparitiei in baza de date.
Implicit, proprietatea AutoGenerateColumn este setata pe true, ceea ce inseamna
crearea unui obiect BoundColumn pentru fiecare inregistrare din sursa de date. Se pot
controla ordinea, functionarea si afisarea fiecarei coloane. DataGrid-ul suporta mai
multe tipuri de coloane oferind diferite functionalitati de baza in prelucrarea datelor:
* BoundColumn, afiseaza fiecare articol dintr-o inregistrare ca text simplu;
* ButtonColumn, afiseaza un buton de comanda pentru fiecare articol dintr-o coloana.
Acesta permite crearea unei coloane de controale Button cu functionalitati gen
Adaugare si stergere;
* EditCommandColumn, afiseaza o coloana care contine comenzi de editare pentru
fiecare articol dintr-o coloana;
* HyperLinkColumn, afiseaza fiecare articol dintr-o coloana ca un hyperlink;
* TemplateColumn, afiseaza fiecare articol dintr-o coloana folosind un sablon
specificat. Acesta permite sa folosim controale specializate in coloane.
<asp:DataGrid id="list3" runat="server"
BorderColor="black"
BorderWidth="1"
GridLines="Both"
CellPadding="3" CellSpacing="0"
Font-Name="Verdana"
Font-Size="8pt"
HeaderStyle-BackColor="#aaaadd">
</asp:DataGrid>

4. Evenimente
Dezvoltare de aplicatii in Visual Studio .NET

Page 199 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Tratarea evenimentelor in paginile WebForms


Capturarea evenimentelor in paginile WebForms reprezinta o operatie facila, similara
tratarii evenimentelor in WinForms. In acest sens, ASP.NET furnizeaza un mecanism
virtual pentru capturarea, transmiterea si interpretarea evenimentelor fara sa fim nevoiti
sa cunoastem modul in care evenimentele sunt capturate la client si trimise la server
pentru a fi procesate in codul corespunzator.
Evenimentele tratate in controalele server pot fi in general de tipul Click, dar exista
altele speciale, mult mai abstracte, ca onchange si SelectionChanged (pentru controlul
Calendar). De regula, evenimentele de tip Click genereaza o postare a paginii la
serverul Web, iar cele de tipul onchange sunt capturate, dar nu sunt trimise imediat la
server (sunt mentinute intr-o coada de mesaje si procesate intr-o ordine aleatoare).
Pentru acele controale in care se genereaza evenimentul onchange exista proprietatea
AutoPostBack care daca are valoarea true atunci trimite automat formularul la server.
Metoda care trateaza evenimentele in ASP.NET respecta acelasi tipar cu cele folosite
in platforma .NET Framework. Astfel, toate evenimentele paseaza metodei doua
argumente: un obiect care identifica obiectul care a aruncat evenimentul si un alt obiect
continand informatii specifice evenimentului. Acesta din urma, este de obicei de tipul
System.EventArgs, dar exista si alte tipuri cum ar fi ImageClickEvensArgs pentru
controlul Web ImageButton care ofera informatii exacte despre pozitia unde s-a facut
click pe imagine.
Adaugarea unei metode care sa trateze mesajul generat se poate specifica astfel: daca
evenimentul este generat de un control HTML, acesta poate fi capturat atat la client cat
si la server. Aceasta se specifica prin adaugarea atributelor OnClick, respectiv
OnServerClick care vor indica metoda care va fi apelata la generarea evenimentului.
Exemplu:
<input type="submit" value="Enter"
OnServerClick="SubmitBtn_Click" runat="server">
unde metoda void SubmitBtn_Click (object sender, EventArgs e) este cea care
trateaza evenimentul pe server.
Daca evenimentul este generat de un control Web, nu se poate specifica tratarea unui
eveniment la client in sintaxa HTML, dar se poate adauga dinamic un nou atribut
controlului astfel: Button1.Attributes.Add ("onclick", "clientfunction();"); Putem specifica
o metoda dinamica care sa trateze mesajul evenimentului pe server astfel:
this.Button1Web.Click += new System.EventHandler
(this.Button1_Click);
this.Button2HTML.ServerClick += new System.EventHandler
(this.Button2_ServerClick);

5. Concluzii
Page 200 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

ASP.NET a fost dezvoltat pentru a lucra asemenea editoarelor WYSIWYG (What You
See Is What You Get) HTML, astfel mediul de dezvoltare Microsoft Visual Studio.NET
pe langa un GUI pe care dezvoltatorii il pot utiliza pentru a adauga controale server in
paginile WebForms, ofera suport integrat complet pentru depanarea aplicatiilor Web.
Tehnologia pe care platforma .NET o ofera prin ASP.NET, alaturi de limbajul C#, un
limbaj elegant si totodata performant, robust si productiv, va conduce la dezvoltarea
aplicatiilor Web complexe pentru organizatii mari, intreprinderi care vor putea
interopera folosindu-se de serviciile Web. ASP.NET, prin WebForms, imprumuta stilul
de programare Visual Basic folosind form-uri si evenimente si il transpune pe Web
oferind productivitate maxima in construirea aplicatiilor Web. Mai mult, modelul abstract
orientat pe obiecte al mediului ASP.NET va conduce la o dezvoltare rapida a
componentelor unei aplicatii Web, deci la aplicatii cu interfete utilizator bogate in
posibilitati de prezentare a informatiilor.

Dezvoltare de aplicatii in Visual Studio .NET

Page 201 of 203

ibm.com/developerWorks

Presented by developerWorks, your source for great tutorials

Section 14. Appendix


Lista cuvintelor cheie
va urma...

Page 202 of 203

Dezvoltare de aplicatii in Visual Studio .NET

Presented by developerWorks, your source for great tutorials

ibm.com/developerWorks

Section 15. Bibliografie, referinte


Lista materialelor didactice
Nr.

Descriere

1.

Alexandru PRUTEANU, Dezvoltare de aplicatii in Visual Studio .NET Iasi,


2002

2.

Training Kit MCAD/MCSD 70-316, Developing Windows-Based


Applications with Microsoft Visual C# .NET

3.

Microsoft Academic resource Kit for .NET Technology, Micosoft


Corporation 2003

4.

Tom ARCHER, Andrew WHITECHAPEL, Inside C#, Second Edition,


Micosoft Corporation 2002

5.

Gabriel ENEA, WebForms, o tehnologie ASP.NET 2002

Colophon
This tutorial was written entirely in XML, using the developerWorks Toot-O-Matic tutorial
generator. The open source Toot-O-Matic tool is an XSLT style sheet and several XSLT
extension functions that convert an XML file into a number of HTML pages, a zip file, JPEG
heading graphics, and two PDF files. Our ability to generate multiple text and binary formats
from a single source file illustrates the power and flexibility of XML. (It also saves our
production team a great deal of time and effort.)
You can get the source code for the Toot-O-Matic at
www6.software.ibm.com/dl/devworks/dw-tootomatic-p. The tutorial Building tutorials with the
Toot-O-Matic demonstrates how to use the Toot-O-Matic to create your own tutorials.
developerWorks also hosts a forum devoted to the Toot-O-Matic; it's available at
www-105.ibm.com/developerworks/xml_df.nsf/AllViewTemplate?OpenForm&RestrictToCategory=11.
We'd love to know what you think about the tool.

Dezvoltare de aplicatii in Visual Studio .NET

Page 203 of 203

S-ar putea să vă placă și