Sunteți pe pagina 1din 351

Constantin Gltan

Susana Gltan
9

Curs de

Programare n Visual C# 2008


Express Edition

L& S info-m et

Copyright 2008 L&S INFO-MAT


Toate drepturile asupra acestei lucrri aparin editurii L&S INFO-MAT.
Reproducerea integral sau parial a textului din aceast carte este posibi l
doar cu acordul n scris al editurii L&S INFO-MAT.
Tiparul executat la S.C. LuminaTipo S.R.L.
Str. Luigi Galvani nr. 20 bis, Sector 2, Bucureti,
office@luminatipo.com

Descrierea CIP a Bibliotecii Naionale a Romniei


GLAN, CONSTANTIN
Curs de C# : programare n Visual C# 2008 Express
Edition / Constantin Glan, Susana Glan. - Bucureti:
Editura L & S Info-mat, 2008
ISBN 978-973-7658-16-6
I. Glan, Susana
004.43 C#

E d itu ra

L&S

INFO-MAT:

fp k

Adresa: Str. Stnjeneilor nr. 6, bl. 30, sc. A, et. 1, apt. 11, sector 4, Bucureti;
Tel/Fax: 031-105.62.84;
Mobil: 0722-530.390; 0722-57.37.01;
E-mail: comenzi@ls-infomat.ro:
office@ls-infomat.ro:

http-.f/

Magazin online: www.ls-infomat.ro


Catalog online: www.manuale-de-informatica.ro
Biblioteca Digital de Informatic TUDOR SORIN
www.infobits.ro

CUPRINS
C# i platforma .NET...................................................................................7
.NET Framework........................................................................................................................8
Compilarea programelor pe platforma .NET........................................................................ 9
Instrumente de dezvoltare a aplicaiilor .NET.....................................................................10
Principalele caracteristici ale arhitecturii .NET...................................................................10
Mediul Integrat Visual C# 2008 Express Edition.....................................................................11
Instalare............................................................................................................................... 11
Compilare n linie de comand............................................................................................12
Primul program C #.............................................................................................................. 12
O scurt analiz a programului salut.cs................................................................................14
Crearea unei aplicaii de tip consol....................................................................................14
IntelliSense - o facilitate important a editorului de cod................................................... 16
Rezumatul capitolului............................................................................................................... 17
ntrebri i exerciii.................................................................................................................. 17

Limbajul C# . Introducere........................................................................18
Structura unui program simplu C # ...........................................................................................18
O aplicaie de tip Consol....................................................................................................18
Metoda M ain - punctul de intrare n aplicaie.....................................................................19
Calificarea complet a numelor cu ajutorul operatorului .................................................. 20
Parametri n linia de comand................................................................................................. 21
Variante ale metodei M ain.......................................................................................................23
Rezumatul capitolului...............................................................................................................24
ntrebri i exerciii..................................................................................................................24

Fundamentele limbajului C#..

........ 25

Tipuri.................................................
Tipuri predefinite.........................
Tipuri definite de programator.....
Tipuri valoare i tipuri referin....
Conversii ntre tipuri....................
Variabile i constante.......................
Enumerri..........................................
Expresii.............................................
Tablouri.............................................
Tablouri unidimensionale............
Tablouri multidimensionale.........
Tablouri neregulate......................
Instruciuni........................................
Instruciunea de selecie if ... else
Instruciunea de selecie s w itc h .
Ciclul f o r ...................................
Ciclul f o r e a c h ..........................
Ciclul w h i l e ...............................
Ciclul do w h i l e .......................
Instruciuni de salt necondiionat.
Spaii de nume..................................
Directive de preprocesare................
Directiva t d e f i n e ....................
Directiva tu n d e f i n e ...............

............ 25
............ 25
............ 27
............ 29
............ 31
............ 32
............ 33
............ 34
............ 36
............ 36
............ 38
............ 39
............ 42
............ 42
............ 43
.....44

.......... 44
..... 45

.......... 46
...........46
...... ...48

C# pentru liceu

Cuprins

Rezumatul capitolului..............................................................................................................53
ntrebri i exerciii................................................................................................................. 53

Programare Orientat peObiecte n C#................................................... 54


Obiecte i clase......................................................................................................................... 54
Mecanismele fundamentale ale OOP........................................................................................55
Clasele C # ................................................................................................................................ 56
Definirea claselor.................................................................................................................57
Metode. Parametrii metodelor............................................................................................. 59
Suprancrcarea metodelor...................................................................................................63
Membrii statici ai unei clase............................................................................................... 64
Constante............................................................................................................................. 65
Constructori......................................................................................................................... 66
Cuvntul cheie t h i s ...........................................................................................................69
Destructorul clasei...............................................................................................................71
Proprieti............................................................................................................................ 71
Indexatori............................................................................................................................. 76
Operatori de conversie.........................................................................................................78
Clase interioare.................................................................................................................... 80
Coninere............................................................................................................................. 82
Clase pariale....................................................................................................................... 83
Clase sigilate........................................................................................................................ 84
Suprancrcarea operatorilor.....................................................................................................84
Sintaxa................................................................................................................................. 85
Suprancrcarea operatorilorbinari..........................................
85
Metoda ToString()...............................................................................................................87
Suprancrcarea operatorilorunari........................................................................................87
Structuri.................................................................................................................................... 89
Interfee.........................................................................................................
90
Motenire.................................................................................................................................. 92
Specializare i generalizare................................................................................................. 92
Implementarea motenirii....................................................................................................93
Accesarea membrilor motenii.......................................................................................... 95
Constructorii claselor derivate............................................................................................ 97
Membrii ascuni...................................................................................................................99
Polimorfism............................................................................................................:..............100
Conversia referinelor........................................................................................................ 100
Metode virtuale.................................................................................................................. 101
Utilitatea polimorfismului.................................................................................................. 104
Rezumatul capitolului............................................................................................................. 105
ntrebri i exerciii................................................................................................................ 105

Trsturi eseniale ale limbajului C#..................................................... 106


Delegri...................................................................................................................................106
Declarare..............................................................................................................
106
Crearea obiectelor delegare................................................................................................ 106
Invocarea metodelor ataate unei delagri.........................................................................107
Invocarea delegrilor cu tipuri de retur..............................................................................108
Evenimente..............................................................................................................................109
Lucrul cu evenimente......................................................................................................... 109
Publicarea evenimentelor n mod specific .NET................................................................112
Generice..................................................................................................................................114
Clase generice................................................................................................
115

C#pentru liceu

Cuprins

Metode generice....................................................................................................................
Colecii.................................................................................................................................. - 19
Clasa generic S ta ck < T > ................................................................................................ 11?
Clasa generic L is t< T > .................................................................................................. 120
Clasa generic D ic tio n a ry C T k e y , T v a lu e > ..........................................................121
Tratarea excepiilor................................................................................................................. 123
Manevrarea stringurilor.......................................................................................................... 124
Operaii i metode.............................................................................................................. 125
Formatarea stringurilor...................................................................................................... 125
Transformarea stringurilor n valori numerice...................................................................126
Citirea unui ir de valori numerice.....................................................................................127
Citiri i afiri din fiiere de tip text....................................................................................... 128
Rezumatul capitolului............................................................................................................. 130
ntrebri i exerciii................................................................................................................ 130

Aplicaii de tip Windows Forms.............................................................131


Aplicaii cu interfa grafic cu utilizatorul.......................................................................... 131
Realizarea unei aplicaii simple de tip Windows Forms........................................................ 132
Controale, proprieti i evenimente.......................................................................................134
Tratarea evenimentelor........................................................................................................... 135
Cum se creaz handler-ele.................................................................................................135
O privire n spatele scenei.................................................................................................. 138
Declanarea programatic a unui eveniment......................................................................142
Crearea programatic a unui control..................................................................................143

Controalele Windows Forms...................................................................145


Controlul Button..................................................................................................................... 145
Controalele Labei i LinkLabel.............................................................................................. 148
Controalele RadioButton, CheckBox i GroupBox................................................................151
Controlul TextBox.................................................................................................................. 154
: Controalele MenuStrip i ContextMenuStrip.........................................................................161
Forme......................................................................................................................................165
Principalii membri ai clasei Form......................................................................................165
Crearea formelor................................................................................................................ 166
Dialoguri modale i dialoguri nemodale............................................................................167
Butoane de validare a datelor............................................................................................. 173
Dialoguri predefmite.............................................................................................................. 177
Descrierea dialogurilor predefmite....................................................................................177
Afiarea dialogurilor predefmite........................................................................................178
MDI - Multiple Document Interface......................................................................................184
Controlul RichTextBox.......................................................................................................... 191
Controlul ToolTip................................................................................................................... 196
Controlul Notifylcon.............................................................................................................. 199
Fonturi.................................................................................................................................... 203
Stilurile Fonturilor.............................................................................................................204
Fonturile instalate..............................................................................................................206
Desenarea fonturilor..........................................................................................................206
TabControl............................................................................................................................. 208
Controalele ListBox, ComboBox i CheckedListBox........................................................... 213
Controalele TrackBar, NumericUpDown i DomainUpDown..............................................218
Controlul ProgressBar............................................................................................................223
Controlul Timer...................................................................................................................... 224
Controalele PictureBox i Imagelist...................................................................................... 22

C# pentru liceu

C aprins

Controlul ListView.................................................................................................................237
Controlul TreeView..................................................................
245
Controalele Web Browser i StatusStrip......................................
253
Integrarea WindowsMediaPlayer n aplicaii........................................................................ 257

Desenare n .NET cu Visual C#...............................................................260


Clasa Graphics........................................................................................................................260
Penie pentru desenarea formelor.......................................................................................... 260
Pensule pentru umplerea formelor......................................................................................... 264
Desenarea textului..................................................................................................................266

XML cu C # ...............................................................................................270
Sintaxa XML.......................................................................................................................... 270
Clase .NET pentru Xml..........................................................................................................271
Citirea informaiilor dintr-un document XML....................................................................... 271
Descrcarea fiierelor XML de pe Internet............................................................................ 275
Citirea i analiza unui document XML cu XmlTextReader.................................................. 276
Crearea coninutului XML cu XmlTextWriter...................................................................... 279

Baze de date i ADO.NET. Noiuni introductive................................... 282


Instrumente de lucru............................................................................................................... 282
Calitile SGDBR-urilor....................................................................................................283
Furnizori de baze de date relaionale................................................................................ 284
Tehnologia ADO.NET - introducere.................................................................................... 284
Caracteristicile tehnologiei ADO.NET............................................................................. 284
Arhitectura ADO.NET.......................................................................................................285
Crearea unei baze de date n VCSE.................................................................................. 288
Interogri cu Query Designer.............................................................................................292
Controlul DataGridView....................................................................................................299

Aplicaii cu baze de date n modelul conectat........................................ 304


Utilizarea provider-ului pentru SQL Server 2005................................................................. 304
Utilizarea provider-ului pentru OLE DB............................................................................... 309
Utilizarea provider-ului pentru ODBC...................................................................................312

Aplicaii cu baze de date n modelul deconectat....................................320


Construirea i utilizarea dataset-urilor....................................................................................320
Accesarea tabelelor ntr-un dataset.........................................................................................321
Accesarea rndurilor i coloanelor ntr-o tabel.................................................................... 321
Accesarea valorilor dintr-o tabel a unui dataset................................................................... 322
Propagarea schimbrilor din dataset spre baza de date.......................................................... 322
Dataset-urile i XML..............................................................................................................326
Controalele i legarea datelor.................................................................................................327
Legarea simpl a datelor....................................................................................................327
Legarea complex a datelor...............................................................................................328

Relaii ntre tabele....................................................................................335


Constrngerea Cheie Strin-Cheie Primar......................................................................... 335
Interogri. Proceduri stocate................................................................................................... 338
Vederile unei baze de date (Views)....................................................................................... 346
Bibliografie............................................................................................................................ 351

Capitolul 1.

C# i platforma .NET

Partea I

Limbajul C#
Capitolul 1

C# i platforma .NET
Numele limbajului C# a fost inspirat din notaia t {diez) din muzic, care
indic faptul c nota muzical urmat de jf este mai nalt cu un semiton. Este o
similitudine cu numele limbajului C++, unde ++ reprezint att incrementarea unei
variabile cu valoarea 1, dar i faptul c C++ este mai mult dect limbajul C.
Limbajul C# a fost dezvoltat n cadrul Microsoft. Principalii creatori ai
limbajului sunt Anders Hejlsberg, Scott Wiltamuth i Peter Golde. Prima
implementare C# larg distribuit a fost lansat de ctre Microsoft ca parte a
iniiativei .NET n iulie 2000. Din acel moment, se poate vorbi despre o evoluie
spectaculoas. Mii de programatori de C, C++ i Java, au migrat cu uurin spre
C#, graie asemnrii acestor limbaje, dar mai ales calitilor noului limbaj. La
acest moment, C# i-a ctigat i atrage n continuare numeroi adepi, devenind
unul dintre cele mai utilizate limbaje din lume.
Creatorii C# au intenionat s nzestreze limbajul cu mai multe faciliti.
Succesul de care se bucur n prezent, confirm calitile sale:

Este un limbaj de programare simplu, modern, de utilitate general, cu


productivitate mare n programare.
Este un limbaj orientat pe obiecte.
Permite dezvoltarea de aplicaii industriale robuste, durabile.
Ofer suport complet pentru dezvoltarea de componente software,
foarte necesare de pild n medii distribuite. De altfel, se poate
caracteriza C# ca fiind nu numai orientat obiect, ci i orientat spre
componente.

La aceste caracteristici generale se adaug i alte trsturi, cum este de


pild suportul pentru internaionalizare, adic posibilitatea de a scrie aplicaii care
pot fi adaptate cu uurin pentru a fi utilizate n diferite regiuni ale lumii unde se
vorbesc limbi diferite, fr s fie necesare pentru aceasta schimbri n arhitectura
software.
n strns legtur cu Arhitectura .NET {.NET Framework) pe care
funcioneaz, C# gestioneaz n mod automat memoria utilizat. Eliberarea
memoriei ocupate {garbage collection) de ctre obiectele care nu mai sunt
necesare aplicaiei, este o facilitate important a limbajului. Programatorii nu mai
trebuie s decid singuri, aa cum o fac de pild n C++, care este locul i
momentul n care obiectele trebuie distruse.
n C# se scriu de asemenea aplicaii pentru sisteme complexe care
funcioneaz sub o mare varietate de sisteme de operare, ct i pentru sisteme

Partea I. Limbajul C#

dedicate (embeded systems). Acestea din urm se ntind pe o arie larg, de la


dispozitive portabile cum ar fi ceasuri digitale, telefoane mobile, MP3 playere, pn
la dispozitive staionare ca semafoare de trafic, sau controlere pentru
automatizarea produciei.
Din punct de vedere sintactic C# deriv din limbajul C++, dar include i
influene din alte limbaje, mai ales Java.

.NET Framework
Arhitectura .NET este o component software care ofer un mediu de
programare i de execuie a aplicaiilor pentru sistemele de operare Microsoft. Este
inclus n sistemele de operare Windows Server 2008 i Windows Vista i poate fi
instalat pe Windows XP i Windows Server 2003.
.NET Framework este un mediu care permite dezvoltarea i rularea
aplicaiilor i a serviciilor Web, independente de platform.
Limbajul C# se afl ntr-o strns legtur cu arhitectura .NET. Iniial, C# a
fost dezvoltat de ctre Microsoft pentru crearea codului platformei .Net, la fel cum
destinaia iniial a limbajului C a fost aceea de a implementa sistemul de operare
UNIX. .NET pune la dispoziie o colecie impresionant de clase organizate n
biblioteci, pe care C# le utilizeaz.
Este momentul s precizm c C# funcioneaz avnd .NET ca
infrastructur, dar .NET suport i alte limbaje, cum este C++, Visual Basic sau
Java. n oricare dintre aceste limbaje programai, avei la dispoziie aceleai
biblioteci de clase. .NET se realizeaz n acest fel interoperabilitatea limbajelor.
.NET este constituit din dou entiti importante:

Common Language Runtime (CLR)


Acesta este mediul de execuie al programelor. Este modulul care
se ocup cu managementul i execuia codului scris n limbaje
specifice .NET. CLR furnizeaz de asemenea servicii importante,
cum sunt securitatea aplicaiilor,
portabilitatea acestora,
managementul memoriei i tratarea excepiilor.

Base Class Library


Este vorba despre Biblioteca de Clase .NET. Aceast bibliotec
acoper o arie larg a necesitilor de programare, incluznd
interfaa cu utilizatorul, conectarea cu bazele de date i accesarea
datelor, dezvoltarea aplicaiilor web, comunicarea n reele i altele.
Codul bibliotecii este precompilat, fiind ncapsulat de regul n
funcii, numite metode, pe care programatorul le poate apela din
propriul program. La rndul lor, metodele aparin claselor, iar
clasele sunt organizate i separate ntre ele cu ajutorul spaiilor de
nume (namespaces). Despre toate aceste noiuni vom vorbi pe larg
n capitolele urmtoare. Ceea ce trebuie reinut pentru moment,
este c programatorii combin propriul cod cu codul Bibliotecii de
Clase .NET pentru producerea de aplicaii.

Capitolul 1.

C# i platforma .N ET

Compilarea programelor pe platforma .NET


Limbaje interpretate
Cnd programai ntr-un limbaj de programare interpretat, vei scrie codul i
vei rula aplicaia. Cu ajutorul unui interpreter specific limbajului, fiecare linie de cod
este interpretat chiar n momentul rulrii i este preschimbat imediat n cod
main i executat. Partea bun este c putei rula codul pn la primul bug,
putei nltura eroarea n cod iar apoi s continuai execuia codului. Limbajul nu
necesit timp de compilare i de legare. Partea neplcut este c limbajele
interpretate sunt lente. Limbajul Basic a fost iniial un limbaj interpretat, dar mai
apoi, ncepnd cu anii 1980, au aprut i versiuni compilate. Marea majoritate a
limbajelor de scriptare Web sunt de asemenea limbaje interpretate.
Limbaje compilate
Codul scris ntr-un asemenea limbaj, numit cod surs, este translatat de
ctre compilator ntr-un cod apropiat de nivelul mainii, numit cod executabil (de
exemplu codul coninut n fiierele (*.exe). Dac n timpul compilrii apar erori,
atunci este necesar s le nlturai, dup care vei compila din nou. Dac aplicaia
trece acum de compilare fr erori de sintax, atunci se va produce codul
executabil i vei putea s rulai aplicaia. Limbajele C i C++ sunt exemple clasice
de limbaje compilate.
Din aceast perspectiv C# este un limbaj compilat. Dar nu n sensul descris
mai sus. Ca s nelegei, este necesar s tii c n urma compilrii unui program
C#, nu se creaz un cod executabil. Se creeaz un fiier numit assembly care de
regul se identific cu extensia .exe sau .dll. Un asemenea fiier nu poate fi
executat pe un sistem pe care nu exist infrastructura .NET. Fiierul conine un tip
special de cod, numit Limbaj Intermediar, pe scurt CIL (Common Intermediate
Language). Limbajul CIL definete un set de instruciuni portabile, independente
de orice tip de procesor i platform.
Figura ilustreaz procesul de creare a codului executabil pe platforma .NET.

Fig.1.1 Procesul de compilare pe platforma .NET

10

Partea I. Limbajul C#

n momentul n care un program este executat, CLR activeaz un


compilator special, numit JIT (just in time). Acesta preia codul CIL i l transform
n cod executabil. Transformarea se face la cerere, n sensul c o secven de
cod se compileaz doar n momentul n care este utilizat pentru prima oar. Un
program compilat n format CIL poate rula pe orice sistem pe care s-a instalat
Common Language Runtime. Aceasta asigur portabilitatea aplicaiilor .NET.
Fiierul .exe sau .dll produs la compilare conine pe lng codul CIL, aa
numitele metadate. Metadatele descriu datele utilizate de ctre aplicaie.

Instrumente de dezvoltare a aplicaiilor .NET


Platforma .NET actual a ajuns la versiunea 3.5. Microsoft pune la dispoziia
programatorilor dou unelte pentru dezvoltarea aplicaiilor:
1. Visual Studio .NET i varianta free Visual Studio Express 2008.
2. .NET Framework SDK.
Pachetul de dezvoltare a aplicaiilor pentru .NET 3.5 (Microsoft .NET
Framework 3.5 SDK1), include:
> .NET Framework
> Compilatorare n linie de comand pentru limbajele de
programare: C#, C++ , Visual Basic, i Jscript.
> Instrumente pentru crearea, depanarea i configurarea aplicaiilor
.NET.
> Exemple i documentaie.
Trebuie s tii c exist compilatoare pentru platforma .NET create de anumite
firme sau organizaii, pentru limbajele Smaltalk, Perl, Cobol sau Pascal, ca s
enumerm doar cteva disponibile pe pia.

Principalele caracteristici ale arhitecturii .NET


Independena de procesor i de platform
Codul CIL este independent de sistemul de operare i de procesor.
De aceea, n scrierea aplicaiilor nu trebuie s fii preocupai de caracteristicile
hardware sau software ale sistemului. Spre surpriza multor programatori, aplicaiile
.NET pot fi dezvoltate i executate pe sisteme de operare non-Microsoft, (Mac OS
X, numeroase distribuii Linux i Solaris, ca s numim numai cteva).
Managementul automat al memoriei
Alocara i eliberarea memoriei nu mai este o problem care trebuie s-i
preocupe pe programatori, datorit mecanismului automat de garbage collection.
Interoperabilitatea limbajelor
Este un fapt comun ca diversele componente ale unei aplicaii s fie scrise
n limbaje diferite, suportate de ctre platforma .NET.

1Software Development Kit - Kit de Dezvoltare a Aplicaiilor

Capitolul 1.

C# i platforma .N ET

11

Securitate
.NET furnizeaz un model comun de securitate, valabil pentru toate
aplicaiile, care include un mecanism unificat de tratare a excepiilor . O excepie
este un eveniment neprevzut, care ntrerupe execuia unui program, atunci cnd
de pild, se execut o intruciune ilegal.
Portabilitate
Un program scris pentru platforma .NET poate rula fr nici o modificare pe
oricare sistem pe care platforma este instalat.
Caracteristicilor de mai sus li se adaug i altele, care ies ns din cadrul
acestei lucrri.

Mediul Integrat Visual C# 2008 Express Edition


Visual C# 2008 Express Edition (pe scut: VCSE), este un mediu free de
dezvoltare a aplicaiilor produs de Microsoft. Este un IDE (integrated development
environment), care ofer un set de instrumente, ntre care un editor de cod pentru
scrierea programelor C#, compilator, depanator, instrumente pentru build
automation (automatizarea procesului de compilare) i altele. Kit-ul de instalare C#
Express, include Platforma .NET 3.5, iar aceasta la rndul ei include ntre altele
Biblioteca de Clase.

Cerine de sistem
Sistemele de operare suportate sunt: Windows Server 2003, Windows Vista;
Windows XP.
>

>

Pentru Microsoft Windows XP, Service Pack 2


minim 192 MB de RAM (preferabil cel puin 384 MB)
cel puin un procesor de 1 GHz (preferabil > 1.6 GHz)
Pentru Microsoft Windows Vista i Microsoft Windows Server 2003
minim 768 MB de RAM (preferabil cel puin 1 GB)
cel puin un procesor de 1,6 GHz (preferabil > 2.2 GHz)

Instalare
Visual C# 2008 Express Edition poate fi descrcat de pe site-ul Microsoft,
la adresa http://www.microsoft.com/express/download/. Alternativ, n josul paginii
avei opiunea de a descrca Visual Studio Express Edition pentru o instalare
offline. Visual Studio conine mediile de programare Visual C#, Visual Basic,
Visual C++, precum i serverul de baze de date Microsoft SQL Server 2005.
Instalarea se face simplu, cu ajutorul unui wizard, ns pentru montarea imaginii
DVD-ului (fiier cu extensia ISO) avei nevoie de un utilitar cum ar fi de pild
Daemon Tools.
Ca observaie, indiferent dac vei instala Visual Studio sau doar Visual C#
2008 Express, vei opta ntotdeauna pentru instalarea .NET Framework, Visual
C#, MS SQL Server i MSDN (Micorsoft Developer Network). MSDN conine o
foarte bogat documentaie de care nu v putei lipsi cnd dezvoltai aplicaii.

Partea I. Limbajul C#

12

Exist i versiunile Visual C# 2008 i Visual Studio 2008 cu faciliti suc imentare,
dar care nu sunt gratuite.
Ajuni n acest punct, dorim s atragem atenia asupra fptuit' c o
prejudecat rspndit privind dezvoltarea .NET este aceea c programatorii
trebuie s instaleze Visual Studio ca s poat crea aplicaii C#. Nu este adevrat.
Putei s compilai i s rulai orice tip de program .NET folosind kit-ul de
dezvoltare a aplicaiilor .NET Framework 3.5 Software Development Kit (SDK),
care este downloadabil n mod gratuit. Acest SDK v pune la dispoziie
compilatoare, utilitare n linie de comand, conine Biblioteca de Clase .Net,
exemple de cod i o documentaie complet.
Se pot crea aplicaii C# n dou moduri diferite:
1. Folosind Notepad sau oricare editor de text i apoi compilarea n linie de
comand.
2. Utiliznd Visual Studio Express Edition. Aceasta este metoda preferabil,
datorit sprijinului considerabil pe care-l ofer mediul integrat n
dezvoltarea aplicaiilor, mai ales a acelora cu interfa cu utilizatorul.

Compilare n linie de comand


Dei s-ar putea ca niciodat s nu v decidei s dezvoltai aplicaii mari
folosind compilatorul C# n linie de comand, este totui important s nelegei
cum se lucreaz n linie de comand fie doar i pentru urmtoarele motive:
Nu avei o copie a Visual C# 2008 Express, sau sistemul pe care-nu
satisface cerinele hardware sau software minimale:
Dorii s proiectai un build tool automatizat, aa cum este MSBuild sau
Nant, care necesit s cunoatei opiunile n linie de comand ale
utilitarelor.
Dorii o nelegere profund a C#, dorii s vedei ce se petrece n
spatele scenei atunci cnd utilizai IDE-uri pentru dezvoltarea aplicaiilor.

Primul program C#
Este o tradiie pstrat n timp, ca o carte de programare s nceap cu
programul care afieaz pe ecran Salut lume ! . Vom compila i executa acest
program C# n linie de comand, urmnd paii de mai jos:
1.

Editarea codului surs


Deschidei Notepad i scriei urmtorul cod:
using System;
class Salut
{
static void Main()

{
Console.WriteLine("Salut lume!");

1
}

Capitolul 1.

C# i platforma .NET

13

n C# fiierele surs au extensia cs. Salvai fiierul cu numele salut.es ntr-un


folder oarecare, de exemplu C:\teste.
2.

Compilarea n linie de comand


La promptul de comand, compilai astfel: esc salut.es
:
Steste>csc salut.es

Aadar, compilatorul csc.exe (C sharp compiler) primete ca argument n linie


de comand numele fiierului surs. Vei constata c n urma compilrii, n
folderul C:\teste s-a creat fiierul saiut.exe. Acesta este un assembly,
coninnd codul intermediar CIL. Executarea lui este posibil doar pe
sistemele care au infrastructura .NET.
3.

Executarea programului
Rularea programului se face simplu, prin tastarea numelui fiierului .exe:
c:\teste>salut
Programul afieaz:
Salut lume!
C:\WINPOWS\sy5tein32tand.exe
C:Nteste>csc salut.es
[Microsoft <H> Uisual C# .NET Compiler uersiol
[for Microsoft <FO .NET Framework version 1.0|
[Copyright <C> Microsoft Corporation 2001. Al|
[C:Steste>salut
[Salut lume

Setarea variabilei de mediu PATH


Dac platforma .NET a fost instalat odat cu Visual Studio sau VCSE,
atunci la instalare putei opta ca variabila de mediu PATH s rein n mod implicit
cile spre utilitarele n linie de comad, inclusiv spre compilator, ceea ce v
scutete de efortul de a le introduce manual. Dac PATH nu reine aceste ci,
atunci nu vei putea lucra n linie de comand, deoarece sistemul de operare nu va
gsi aceste utilitare.

14

Partea I. Limbajul C#

n cazul n care nu ai ales varianta setrii PATH la instalare : putei face


ulterior astfel:
La promptul de comand, mutai-v n subdirectorul Common"7Tools al
instalrii.
Rulai fiierul de comenzi v s v a r s 32 .bat scriind: VSVARS32.

O scurt analiz a programului salut.cs


Prima linie a programului, using System; spune implementrii C# prin
intermediul directivei using, c se vor utiliza clase aflate n spaiul de nume
System. Aa cum vei vedea n capitolul urmtor, C# a preluat din C++ spaiile de
nume (namespaces). Spaiile de nume funcioneaz ca nite containere, n care se
definesc nume de clase pentru evitarea conflictelor de nume, dar i pentru
separarea logic. Toate clasele din Biblioteca de Clase .NET se definesc n
interiorul unor spaii de nume. System este un spaiu de nume fundamental, care
definete ntre altele, clasa Console. Aceasta din urm, conine metode (funciile
din C#) care scriu i citesc date de la consol.
Observm c la fel ca n C++, exist metoda Main(), care se declar
ntotdeauna static.

IMPORTANT!
O deosebire fa de C++ este faptul c trebuie s existe o clas, n cazul
de fa clasa Salut, care gzduiete metoda Main(). Aceasta, deoarece C# este
un limbaj p u r orientat obiect, i nu pot exista definiii de funcii n afara claselor
i nici variabile globale.________________________________ _____________
n acest sens, C# seamn cu Java. Totui, n Java numele clasei care conine
metoda main() trebuie s coincid n mod obligatoriu cu numele fiierului. Dac
vei schimba mai sus numele clasei, de exemplu Hello, o s constatai c nu vei
avea nici o problem la compilare.
Linia Console .WriteLine ("Salut lume!"); este apelul metodei
statice WriteLine din clasa Console. O s revenim asupra metodelor statice n
capitolele urmtoare. Pentru moment, reinei c o metod static se apeleaz
astfel: nume clasa.nume metod.

Crearea unei aplicaii de tip consol


1.

Deschidei mediul integrat de programare: Start->AII Programs-> Visual C#


2008 Express Edition.
2. n meniul File, selectai New Project. Se deschide dialogul New Project.
Acesta permite alegerea diferitor tipuri de aplicaii. Selectai Console
Application ca tip de proiect i schimbai numele aplicaiei n salut. Click OK.
Visual C# Express Edition 2008 creaz un nou folder pentru proiect, cu
acelai nume cu cel al proiectului. Deschide de asemenea fereastra principal
i Editorul de Cod unde vei intra i vei modifica codul surs C#.

Capitolul 1.

C# i platforma .NET

15

mm

Templates:
Visual Studio installed templates

rs!)
Windows
Forms A...

Class Library

ra*t
i #1

1 d*l

WPF
Application

WPF Browser
Application

cttj

HP

Empty Project

My Templates

Search Online
Templates...

A project for creating a command-line application (.NET Framework3.5)


Name:

salut

Cancel

Solution
Explorer
Solution Explorer - salut

sL& aa
S

Program.es

start Page

1using System;
U 3 i n g System.Collections.Generic;
using System.Linq;

-U3ing System.Text;
0 namespace salut
|{

class Program
{
static void Hain(stringf] args)
{

ij-

L>

>
>

........ ,

Solution 'salut' (1 project)


3 salut
iM Properties
i - -M References
i Pfogtam.es

4 X

Partea I. Limbajul C#

16

Barele de instrumente (Toolbars) sunt n partea de sus a ferestrei


principale. Acestea conin icon-uri pentru crearea, ncrcarea i salvarea
proiectelor, editarea codului surs, compilarea aplicaiei. Accesare: View>Toolbars. n partea a doua a lucrrii, prin Toolbar vom identifica bara de
intrumente care pstreaz iconuri cu controalele Windows Forms.
Solution Explorer este un panou foarte util care afieaz fiierele care
constituie proiectul. Cel mai important fiier este Program.es." care
conine codul surs al aplicaiei.
3.

Este permis s schimbai numele clasei n Editorul de Cod. De exemplu


schimbai Program cu Salut.

4.

Scriei codul de mai jos :


using System;
static void Main(string[] args)
{
Console.WriteLine("Imi place C# !");
Console.ReadLine();
}

5. Rularea programului.
Programul este gata de compilare i rulare. Se apas F5 ori click pe iconul ^

IntelliSense - o facilitate important a editorului de cod


Cnd se scrie un nume sau un cuvnt cheie n editor, se poate utiliza
instrumentul numit IntelliSense care este parte a panoului de cod. De exemplu,
cnd metoda ReadLine apare evideniat n list, Apsai Enter sau Tab sau
facei dublu-click i ReadLine va fi adugat n cod:
B namespace salut{
class Program

{
static void Hain(string[]

args)

{
Con 3 o le .WriteLine ('*mi place CU

^ OpenStandardOutput
o ut
OutputEncoding
v Read
v ReadKey

string Console.ReadLineQ
Reads the next line of characters from the standard input stream.

v ReferenceEquals
v SetBufferSize
v SetCursorPosition

Exceptions:
System.10 .IOException
5ystem.OutOf MemoryException
System.ArgumentOutOfRangeException

Capitolul 1.

C# i platforma .NET

17

Avantajul utilizrii IntelliSense este pe de o parte faptul c programatorul nu


trebuie s memoreze toate tipurile i metodele vizibile ntr-un anumit context
deoarece acestea apar n mod automat n list. Pe d alt parte, poate fi sigur c
ceea ce scrie este corect.

Rezumatul capitolului

C# este un limbaj din familia C++, orientat pe obiecte, cu mare productivitate n


programare.
Infrastructura pe care se programeaz n C# este .NET Framework.
.NET Framework este un mediu care permite dezvoltarea i rularea aplicaiilor
i a serviciilor Web, independente de platform.
Una dintre componentele de baz a .NET Framework este Biblioteca de
Clase .NET.
Mediul Visual C# Express Edition 2008 este un instrument de programare free,
cu care putei dezvolta aplicaii pentru sistemele de operare Windows.

ntrebri i exerciii
1.

Precizai cteva dintre calitile limbajului C#.

2.

Ce reprezint Common Language Runtime ?

3.

Descriei modul n care se produce compilarea unui program C#. Care


este rolul compilatorului J/T?

4.

Ce este un assembly ?

5.

Descriei cteva dintre caracteristicile Platformei .NET.

18

Partea I. Limbajul C#

Capitolul 2

Limbajul C # . Introducere
Limbajul C# este deosebit de simplu, cu numai 80 de cuvinte cheie i 12
tipuri incorporate. Dar C# este n acelai timp un limbaj foarte productiv din punct
de vedere al programrii aplicaiilor i pe deplin adaptat conceptelor moderne de
programare.
Fiind un limbaj orientat pe obiecte, o caracteristic esenial a sa este
suportul pentru definirea i lucrul cu clasele. Clasele definesc tipuri noi de date.
Variabilele de tip clas se numesc obiecte. Uneori un obiect este abstract, cum ar fi
o tabel de date sau un thread (program sau proces lansat n execuie). Alteori
obiectele sunt mai tangibile, cum sunt un buton sau o fereastr a aplicaiei.
Obiectele sunt un element fundamental n programare datorit rolului lor n
modelarea problemelor din practic care trebuie rezolvate. Programarea orientat
pe obiecte se sprijin pe trei piloni fundamentali: ncapsularea datelor, motenire
i polimorfism.
Clasele C# conin cmpuri i proprieti care rein informaii despre obiecte
i metode (funcii aparinnd clasei). Metodele ncapsuleaz cod care descrie ceea
ce poate face obiectul, aciunile i capabilitile sale. Obiectele la rndul lor,
interacioneaz, comunic ntre ele.
C# este un limbaj care ofer suport explicit pentru tratarea evenimentelor.
Vom reveni pe larg asupra tuturor acestor concepte n capitolele urmtoare.
C# admite programarea generic. Programarea generic este un stil de
programare diferit de programarea orientat pe obiecte. Scopul programrii
generice este scrierea de cod care s fie independent de tipul datelor. De exemplu,
imaginai-v o funcie care primete ca parametru un ir numeric pe care l
sorteaz. Algoritmul de sortare nu depinde de tipul elementelor irului. Acestea pot
fi de pild ntregi sau reale. n aceast situaie n C# putei defini o funcie
generic, care va folosi dup caz, iruri ntregi sau reale.
C#, aa cum s-a vzut n capitolul precedent utilizeaz un garbage
collector (colector de deeuri) pentru eliberarea memoriei ocupate de obiectele de
care aplicaia nu mai are nevoie. Obiectele C# se aloc ntotdeauna dinamic, adic
n timpul execuiei programaului i se distrug n mod automat.

Structura unui program simplu C#


O aplicaie de tip Consol
Creai n VCSE o aplicaie de tip consol i rulai programul urmtor:
/*
Programul declarar variabile, iniializeaz
variabile i face atribuiri
*/

Capitolul 2.

Limbajul C#. Introducere

19

namespace SpatiulMeu
{
class Test

{
static void Main(string[] args)

{
int a;
// Declararea unei variabile locale
a = 20;
// Atribuire
double b = 10;
// Declarare i iniializare
string s = "obiect de tip string";
System.Console.WriteLine("a = " + a);
System.Console.WriteLine("b = " + b);
System.Console.WriteLine("s este " + s);

}
}
}

Cu Ctrl + F5 compilai i lansai programul, care va afia pe ecran:


a = 20
b = 10
s este obiect de tip string

Vom analiza n continuare structura acestui program.

Metoda M a i n - punctul de intrare n aplicaie


Fiecare program necesit un punct de intrare (entry point) i n cazul C#,
aceasta este metoda static Main. La lansarea n execuie a programului, mediul
de execuie .NET (CLR) caut i apeleaz metoda Main. Un program poate s
conin mai multe clase, dar numai una dintre acestea definete metoda Main.

Tipuri abstracte
Programul declar un tip (clasa cu numele Test) i un membru al clasei
(metoda Main). Este o diferen fa de C++, unde de regul tipurile abstracte se
declar n fiiere header, iar definiiile acestora n fiiere .cpp separate.

Variabile locale
Metodele unei clase pot s declare variabile locale, aa cum este variabila
ntreag a, variabila real b i variabila de tip string, s. Tipul string este un tip
definit n Biblioteca de Clase .NET, fiind destinat lucrului cu iruri de caractere.
Variabilele locale pot fi iniializate cu valori la momentul declarrii.

Comentarii
C# admite comentarii multilinie ( /*
( / / ), ntocmai ca C++.

...

* /) i comentarii de o singur linie

20

Partea I. Limbajul C=

Clase
C# lucreaz cu clase. Fiind un limbaj pur -jnientat aonec:, nu putei scrie un
program C#fr clase. Totul se petrece r -tenatail anse"
ceea ce aparine
unei clase, va fi definit n interiorul ei. Nu r sut aifiiaitalie z coaie i nici funcii
globale. Un program trebuie s aib cel puin c ::sse aceea : ='e conine metoda
Main. O clas se definete cu ajutorul cuvn:_ . oho* c l u ;
Exemplu:
class Persoana
{
// membrii clasei
}

Observaie:
Programatorii C++ trebuie s fie avizai de faptu: c n C- dup ultima
parantez nchis a clasei, nu se pune ; .

Spaii de nume definite de programator


Exist spaii de nume predefinite. Ne referim la ace ea oare "ac parte din
Biblioteca de Clase .NET. n acelai timp C# permite programe-.; - cr s-i creeze
propriile spaii de nume pentru organizarea logic a aplicaiilor man. Ai remarcat
desigur namespace SpatiulMeu definit n primul program. Es:e : ne de reinut
c prezena lui este opional i c att clasa care conine metoda Main, ct i
celelalte clase ale programului pot s fie incluse sau nu n interiorul unui
namespace.

Calificarea complet a numelor cu ajutorul operatorului .


Afirile pe ecran s-au fcut prin apelul metodei statice WriteLine din
clasa Console. Clasa Console este definit n spaiul de nume System. Pentru
utilizarea claselor C# din Biblioteca de Clase .NET, dar i a metodelor statice ale
acestor clase, exist alternativele:
1. Utilizarea directivei using;
Directiva using face vizibile n program toate numele de clase dintrun spaiu de nume. Reamintim c spaiile de nume sunt containere logice
care servesc la separarea numelor de tipuri ntr-o bibliotec de clase sau
ntr-un program.

Exemple:

using System; - toate numele definite n spaiul de nume


System devin accesibile.
using System.Windows .Forms - clasele din spaiul de nume
Forms devin vizibile n program. Observai c spaiile de nume se
pot include unele n altele. De pild System conine mai multe
clase, dar i spaii de nume printre care spaiul de nume Windows.
Spaiul de nume Windows la rndului lui include mai multe spaii
de nume, ntre care i Forms.

Capitolul 2.
2.

Limbajul C#. Introducere

21

Calificarea complet a numelui


Calificarea complet a numelui (fully qualified name) presupune
precizarea cii complete pn la numele metodei. n programul anterior,
apelul System.Console.WriteLine ("a = " + a) ; ilustreaz modul
corect de apelare. Operatorul . servete la separarea spaiilor de nume.
Se pornete de la spaiul de nume exterior (System) i se continu cu
specificarea tuturor spaiilor de nume pn se ajunge la metoda dorit.
S scriem dou programe simple:
// Primul program folosete
using System;

directiva using

class Test

1
static void Main()
{
Console.WriteLine("C#");
}
}
// Al doilea program precizeaz calea complet
// a numelui metodei
class Test
{
static void Main()

{
System.Console.WriteLine("C#");
}
}

Cele dou programe compileaz i ruleaz identic.

Parametri n linia de comand


Metoda Main poate avea un parametru. Acesta este un ir de stringuri, care
reine argumentele n linia de comand care se transmit programului. Acestea sunt
informaii care pot fi pasate programului de ctre utilizator. Creai un proiect de tip
consol cu numele arg. n editorul de cod introducei programul:
using System;
class Program
{
static void M ai n (stringf] args)

{
for (int i = 0; i < args.Length; i++)
Console.Write(args[i] + " ");

Partea I. Limbajul C#

22

Compilai proiectul (facei Build) cu F6 . n folderul \bin\Release al aplicaiei se va


produce fiierul assembly cu numele arg.exe.
OBSERVAII
5
^
Vom reveni n capitolul urmtor asupra buclei f o r . n acest moment reinei
sintaxa preluat din limbajul C.
Length este o proprietate public a clasei abstracte Array, care returneaz
numrul de elemente ale irului. Toate tablourile unidimensionale din C#
motenesc clasa Array, deci pot utiliza proprietile acesteia.
Transmiterea argumentelor de la promptul sistemului de operare
Interpretorul n linie de comand al sistemului de operare este cmd.exe.
Acionai Start->Run i introducei comanda cmd. La promptul sistemului
schimbai calea n folderul \bin\Release al proiectului. Tastai numele programului,
urmat de cateva argumente separate prin spaii: arg unu doi trei patru.
Programul afieaz pe ecran: unu doi trei patru

':\tese\arg\arg\binSJlelease>arg unu doi trei patru


nu doi trei patru
:\testeSarg\argSbinSRelease>

Argumentele sunt de regul informaii de care programul are nevoie, de


exemplu numele fiierelor de intrare i de ieire.
Transmiterea argumentelor n linie de comand din Visual C# Express
n fereastra Solution Explorer, facei dublu click pe iconul Properties. n
fereastra din dreapta, click pe tab-ul Debug. Introducei argumentele n linie de
comand n TexBox-ul cu eticheta Command Line Arguments:
a rg *

Program.es

Start Page

Application
Build

Command line arguments;

a b c d e

Build Events
Debug*
Working directory:
i

Resources

........................................................ - r c i

Enable the Visual Studio hosting process

Settings

Facei Build i rulai acionnd Ctrl + F5. Programul afieaz: A B c D s

Capitolul 2.

Limbajul C#. Introducere

23

Variante ale metodei Main


La crearea unei aplicaii de tip consol, VCSE genereaz urmtoarea
definiie pentru metoda Main:
static void Main (string [] args) { /*...*/}

Este declarat static, are tipul de retur void i un ir de stringuri, ca i


parametru de intrare. C# admite i alte signaturi ale funciei Main, ca mai jos:
static int Main(string[] args) { /*...*/}
static void Main() { /*...*/}

/ / Tip de retur int,


/ / un ir de stringuri ca argument
/ / Fr tip de retur, fr argumente

static int Main() { /*...*/}

/ / Tip de retur int, fr argumente

Vei alege un prototip sau altul, n funcie de necesiti. Dac dorii ca aplicaia s
ntoarc sistemului de operare o valoare ntreag, de pild un cod de eroare cnd
programul se termin, atunci vei prefera o signatur care returneaz int. Dac
aplicaia folosete argumente transmise de ctre utilizator din linie de comand,
atunci vei opta pentru o versiune cu un parametru de tip ir de stringuri.

IMPORTANT
> C# este case-sensitive. Aceasta nseamn c Main este corect, iar main greit, c
WriteLine nu este tot una cu writeline.
>

Cuvintele cheie din C#, (return, int, void, if, etc) se scriu cu litere mici.

>

Pentru tipurile definite de programator, pentru spaiile de nume i pentru metode,


exist convenia pe care este indicat s o respectai i anume: prima liter este
mare i fiecare cuvnt coninut ncepe tot cu liter mare.
Exemple: Console.ReadLine ()
- metod
System.TimeZone
- spaiu de nume
System.Data.SqlClient - clas

Rolul cuvntului cheie static n prototipul metodei Main


Main este membr a unei clase, de pild clasa TestAfisare. Dar o clas
nu este altceva dect o specificaie a unui tip de date. n lipsa unui obiect de tip
TestAfisare, nu exist nici un membru al clasei. Totui, Main trebuie s fie
apelat pentru c este punct de intrare n program. Pentru ruperea cercului vicios,
se definete Main ca metod static. Metodele statice au tocmai aceast
proprietate interesant, c ele exist i pot fi apelate n lipsa unui obiect de tipul
clasei.

Partea I. Limbajul C#

24

Accesul public sau privat la metoda Main


La fel ca n cazul altor limbaje orientate obiect, In 2= se specific modul de
acces la membrii clasei cu ajutorul modificatorilor de acces public sau private.
Vom reveni n capitolul urmtor asupra acestor cuvinte cheie Pe scurt, cuvntul
private aplicat unui membru de clas face ca acel membru s nu poat fi
accesat din exteriorul clasei. Visual C# 2008 Express dehnete mod implicit
metoda Main ca fiind private, pentru ca alte aplicaii s nu o poat apela. Avei
libertatea s specificai modificatorul public sau private. Construciile urmtoare
sunt legale:
public static void Main()
{
}
private static void Main()
{
}

Rezumatul capitolului

Metoda Main este punctul de intrare ntr-un program C#.


Un program trebuie s aib cel puin o clas, aceea care conine metoda

Main.
Main are cteva versiuni. Prin tabloul de stringuri pe care Main l are ca

parametru, se pot pasa programului argumente n linia de comand.


C# nu admite variabile globale. Toate variabilele declarate sunt locale.
Toate clasele .NET sunt definite n interiorul unor spaii de nume.

ntrebri i exerciii
1.

Ce se nelege prin garbage collection ?

2.

Care este rolul cuvntului cheie static n signatura metodei Main ?

3.

Ce se nelege prin fully qualified name ?

4.

Scriei un program C# care se ruleaz ntr-o aplicaie de tip consol.


Programul afieaz toi parametrii transmii n linie de comand. Nu se vor
utiliza directive de compilare.

5.

Ce rol are operatorul . ntr-un program C# ?

Capitolul 3.

Fundamentele limbajului C#

25

Capitolul 3

Fundamentele limbajului C#
Acest capitol descrie elemente de baz ale limbajului C#: tipurile de date,
sintaxa, expresiile, operatorii, directivele de procesare.
Toate programele din acest capitol se pot testa cu ajutorul unei aplicaii de tip
consol n Visual C# 2008 Express Edition.

Tipuri
C# este un limbaj puternic tipizat (strongly-typed). Un asemenea limbaj
impune programatorului s declare un tip pentru fiecare obiect creat, iar
compilatorul verific compatibilitatea dintre tipurile obiectelor i valorile care le sunt
atribuite.
Tipurile sistem din C#, se mpart n dou categorii:
Tipuri predefinite (built-in), cum sunt int, char, etc.
Tipuri definite de programator (user-defined). Acestea se definesc cu
ajutorul claselor, structurilor sau interfeelor.
Un alt sistem de clasificare a tipurilor n C# mparte tipurile astfel:
Tipuri referin
9 Tipuri valoare
Tipurile valoare sunt variabile locale care se memoreaz n segmentul de stiv al
programului, iar tipurile referin se aloc dinamic n Heap.
C# admite i tipul pointer, ns pointerii sunt folosii foare rar i doar n
situaiile cnd se lucreaz cu unmanaged code, adic cod nespecific platformei
.Net.

Tipuri predefinite
C# ofer toate tipurile de baz necesare unui limbaj de programare modern,
n C# toate tipurile sunt obiecte, chiar i cele mai elementare tipuri. Cuvintele cheie
pentru tipurile predefinite (int, char, double, etc.) sunt mapate direct peste tipuri
struct din spaiui de nume System. De exemplu, cuvntului cheie int i
corespunde clasa System. Int32 din Biblioteca de Clase .NET. Avei libertatea s
declarai o variabil ntreag astfel:
System. Xnt32 x; , n loc de int x;

Maparea tipurilor primitive peste tipuri din .NET asigur faptul c tipurile create n
C# pot interaciona cu tipuri create n alte limbaje care lucreaz pe platforma .Net.
Tipurile referin predefinite sunt object i string.

26

Partea I. Limbajul C#

Tipul object
Tipul object este rdcina ntregii ierarhii de tipuri i clasa de baz a
tuturor claselor din .NET Framework. Aceasta nseamn pe de o parte c toate
clasele din .NET motenesc clasa object i pe de alat parte c oricare clas
definit de programator deriv n mod implicit din object.

Tipul string
Tipul string reine un ir de caractere din setul Unicode. Unicode este un
standard care permite reprezentarea tuturor caracterelor scrise n orice limb
scris, nu doar n limbile de circulaie internaional (n jur de 100.000 carcatere).
Tabelul 3.1
Tip

Tipuri C# predefinite
Dimensiune
Tip .Net
asociat
(bytes)

object
string
byte
char
bool
sbyte
short
ushort
int

variabil
variabil
1
2
1
1
2
2
4

Object
String
Byte
Char
Boolean
SByte
inti 6
UIntl6
Int32

uint
float

4
4

Uint32
Single

double

Double

decimal

12

Decimal

long
ulong

8
8

Xnt64
UInt64

Descriere
Tipul de baz al tuturor tipurilor
Tip ir de caractere.
Tip ntreg fr semn. [0, 255]
Tip caracter. Reine carcatere Unicode
Valori true sau false
Tip ntreg cu semn. [-128,127]
Tip ntreg cu semn. [-32768,32767]
Tip ntreg fr semn. [0, 65535]
Tip ntreg cu semn.
[-2.147.483.648, 2.147.483.647]
Tip ntreg fr semn. [0, 4.294.967.295]
Tip real cu virgul mobil, simpl precizie.
Valori cuprinse ntre +/-1,5 x 10"45 i +/-3,4
x 1038 cu 7 cifre semnificative
Tip real cu virgul mobil, dubl precizie.
Valori cuprinse ntre +/-5,0 x IO'324 i +/-1,8
x IO308 cu 15 cifre semnificative
Tip zecimal cu virgul fix. Precizie de cel
puin 28 cifre semnificative.
Tip ntreg cu semn.
[-263, 263 - 1]
Tip ntreg fr semn. [0, 264]

Tipul decimal se folosete n calcule financiare, atunci cnd erorile de rotunjire


datorate virgulei mobile sunt inacceptabile.

Declarri de variabile
Toate declarrile de mai jos sunt legale:
object ol, o2 = nuli;
string s = "Salut";
sbyte b = 6;
short h = 13;

Capitolul 3.

Fundamentele limbajului C#

27

ushort u = 7;
int a = 10;
long p = 3, q = 8L;
ulong x = 2UL, y = 5L, z = 10U, w = 8;
float fl = -4.5, f2 = 3.8F;
double dl = 1.3, d2 = 0.2D;
char c = 'T ';
Decimal d = 12. 4M;
/ / Mdesemneaz o constant decimal

Tipuri definite de programator


n C# programatorii pot defini propriile tipuri cu ajutorul cuvintelor cheie :
class, struct, interface, delegate i enum. Tipul tablou este de asemenea

un tip user-defined.

Tipul class
n C# clasele se creeaz cu ajutorul cuvntului cheie class:
class nvme_clasa

{
modificator_acces Tip nume_membru;
I I ali membri

}
Exemplu:
class ntreg

{
public int x;

// x - cmp (membru) al clasei

De reinut:

Variabilele de tip clas se numesc obiecte sau instane ale clasei.


Crearea unui obiect de tip clas, se numete instaniere.

Instanierea se face cu ajutorul operatorului new, urmat de apelul constructorului


clasei. Vom reveni asupra acestor noiuni n capitolul urmtor. Vom crea dou
obiecte de tip ntreg:
ntreg r l , r 2 ;
rl = new I n t r e g O ;
r2 = new IntregO;

// Declar dou referine


// Creeaz un obiect referit de rl
// Creeaz un obiect referit de r2

Mai sus, r l i r2 se numesc referine.

Partea I. Limbajul C#

28

IMPORTANT
Accesarea membrilor clasei se face cu sintaxa: referina.membru

Modificatorul p u b lic care prefixeaz declararea cmpului x, indic faptul c x


poate fi accesat din afara clasei sale astfel: r . x.
Ilustrm aceste informaii n programul in t r e g . cs:
using System;
class ntreg
{
public int x;
}
class Testlntreg

l
static void Main()
{
ntreg r = new ntreg();
r.x = 10;
// Atribuie valoarea 10 cmpului x
Console.Write(r.x);
// Afieaz 10
}
}

Observai c un program C# poate s conin una sau mai multe clase, dintre care
una singur conine metoda Main.

Structuri
Structurile se construiesc prin utilizarea cuvntului cheie struct. Au fost
introduse n C# pentru a permite programatorului s defineasc tipuri valoare. Sunt
similare claselor, dar le lipsesc unele caracteristici, cum ar fi motenirea. Obiectele
de tip struct se depoziteaz n stiv. Se creeaz i se acceseaz mai rapid
dect cele alocate dinamic. Sunt de preferat atunci cnd avei nevoie de obiecte
mici ca dimensiuni, sau care se construiesc ntr-un ciclu.
Sintaxa este similar cu cea a claselor:
Exemplu
using System;
struct Persoana
{
public string nume;
public int vrsta;
}

Capitolul 3.

Fundamentele limbajului C#

29

class TestStruct
{
static void Main()
{
// Datele obiectului p se memoreaz n stiv
Persoana p = new Persoana();
p.nume = "Iulia";
p.varsta = 8;
Console.Write("Numele {0}\nVarsta {1} ani",
p.nume, p.varsta);
}
}

La rulare, programul afieaz:


Numele Iulia
Varsta 8 ani

Not

Metodele Write i WriteLine din clasa Console, admit formatarea


afirii n maniera funciei print() din C. Modificatorii {0} i {1}
specific locul i ordinea n care se vor afia valorile argumentelor
p .nume, respectiv p .varsta.
\n este o secven escape, reprezentnd caracterul (newline).

Tipuri valoare i tipuri referin


n C# tipurile se clasific n tipuri valoare i tipuri referin.
Tipurile valoare sunt toate tipurile predefinite (char, int, float, etc.), cu
excepia tipurilor string i object. C# permite n plus definirea de tipuri valoare
cu ajutorul cuvntului cheie struct. Tipurile valoare se caracterizeaz prin faptul
c se memoreaz n segmentul de stiv al programului.
Tipurile referin, se definesc de ctre programator. n aceast categorie se
includ tipurile clas, tipurile interfa, tipurile delegat i tipurile array (tablourile). Se
numesc tipuri referin, deoarece variabilele folosite pentru manipularea lor sunt
referine la obiecte alocate dinamic n Heap. O variabil de tip referin, pstreaz
de fapt adresa obiectului din Heap pe care l refer, astfel c exist o asemnare
ntre referine i pointerii C++.
Ca s putem lmuri pe deplin diferenele ntre tipurile referin i tipurile valoare,
vom vedea cum se creaz obiectele.

IMPORTANT
Tipurile valoare difer de tipurile referin prin faptul c variabilele de
tip valoare conin datele obiectului, n timp ce variabilele de tip referin conin
referine la obiecte.
Pentru a lmuri aceasta, vom analiza programul:

Partea I. Limbajul C#

30
class C
{
}

// Tip referin

struct S

// Tip valoare

{
}
class StackHeap
{
static void Main(string[] args)
{
int x = 7;
// Variabil local.
S s = new S(); // s - variabil local
C r;
r = new C();

// Referina r se memoreaz pe Stiv,


// Aloc n Heap un obiect referit de r

}
}

Unde se vor memora variabilele x, s, r i obiectele create cu new ? Privii figura:

Figura 3.2. Memorarea datelor tipurilor valoare i referin


Observm cteva aspecte importante:
Obiectul cu numele s de tip struct, creat cu new se memoreaz n
stiv.
Referina r la obiectul de tip class se memoreaz n stiv, iar obiectul
propriuzis creat cu new se aloc n Heap.
Variabila x se memoreaz n stiv.

Capitolul 3.

Fundamentele limbajului C#

31

DE RETINUT:
j
>

>

Datele variabilelelor de tip valoare, se memoreaz pe stiv (Stack). O


excepie de la aceast regul o constituie situaia n care tipuri valoare
sunt incorporate unui tip referin (de pild, sunt date membre ale unei
clase). n acest caz datele se memoreaz n Heap.
n cazul tipurilor referin, referinele sunt n stiv, iar datele se aloc
dinamic n Heap.

Conversii ntre tipuri


Obiectele de un anume tip se pot converti n obiecte de un alt tip n mod implicit
sau explicit. Tipurile predefinite suport de asemenea conversii.

Conversiile implicite
Acest tip de conversie se produce n mod automat. O face compilatorul i
avei garania c se produce fr pierdere de informaie.
Exemplu:
short a = 4;
int n = a;
// Conversie implicit spre tipul int.
// Nu se pierde informaie

Conversiile explicite
Dac ncercai s atribuii unei variabile de tip short valoarea unei variabile
de tip int, compilatorul nu va efectua conversia implicit, deoarece aceasta poate
cauza pierdere de informaie. Avei totui posibilitatea de a efectua aceast
conversie cu ajutorul operatorului de conversie explicit (cast operator) :
int n = 10000;
short sl = n;
short s2 = (short)n;

// Incorect. Nu va compila
// Corect. Conversie explicit
// cu pierdere de informaie

Secvena urmtoare ilustreaz modul n care conversiile au loc n C#:


// Declarri
object o = nuli;
int a = 2000;
short b = 3;
char c = 'T ';
long d = 10;
double f = 1.2;
// Testarea convertibilitii
a = d;
// Eroare.
a = (int)d;
// Corect. Conversie explicit
o = b;
// Corect. Toate tipurile se convertesc
//
n mod implicit la tipul object
b = o;
// Eroare.

32

Partea I. Limbajul C#

f = b;
b = f;
ulong e = -3;
a = c;
c = a;
c = (char)a;

/ / Corect. Conversie ia p L ic ^ r a
//
//
//
//
//

Eroare.
Eroare.
Corect. Conversie implici*
Eroare.
Corect. Conversie explicic

Variabile i constante
Variabile
O variabil este o locaie de memorie care are un tip asociat. n programul
de mai jos, a i b sunt variabile:
using System;
static void Main(string[] args)
{
int a = 2;
int b;
b = 3;
System.Console.WriteLine(a + " " + b ) ;
>

Programul afieaz: 2 3
Comentai instruciunea b = 3; Vei constata faptul c programul are o eroare.
Compilatorul anun c ai ncercat s utilizai o variabil creia nu i-a fost atribuit
o valoare.

IMPORTANT
C# nu permite utilizarea variabilelor crora programul nu le-a asociat anterior o
valoare.

Constante
O constant este o variabil iniializat, a crei valoare nu mai poate fi
modificat n program. Constantele se introduc cu ajutorul calificativului const:
using System;
static void Main (stringH args)
{
const long x = 100; // Corect
const string s;
// Eroare. Constanta neinitializata
s = "Salut";
System.Console.WriteLine (x + " " + s);
}

Programul nu va compila, deoarece stringul s a fost declarat constant dar nu i s-a


atribuit o valoare iniial.

Capitolul 3.

Fundamentele limbajului C#

33

Enumerri
Enumerrile sunt tipuri de date de tip valoare, create de programator n
scopul de a grupa sub un nume un set de constante simbolice.
Exemplul 1:
using System;
enum Saptamana
{
Luni, Marti, Miercuri, Joi,
Vineri, Sambata, Duminica

}
class TestEnum
{
static void M a i n ()

{
Saptamana ziua = Saptamana.Luni;
if ( ziua == Saptamana.Luni)
Console.Write("Luni e {0} Marti e {1}",
(int)Saptamana.Luni, (int) Saptamana.Marti);

}
}
Programul afieaz: Luni e 0 Marti e 1

De retinut:
i

Membrii unei enumerri se numesc enumeratori. Lista membrilor


enumerrii, se separ prin virgul.
Variabila ziua de tip enum, reine doar unul dintre membrii enumerrii
(Luni).

Valorile membrilor enumerrii se obin prin conversii explicite ia int i sunt


egale cu 0, 1, 2.......dac nu se specific alte valori pentru enumeratori.

Exemplul 2
Membrilor unei enumerri li se pot asocia valori de tip ntreg:
using System;
enum Note
{
Mate = 10,
Info = 9,
Romana = 8

Partea I. Limbajul C#

34

class TestEnum

{
static void Main()

{
Console.Write("mate: {0}\ninfo: {1}\nromana: {2}",
(int)Note.Mate, (int)Note.info, (int)Note.Romana);

}
}
Programul afieaz:
mate: 10
info: 9
romana: 8

Enumerrile sunt o alternativ puternic n raport cu constantele. Utilizarea


enumerrilor face codul mai clar, mai bine documentat.

Expresii
Expresiile n C# sunt similare cu expresiile din C++ i Java. Expresiile se
construiesc folosind operanzi i operatori i n general ntorc o: valoare n urma
evalurii lor. Operanzii sunt variabile de memorie, nume de metode, de tablouri, de
obiecte, etc.
Tabelul de mai jos prezint operatorii C# n ordinea descreterii precedenei
(prioritii) lor.
Tabelul 3.3. Operatorii C#
Grupul de
operatori

__ .

Operator

0
[]
++

Multiplicativi

f (X)

Apel de metod
Acces la elem. tablourilor
Postincrementare
Postdecrementare
Creare de obiecte
Creare de tablouri
Informaii despre tipul T
Evaleaz expresia x n
medii checked i
unchecked
Identitate i negaie
Negaie logic
Negaie pe bii
Preincrementare
Predecrementare
Conversie explicit
nmulire, imprire,
modulo

typeof

Acces la membrii clasei

X++

checked
unchecked

~
++

0
* / %

Descriere

x .m

a [x]

new

Unari

Expresii

n e w T(x)
n e w T[x]
typeof(T)
c h e c k e d (x)
u n c h e c k e d (x)
+x

-x

!x
~x
++X

- -X
(T) x
x*y

x/y

x%y

Capitolul 3.

x+y

x-y

x
x

y
y

<

Relaionali i
de testare a
tipului

II
A

II
V A V
V A

Aditivi
Shiftare

Fundamentele limbajului C#

x<y x>y x<=y x>=y

is

x is T

as

x as T

35

Adunare, scdere
Deplasare pe bii la stnga
i la dreapta
Operatori aritmetici
true,
dac x este
convertibil la T. Altfel,
false

!=

x == y

&

x
x

| y

&& y

II

II y

?:

? y

x %= y

ii

ii

x = y
etc.

: z

<

II A
+ A

/=

*=

>t

I
&&

x != y

& y

II V II
<*> v

Atribuire

==

<

Egalitate
AND logic
XOR logic
OR logic
AND
condiional
OR
condiional
Condiional

Retumeaz x convertit la
T sau n u l i dac
conversia e imposibil
Egal i diferit
AND logic pe bii
XOR logic pe bii
OR logic pe bii
Evalueaz y numai dac x
este t r u e
Evalueaz y numai dac x
este f a l s e
Evalueaz y dac x este
true. Altfel, evalueaz z
Atribuire
simpl
i
atribuiri compuse

Observaie:

Din tabel se constat c apelurile metodelor sunt expresii, accesarea unui


element ntr-un tablou este o expresie, crearea de obiecte sau de tablouri sunt de
asemenea expresii.
Cnd o expresie conine mai muli operatori, precedena operatorilor
determin ordinea de evaluare a operaiilor.
De exemplu, x - y / z se evalueaz ca x - (y / z) deoarece precedena
operatorului / este mai mare dect cea a operatorului - .
Cnd un operand se gsete ntre doi operatori cu aceeai preceden,
atunci asociativitatea operatorilor controleaz ordinea operaiilor.
n afara operatorilor de atribuire, toi operatorii binari se asociaz de la
stnga spre dreapta. De exemplu: a + b + c se asociaz (a + b) + c.
Operatorii de atribuire i operatorul condiional (?:) se asociaz de la
dreapta spre stnga. De exemplu: a = b = c se evaluaeaz n ordinea a = (b
= c).

Precedena i asociativitatea se pot controla cu ajutorul parantezelor. De


exemplu: a+b/c mparte b la c i apoi adun a la rezultat, dar (a+b) /c adun a
cu b i mparte rezulatul la c.
([1])

Partea I. Limbajul C#

36

Tablouri
Un tablou este o structur de date coninnd variabile de acelai tip. n C#
tablourile sunt tipuri referin. Tablourile pot fi unidimensionale sau
multidimensionale. Cele multidimensionale, la rndul lor pot fi dreptunghiulare
sau neregulate (jagged).

Tablouri unidimensionale
Declararea tablourilor unidimensionale se face preciznd un tip de dat
urmat de operatorul de indexare i numele tabloului. Crearea tabloului se face cu
new urmat de tip i dimesiunea tabloului cuprins ntre paranteze ptrate.
Declarare: Tip[] a;
Creare:
a = new Tip[n] ;
Tablourile se indexeaz de la 0. Un tablou cu n elemente este indexat de la 0 la n1.

Exemplul 1:
Programul de mai jos definete un tablou cu 5 valori de tip int.
using System;
class TabUnidiml
{
static void Main()

{
// Tablou cu 5 elemente de tip int
int[] a;
// Declarare
a = new int[5]; // Creare
for (int i = 0; i < a.Length; i++)
a [i] = i + 1;
for (int i = 0; i < a.Length; i++)
Console.Write("a[{0} ] = {l}\n", i, a[i]);

}
Programul afieaz:
a[0]
a[l]
a [2]
a[3]
a [4]

=
=
=
=
=

1
2
3
4
5

Capitolul 3.

IMPORTANT !

Fundamentele limbajului C#

37

_________________ ____________________

Tablourile sunt n realitate obiecte care motenesc clasa Array. De aceea,


metodele i proprietile acestei clase pot fi folosite pentru tablouri. Proprietatea
Length a clasei Array returneaz numrul de elemente ale tabloului.

Exemplul 2:
Mai jos, a, b, c, sunt tablouri de double, char, string, respectiv obiecte
de tip A.
class TabUnidim2

{
class A

{
}
static void Main{)
/

doublet] a = new double[100] ;


chart]
b = new char[50];
string[] s = new string[1000];
// Tablou de 7 obiecte de tip A
A[] ob = new A [7]';
for (int i = 0; i < ob.Length; i++)
if ( ob[i] == null ) //
Console.Write("null ");
Decimal[] d = new Decimal[10];
for (int i ='0; i < d.Length; i++)
Console .Write (d [i] + "

}
}
Programul afieaz:
null null null null null null null 0 0 0 0 0 0 0 0 0 0

Observaii:
9

1.
2.

C# v permite s definii clase imbricate (nested), aa cum este cazul


clasei A, definit n interiorul clasei TabUndim2.
Valorile implicite ale tablourilor numerice sunt setate la 0, iar elementele
referin sunt setate la nuli.

Initialializare
9

Tablourile unidimensionale se pot iniializa cu valori de acelai tip cu tipul


tabloului:

Partea I. Limbajul C#

38

Exemple:
// Tablou cu 4 elemente.
int[] a = new int[] | 7, 4, 3, 0 );
// Sintax alternativ. Tablou cu 3 elemente
int[]
b = {10, 2, 17};
float[] c = { 1.2F, 7.9F, -8F };
string[] sl = new string[]

{ "UNU", "DOI", "TREI" };

// Sintax alternativ. Tablou cu 3 elemente


string[] s2 = { "UNU", "DOI", "TREI" };

Tablouri multidimensionale
Un tablou poate avea una, dou sau mai multe dimensiuni.

Exemple:
// Tablou bidimensional cu 3 linii i 5 coloane
doublet,] a = new double[3, 5];
// Tablou tridimensional cu dimensiunile 3, 7 i 5
doublet, ,] a = new double[3, 7, 5];

Accesarea elementelor
Accesarea elementelor unui tablou multidimensional se face cu sintaxa
cunoscut din limbajul Pascal. De exemplu, elementul aflat pe linia 2 i coloana 0
ntr-o matrice se acceseaz astfel: a [2, 0].

Iniializare

Tablourile multidimensionale pot fi iniializate ca n exemplele urmtoare:

// Tablou cu 2 linii i 3 coloane .


int[,] x = new int[,]{ { 1 , 2 , 3 } , { 2 , 3 , 0 } } ;
// Identic, dar .cu sintaxa alternativa
int[,] y = { { 1, 2, 3 }, { 2, 3, 0 } };

DE RETINUT

Dac ai creat mai nti referina, iar tabloul va fi creat ulterior, atunci sintaxa
alternativ de iniializare nu se mai poate folosi. n acest caz este obligatorie
utilizarea operatorului new.

Capitolul 3.

Fundamentele limbajului C#

39

Exemplu:
using System;
class TabBidim
{
static void Main()

{
int[,] y;
// y = { { 1, 2, 3 }, { 2, 3, 0 } };
i n t [, ] x ;
x = new int[,] { { 1 , 2 , 3 } ,

// Ilegal

{2,3,0}

} ; / / OK

for (int i = 0; i < 2; i++)

{
for (int j = 0; j < 3; j++)
Console.Write(x[i, j] + " ");
Console.WriteLine();

}
}
}
Ieire:
12 3
2 3 0

Tablouri neregulate
Un tablou neregulat (jagged array) este un tablou ale crui elemente sunt
tablouri. Elementele pot fi tablouri unidimensionale sau chiar multidimensionale.

Exemplu:
Un jagged array cu dou elemente, fiecare dintre acestea fiind un ir de
int, se declar astfel:
int[][] a = new int [2][];

Tabloul nu este nc complet definit. Este nevoie de iniializarea fiecrui element:


a[0] = new int[3]; // tablou unidimensional cu 3 elemente
a[l] = new int[5]; // tablou unidimensional cu 5 elemente

Iniializare

C# permite cteva forme de iniializare a tablourilor neregulate:

Partea I. Limbajul C#

40
1.

Fie tabloul neregulat:

int[] [] a = new int[3] [] ;

Elementele tabloului se pot iniializa cu sintaxa:


a[0]
a[l]
a [2]

=new int[]
=new int[]
= new int[]

{ 2, 7, 3, 8 };
{ 0, -1 };
{ 1, 9, 4 };

Tabloul are ntradevr, form neregulat.


2

-1

2.

A doua variant de iniializare a unui tablou neregulat este urmtoarea:

int[] [] a = new int[] []

{
new int[]
new int[]
new int[]

{1, 4 },
{5, 9, 0, 7,
{6, 8, 3 }

2 },

};
3. A treia variant de iniializare este:
int[] [] a =

{
new in t[]
new int[]
new int[]

{1, 4 },
{5, 9, 0, 7,
{6, 8, 3 }

2 },

};
4. Cu ajutorul cuvntului cheie var, se pot iniializa att variabile simple ct i

tablouri cu tipuri implicite:


var d = 3.5;
var s = "Salut";

// var nlocuiete double


// var nlocuiete string

// Tablou unidimensional, var nlocuiete string[]


var p = new[] { "C# , nuli, "C++", "Java" };
// Tablou neregulat, var inlocuieste int[][]
var q = n e w []
{
n ew [] { 7 , 4 } ,
ne w[] { 2, 0, -4, 8 }

};
n fiecare caz compilatorul deduce tipul de dat din tipul constantelor de iniializare.

Capitolul 3.

Fundamentele limbajului C#

41

Accesarea elementelor
Pentru un tablou neregulat ale crui elemente sunt tablouri unidimensionale,
accesarea se face la fel ca la tablourile din C++: a [ i ] [ j ] .

Exemplu:
using System;
class JaggedArray

{
static void Main()

{
int[] [] a =

{
new in t[] { 1, 4 >,
new in t[] { 5, 9, 0, 7, 2 },
new int[] { 6, 8, 3 }

>;
for (int i = 0; i < a.Length; i++)

{
for (int j = 0 ; j < a[i].Length; j++)
Console.Write(a[i][ j ] + " ");
Console.WriteLine();

}
}
}
Ieire:
1 4
5 9 0 7 2
6 8 3

Tablouri neregulate cu elemente de tip tablou multidimensional


Elementele unui jagged array pot fi tablouri multidimensionale.

Exemplu:
Elementele tabloului neregulat a sunt tablouri dreptunghiulare de valori int:
int[] [,] a = new i nt [3] [,]

{
new
new
new

};

int[,] { {2, 9}, {4,


int[,] { {1, 5}, {3,
int[,] { {8, 6}, {2,

7}, {5, 0} },
12} },
9}, {0, 6},
{3, -1} }

Partea I. Limbajul C#

42

Accesarea elementelor tabloului se face astfel: a[i] [j , k] , unde i este al i-lea


tablou din a, iar j i k este poziia valorii cutate n matricea i. De exemplu,
valoarea -1 din a, se obine: a [2] [3, 1],

Instruciuni
t
n C# o declarare (statement) poate fi: o expresie, o instruciune simpl, o
instruciune compus, o instruciune de control al fluxului de execuie (if, for,
while, etc.), un apel de funcie, un bloc de cod, dar i o declarare de variabil
local.
Un program C# este o secven de asemenea statements care se evalueaz
n ordine. n continuare, vom folosi cuvntul instruciune pentru statement. Fiecare
intruciune se termin cu ;. Intruciunile C# sunt preluate cu unele mici modificri
din C i C++. n continuare vom prezenta intruciunile care controleaz fluxul de
execuie al programului.

Instruciunea
de selecie

if ... else
Instruciunea i f . ..else este mprumutat din limbajul C. Controleaz
fluxul programului prin evaluarea unei expresii booleane. n funcie de valoarea de
adevr, selecteaz pentru executare o secven de instruciuni sau o alta.
if (e x p r e s i e _ b o o l e a n )
instruciuneal;

else
instruciunea2;

sau
if (e x p r e s i e _ b o o l e a n )

{
bloc_instructiunil;

}
else

{
bloc_instructiuni2;

}
Exemplu:
string s = Console.ReadLine();
int x = int.Parse (s) ;
if ( x >= 0 )
Console.Write("pozitiv");
else
Console.Write("negativ");

Capitolul 3.

Fundamentele limbajului C#

43

n cazul instruciunilor if imbricate, trebuie s inei seama de regula conform


creia un else se asociaz cu cel mai apropiat if care nu are else:
if (e x p r e s i e i )
if (e x p r e s i e 2 )
instruciunel;

else
i n t r u c i u n e 2 ; // se asociaz cu if

(e x p r e s i e 2 )

De retinut:

1.

Metoda ReadLineO din clasa System. Console citete linia


urmtoare din stream-ul standard de intrare (tastatur).
2. Metoda Parse (s), membr a structurii System. Int32 convertete
stringul s ntr-un numr ntr-un nteg pe 32 de bii. Amintii-v c tipul
int este un alias pentru structura Int32.

Din pcate biblioteca .NET nu furnizeaz operatorul , aa cum o face


C++, capabil s extrag bytes din sfream-uri i s-i converteasc direct spre tipul
dorit (Exemplu C++: int x; cin x). Metodele Read() sau ReadLineO
care se definesc ca membre ale diferitor clase din .NET, citesc ntotdeauna din
sfream-urile de intrare un caracter, un bloc de caractere sau o linie i returneaz
caracterul citit sau un string. Drept urmare, de cte ori avei nevoie s citii valori
numerice, vei obine un string, pe care l vei converti cu Parse (). Toate tipurile
de date ntregi Intl6, Int32, SByte, etc, definesc aceast metod.

Instruciunea
de selecie

switch
Instruciunile i f imbricate sunt greu de scris corect, greu de citit i greu de
depanat, switch este o intruciune de control mai potrivit atunci cnd avei un set
complex de alegeri de fcut. Sintaxa este identic cu cea din C++.

Sintaxa:
s w itc h
{

( n )

case v a l l : b l o c _ i n s t r u c i u n i l ;
break;
case val2: b l o c _ i n s t r u c i u n i ;
break;
// alte cazuri
default: b l o c _ i n s t r u c i u n i ;

// opional

}
n este o variabil de tip ntreg, de tip char sau de tip string, vall, val2, ... etc,
sunt valorile pe care le poate lua n. Controlul este transferat etichetei case care
potrivete valorii lui n.

Diferena fa de s w itc h din C++ este aceea c C# nu suport cderea


implicit la seciunea urmtoare (fall through). Exemplul urmtor nu va compila:

Partea I. Limbajul C#

44

int k = O;
switch ( k )

{
case O :
Console.WriteLine ( "cazul 0" );
// goto case 1;
case 1:
case 2:
Console.WriteLine( "cazul 1 si 2" );
break;

}
Cderea prin ramuri se poate face numai pentru cazuri vide, cum e case 1. Dac
dorii un salt direct la o anume etichet, folosii instruciunea de salt necondiionat
goto. Dac scoatei de sub comentariu goto case 1; n secvena de program
precedent, atunci pe ecran se va afia:
cazul 0
cazul 1 si 2

Ciclul f o r
Este o instruciune identic cu cea din C++.

Sintaxa:
for (e x p r e s i e i ; expresie2; expresie3)

{
bloc_instructiuni;

>
Dac bloc_instruciuni e format din o singur instruciune, atunci acoladele
sunt opionale. Se evalueaz mai nti expresiei. Apoi se evalueaz
expresie2. Aceasta controleaz bucla. Dac expresie2 este evaluat true, se
execut instruciunile cuprinse ntre acolade, apoi expresie3. Se reia evaluarea
expresie2 i ciclul continu pn cnd expresie2 este evaluat false. Apoi
controlul este cedat instruciunii urmtoare ciclului for.
Toate expresiile sunt opionale. Dac expresie2 lipsete, condiia de test
este evaluat true:
for( ;; )
Console.Write("Ciclu infinit !");

Ciclul fo re a c h
foreach este nou n familia de limbaje C. Este folosit pentru iterarea printre
elementele unui tablou sau ale unei colecii. Coleciile sunt containere de tip
generic, care pot reine secvene omogene de obiecte, aa cum vom vedea mai
trziu.

Capitolul 3.

Fundamentele limbajului C#

45

Sintaxa:
foreach (Tip identificator in expresie)
bloc_instruciuni;

Exemplu:
using System;
class TestForeach

{
static void Main()

{
in t [] a = {10, 20, 30};
foreach (int x in a)
Console.Write(x + " ");
Console.WriteLine() ;
string[] st = { "UNU", "DOI", "TREI" };
foreach (string s in st)
Console.Write(s + " ");

}
}
Ieire:
10 20 30
UNU DOI TREI

Ciclul w h ile
Este mprumutat fr modificri din C++.

Sintaxa:
while (e x p r e s i e )

{
bloc_instruciuni;

}
Dac bloc_instruciuni e format dintr-o o singur instruciune, atunci
acoladele sunt opionale. Se evalueaz expresie. Dac este evaluat true,
atunci se execut bloc_instruciuni. Se reia evaluarea expresiei. Ciclul
continu ct timp este evaluat true.

Exemplu:

Partea I. Limbajul C#

46

int x = 5 ;
while ( x > O )
x ;

Ciclul do w h ile
Este preluat fr modificri din C++. Este un ciclu cu test final, deci
bloc_instruciuni se evalueaz cel puin o dat.

Sintax:
do

{
bloc_instruciuni;

} while (e x p r e s i e );

Dac bloc_instruciuni e format dintr-o o singur instruciune, atunci


acoladele sunt opionale. Se evalueaz blocjLnstruciuni, dup care
expresie. Ct timp aceasta se evalueaz true, ciclul continu. n momentul n
care expresie se evalueaz false, se transfer controlul intruciunii imediat j
urmtoare ciclului.
Exemplu:
int x = 5 ;
do
{
x ;
} while ( x > 0) ;

Observaie
Rezultatul evalurii expresiilor care controleaz buclele C# trebuie s fie o
valoare boolean, adic true sau false. Secvena urmtoare nu va compila:
int x = 5;
do
{

x;
} while ( x );

// Ilegal! x este evaluat la o valoare int

Instruciuni
de salt necondiionat
f

C# admite instruciunile de salt goto, break i continue.

Instruciunea goto
Utilizarea goto este nerecomandabil, deoarece produce cod greu de
neles (cod spaghetti). n cazul n care dorii totui s o folosii urmai paii:
1.
2.

Creai o etichet ( identificator urmat de :


goto etichet

Capitolul 3.

Fundamentele limbajului C#

47

Exemplu:
using System;
public class GoTo

{
static void Main()

{
int x = 1;
repeta:
// Eticheta
Console.Write( x + " ");
X ++ /

if (x <= 5)
' goto repeta; // Salt la eticheta

}
}
Ieire:
1 2 3 4 5

Instruciunile break i continue


Dac n blocul de instruciuni al unei bucle se execut continue, atunci are
loc un salt la nceputul buclei. Instruciunea break duce la ieirea forat din ciclu.

Exemplu:
using System;
public.class TestBreakContinue

{
static void Main()

{
for (int i = l;i i <= 100; i++)

'

'

if (i % 2 =- 1)
//Pentru valori impare
continue;
'.// salt la expresia i < 10
Console.Write(i + " ");
if (i == 10) break;
// "Rupe" bucla

}
}
}
Ieire:
0 2 4 6 8 10

Partea I. Limbajul C#

48

Sugestie
Nu este indicat s utilizai intens aceste instruciuni, deoarece creeaz puncte
multiple de ieire din cicluri, ceea ce duce la cod dificil de neles i de ntreinut
(cod spaghetti).

Spaii de nume
n capitolele 2 i 3 s-au discutat primele noiuni referitoare la spaii de nume
(namespaces). Am artat c sunt containere logice care gzduiesc definiii ale
tipurilor de date. Au fost introduse n C# pentru evitarea conflictelor de nume n
utilizarea bibliotecilor de clase, dar i pentru organizarea i sistematizarea tipurilor
de date. De exemplu, dac ntr-o aplicaie utilizai dou biblioteci neprotejate prin
spaii de nume, care provin de la furnizori diferii, este posibil ca un acelai nume
de clas, s-i spunem Button, s fie definit n ambele biblioteci, ceea ce ar crea o
coliziune n program, inacceptabil de ctre compilator.
ntreaga^ Biblioteca de Clase .NET se gsete n interiorul acestor
namespaces. n afara spaiilor de nume ale bibliptecii .NET Framework sau ale
bibliotecilor altor furnizori, C# v permite s v creai propriile spaii de nume. Se
definesc foarte simplu cu ajutorul cuvntului cheie namespace.
Exemplu:
namespace MySpace
{
static void Main()

{
}
}

Spaii de nume imbricate (nested)


ntr-un spaiu de nume putei defini nu numai tipui de date ci i alte spaii de
nume.
Exemplu:
namespace X
{
namespace Y
{

}
namespace Z
{
namespace W

{
}
}
static void Main()

{
}
}

Capitolul 3.

Fundamentele limbajului C#

49

n interiorul lui x s-au definit alte dou spaii de nume Y i z i metoda M a in () . n


z s-a definit w.

Accesarea numelor de tipuri


Accesarea numelor definite ntr-un namespace se face preciznd toate
spaiile de nume pn la numele clasei dorite, separate ntre ele cu operatorul
punct ( . ) .
Exemplu:
Cum vom accesa numele clasei Button ?

System
Windows

Forms
clasa
Button

n figur s-a ilustrat faptul c spaiul de nume


System include spaiul de nume Windows,
care la rndul lui include Forms. Clasa
Button, ca de altfel toate clasele de tip
fereastr se definesc n Forms.
Cum accesm numele Button ? Vom
crea un obiect de tip Button astfel:
System.Windows.Forms.Button b =
new System.Windows.Forms.Button();

Cam complicat, nu-i aa ? Din fericire, exist


directiva using.
Figura 3.1 Accesarea numelor
Programele C# ncep de regul cu o seciune de directive using.
([4])
using precizeaz spaiile de nume cel mai utilizate n program. n felul acesta
orogramatorul nu mai este nevoit s scrie ntreaga cale (fully qualified name) pn
a clasa cutat,
a) Accesarea unui nume de clas folosind calificarea complet a numelui acesteia:
public class NestedNamaspaces

{
static void M a i n ()

{
System.Windows.Forms.Button b =
new System.Windows.Forms.Button();

}
}

Partea I. Limbajul C#

50

b) Accesarea unui nume de clas cu utilizarea directivei using:


using System.Windows.Forms;
public class NestedNamespaces
{
static void Main()

{
Button b = new Button();

}
}

Not:
Pentru ca programul de la punctul b) s compileze, trebuie s aducei
proiectului de tip consol o referin, la spaiul de nume System. Windows.Forms
astfel:
n Solution Explorer, click dreapta pe numele proiectului.
Alegei Add reference.
n tab-sheet-u l .Net alegei System.Windows.Forms i apsai OK.

ATENTIE
!
j

O directiv using nu v permite accesul la nici un spaiu de nume definit n


spaiul de nume pe care l specificai.
Exemplu:
using System;

public class WrongAcces

{
static void Main()

{
Windows.Forms.Button b = new Windows.Forms.Button();

}
}
Programul de mai sus nu compileaz, deoarece Windows este un spaiu de nume
imbricat n System i nu putei avea acces la acesta, ci doar la numele de tipuri
(clase sau structuri ) din System. Cu directiva de mai sus, este corect s scriei
astfel:
System.Windows.Forms.Button b =
new System.Windows.Forms.Button();

Alias-uri
Pentru simplificarea scrierii putei declara nume alternative pentru spaiile de
nume, astfel:

Capitolul 3.

Fundamentele limbajului C#

51

a) Introducerea unui alias pentru spaii imbricate, definite de programator:


using N = N1.N2.N3;

// Creeaz un alias N

namespace NI
{
namespace N2
{
namespace N3
{
public class C { }

}
}
}
public class estAlias
{
static void Main()

{
N .C ob = new N .C ();

}
}
b) . Introducerea unui alias pentru spaii de nume predefinite:
using F = System.Windows.Forms;
public class estAlias
{
static void Main()

{
F .ComboBox cb = new F .ComboBox();

}
}

Directive de preprocesare
nainte ca programul s fie compilat, un alt program numit preprocesor,
ruleaz i pregtete programul pentru compilare. Preprocesorul detecteaz
directivele de preprocesare i stabilete nite reguli de compilare n raport du
acestea. Directivele ncep cu caracterul #. Le vei introduce n situaii n care dorii
ca unele poriuni de cod s nu fie compilate n anumite condiii. De exemplu, n
etapa de build final a unei aplicaii, nu dorii s mai compilai poriuni de cod pe
care l-ai folosit pentru depanare.

Partea I. Limbajul C#

52

Directiva # d e fin e
Numele simbolice se definesc cu directiva #define, naintea oricrei
secvene de cod din program. Alte directive pot fi definite i n alte zone ale
programului.
Exemplu:
#define DEPANARE
// Cod neafectat de directiva #define
#if DEPANARE
// Cod care se compileaz dac este definit numele DEPANARE
#else
// Cod care se compileaz daca nu este definit DEPANARE
#endif
// Cod neafectat de preprocesor

Cnd preprocesorul ruleaz, ei caut directiva #define. Dac aceasta exist, ia


not de identificatorul d e p a n a r e . Directiva #if testeaz existena identificatorului
n funcie de aceasta, seteaz pentru compilare o poriune de cod sau alta.
Orice cod care nu este cuprins ntre #if i #endif este compilat de ctre
compilator.

Directiva #undef ine


Dac ntr-un punct n program dorii ca un anume identificator definit cu
#define s nu mai fie definit, deci s nu mai fie cunoscut de ctre preprocesor,
atunci folosii directiva #undef:
#define DEPANARE
#define MAXIM
// Cod neafectat de directiva #define
#if DEPANARE
// Cod care se compileaz
#endif
#undef DEPANARE
#if DEPANARE
// Cod care NU se compileaz
#elif MAXIM
// Cod care compileaz pentru c nu e definit DEPANARE,
// dar este definit MAXIM
#endif

S observm c #elif testeaz existena unui nume simbolic doar n cazul n


care testul #if eueaz.

Capitolul 3.

Fundamentele limbajului C#

53

Rezumatul capitolului

Tipurile predefinite din C# (int, char.. string), sunt mapate direct


peste tipuri struct din spaiul de nume System. De exemplu, tipului int
i corespunde clasa System. Int32 din Biblioteca de Clase .NET.
Tipurile definite cu ajutorul cuvintelor cheie class sau struct se
numesc tipuri definite de programator.
Variabilele de tip clas se numesc obiecte sau instane ale clasei.
Tipurile valoare sunt toate tipurile predefinite (char, int, float, etc.),
cu excepia tipurilor string i object.
Tipurile referin: se definesc de ctre programator. n aceast categorie
se includ tipurile clas, tipurile interfa, tipurile delegat i tipurile array
(tablourile).
Datele variabilelelor de tip valoare, se memoreaz pe stiv (Stack).
n cazul tipurilor referin, referinele sunt n stiv, iar datele se aloc
dinamic n Heap.
n C# tablourile sunt tipuri referin. Tablourile pot fi unidimensionale
sau multidimensionale. Cele multidimensionale, la rndul lor pot fi
dreptunghiulare sau neregulate (jagged).
Instruciunile de control al fluxului de execuie a programului (if, for,
while, etc) sunt similare sintactic cu cele din limbajul C++.
ntreaga Biblioteca de Clase .NET se gsete n interiorul spaiilor de
nume. n afara spaiilor denume predefinite, programatorii pot s
defineasc propriile spaii de nume cu ajutorul cuvntului cheie
namespace.

Directivele de preprocesare se introduc n situaiile n care se dorete ca


unele poriuni de cod s nu fie compilate n anumite condiii.

n tre b ri i e x e rc iii
1.

Care este diferena dintre tipurile valoare i tipurile referin ?

2. n ce condiii se produc erori la compilare atunci cnd declarai o variabil?


Dar o constant ?
3. n care zone ale memoriei RAM se memoreaz membrii unei clase ?
4.

Declarai i iniializai un tablou bidimensional dreptunghiular cu 4 linii i 3


coloane.

5.

Declarai i iniializai un tablou bidimensional neregulat cu 3 linii.

6.

Definii dou spaii de nume: x i Y, unde Y este coninut n X. n Y definii


clasa A. Scriei dou programe C# n care se instaniaz clasa A, utiliznd
moduri diferite de accesare a numelui clasei.

54

Partea I. Limbajul C#

Capitolul 4

Programare Orientat pe Obiecte n C#


Programarea Orientat pe Obiecte (OOP) este cea mai influent
paradigm de programare a timpurilor noastre. Prin paradigm se nelege stil de
programare. n raport cu stilul de programare procedural, OOP reprezint o cu
totul alt abordare a programrii.
n limbajulele C sau Pascal ca i n toate celelalte limbaje procedurale, se
pot defini tipuri de date i n mod separat funcii care acioneaz asupra acestora.
Separarea tipurilor de date de funciile corespunztoare, impune programatorului
eforturi considerabile pentru a menine logica gruprii acestora, mai ales cnd
aplicaia are mii de linii de cod.
n OOP funciile sunt grupate n acelai obiect, mpreun cu datele asupra
crora opereaz. Datele sunt mai complexe n OOP i mai bine organizate.
Organizarea superioar se dovedete foarte util atunci cnd se scriu aplicaii
foarte mari, cnd se lucreaz n echip i cnd se scrie cod pentru biblioteci care
vor fi folosite de clieni.

Obiecte i clase
Limbajul C# este un limbaj orientat-obiect. Limbajele orientate pe obiecte au
calitatea c permit programatorului s-i creeze noi tipuri complexe de date.
Tipurile se obin prin definirea de clase. Clasele sunt baza programrii orientat pe
obiecte. O clas reunete cod i date care descriu o anumit categorie de obiecte.
Clasa este apoi folosit pentru construirea de obiecte. Crearea unui obiect se
numete instaniere. Obiectul creat se numete instan a clasei.
Diferena dintre un obiect i o clas este aceeai ca diferena ntre o pisic i
descrierea unei pisici. Descrierea este clasa, iar pisica este obiectul. De altfel,
clasele i obiectele au aprut n programare tocmai din necesitatea de a modela
obiectele din realitate, dar i obiecte abstracte.
O clas Pisica, specific trsturile care ne intereseaz la o pisic: nume,
ras, greutate, culoarea blnii, etc. De asemenea, clasa descrie aciunile pe care o
pisic le poate face: s sar, s zgrie, s toarc, etc. Pisica Kitty, rasa Birmanez,
greutatea - 4 Kg, culoarea blnii - gri, este o instan a clasei, deci un obiect de tip
Pisica.

Marele avantaj al claselor este c ncapsuleaz caracteristicile i


capabilitile obiectului ntr-o singur unitate de cod. O clas descrie complet
obiectele de tipul su, nemaifiind nevoie n acest scop de cod exterior clasei.
Mai trebuie s reinei urmtoarele: programarea orientat pe obiecte nu
este doar programare cu obiecte. ntre obiecte pot exista relaii, obiectele pot
comunica ntre ele, obiectele pot folosi alte obiecte.

Capitolul 4.

Programare Orientat pe Obiecte n C#

55

Mecanismele fundamentale ale OOP


Toate limbajele orientate pe obiecte au cteva caracteristici comune:

1. Abstractizarea
Abstractizarea este simplificarea realitii prin modelarea unor clase care
pstreaz doar trsturile obiectului real care sunt eseniale i suficiente pentru
atingerea scopului propus. Membrii clasei (cmpuri, metode, etc.) definesc aceste
trsturi.

2. ncapsularea
Un obiect ncapsuleaz date i cod care acioneaz asupra acestor date.
Clasa ofer protecie membrilor si. Nu toi membrii clasei pot fi accesai din afara
ei. O regul important n OOP este aceea c datele membre trebuie s rmn
private, s fie inaccesibile din lumea exterioar clasei, pentru a prentmpina
modificrile accidentale. Partea accesibil a clasei o constituie membrii publici, de
regul metodele. Acetia pot fi utilizai de ctre poriuni din program care lucreaz
cu obiectele clasei. Membrii publici ai unei clase formeaz interfaa clasei.

3. Motenirea
Motenirea este mecanismul prin care un limbaj orientat-obiect v permite s
definii noi clase care incorporeaz i extind o clas deja definit. Noile clase se
numesc clase derivate. Ele motenesc atributele i comportamentul clasei pe care
o extind, fiind versiuni specializate ale clasei de baz. Clasa pe care o extindei se
numete clas de baz. Ca exemplu, s presupunem c dorii pentru aplicaia
dumneavoastr un buton care s aib funcionalitatea unui buton de apsare, dar
s aib n plus anumite proprieti: s fie rotund, s aib un mic punct luminos
central care clipete cnd este apsat, etc. Avei dou opiuni: s scriei o clas
care s ndeplineasc toate cerinele sau s scriei o clas MyButton, care s
moteneasc de pild clasa System.Windows.Forms.Button. A doua variant
este avantajoas, deoarece clasa MyButon motenete ntregul comportament i
caracteristicile unui buton obinuit i vei avea nevoie s adugai doar codul cerut
de cerinele suplimentare. Reutilizarea codului este unul dintre beneficiile
importante pe care le aduce motenirea.

4. Polimorfismul
n programarea orientat pe obiecte, polimorfismul (cuvnt care vine din
greac i care nsemn a avea mai multe forme") este caracteristica unei interfee
de a fi folosit cu aciuni multiple. O funcie sau un obiect au un comportament
polimorfic, dac acestea au mai mult de o singur form.
Polimorfismul, caracterizat de expresia interfa comun, aciuni multiple",
este deci capacitatea de a folosi n funcie de context, mai multe forme ale unui tip
sau metod, fr s ne intereseze detaliile de implementare.
Exist cteva tipuri de polimorfism. Unul dintre acestea se obine n OOP cu
ajutorul motenirii. S lum un exemplu din viaa real: Un dresor de circ are trei
animale : un arpe, un porumbel, i un tigru. Cnd vrea s cheme unul dintre ele,

Partea I. Limbajul C#

56

le trimite un unic mesaj: la masa /. Ca rspuns la acest mesaj, arpele se


trte, porumbelul zboar, iar tigrul alearg. S ne imaginm clasele arpe,
Porumbel i Tigru. Toate clasele motenesc clasa Animal. Fiecare clas i-a
definit aceeai interfa, metoda LaMasa", dar cu aciuni diferite. Obiecte diferite
(animalele) rspund n mod diferit aceluiai mesaj (metoda LaMasa ()). Pentru
dresor nu este important cum procedeaz fiecare animal pentru a veni (detaliile de
implementare ale metodei LaMasaQ ), ci conteaz doar faptul c animalul vine la
mas.

Clasele

C#

n afara celor cincisprezece tipuri predefinite n C#, putei crea propriile tipuri
de date (user-defined types). Exist ase categorii de tipuri pe care le putei crea:
1. Tipuri class
2. Tipuri struct
3. Tipuri tablou
4. Tipuri enum
5. Tipuri delegate
6. Tipuri interface
Odat ce ai definit un tip de dat l putei utiliza ca i cnd ar fi un tip predefinit.
Dintre tipurile enumerate mai sus, class este cel mai important. O clas
este o structur de date care poate depozita date i executa cod. Primele noiuni
despre clasele C# au fost discutate n capitolul 3.

Definiie_______________________________________________
Clasele sunt entiti logice care modeleaz obiecte din lumea real sau
obiecte abstracte. Clasele ncapsuleaz date i funcii care opereaz cu aceste
date.
Caracterisiticile obiectului se memoreaz n cmpurile clasei.
Capabilitile, aciunile obiectului, se codific n metodele clasei.

Cmpurile (acestea sunt date membre) sunt variabile care rein


informaii despre obiect.
Metodele sunt funcii membre ale clasei.

Cmpurile i metodele unei clase se numesc membrii clasei. O clas poate avea
un numr orict mare de date membre i de funcii membre. Membrii pot fi oricare
combinaie a urmtoarelor tipuri de membri:
Date membre
Cmpuri
Constante

Funcii membre
Metode
Proprieti
Constructori

Capitolul 4.

Programare Orientat pe Obiecte n C#

57

Destructori
Operatori
Indexatori
Evenimente

Definirea claselor
O clas se declar cu ajutorul cuvntului cheie class.

Sintaxa minimal:
class nume__clas
{

// Cmpuri
[modificator de acces]

Tip n u m e ;

II Metode
[modificator de acces]

TipRetur N u m e M e t o d ( P a r a m e t r i ) ;

}
Modificatorii de acces controleaz regiunile programului care pot accesa membrii
clasei. Tabelul descrie cele ase tipuri de modificatori:
Atributul
public
private
protected
internal
protected internal

Descriere
Acces nelimitat
Acces limitat la propria clas
Acces limitat la propria clas i la clasele derivate
Acces limitat la programul care conine clasa
Acces limitat la program i la clasele derivate

Dac modificatorul de acces lipsete, atunci membrul respectiv este n mod implicit
private. Parantezele ptrate indic opionalitatea.

Cum se lucreaz cu obiecte ?


1. Mai nti se definete clasa. Exemplu:
class X
{
// membrii clasei

}
2.

Acum putei utiliza tipul x pentru a crea obiecte:


X r = new X() ;

r este referin la obiectul de tip x care se aloc dinamic cu new x ()


(Heap-ul sistemului), x () este constructorul clasei x.

Partea I. Limbajul C#

58

Despre constructori vom discuta ntr-unul dintre paragrafele urmtoare.


3.

Folosii referina pentru a accesa membrii clasei:


r.membru; // Cu operatorul . se acceseaz membrii clasei

Exemplul 1:
class Program
{
static void Main()

{
}

Clasa Program are ca membru doar metoda static Main(). Aceast metod
este punctul de intrare n program (entry point). Membrii statici ai unei clase exist
independent de obiectele clasei. Din acest motiv, Main () poate fi apelat de ctre
platforma .NET, fr s fie nevoie de un obiect de tip Program.
Exemplul 2:
class Test
{
int x = 100;

// Cmp privat

static void Main()

{
x = 10;
Test r;
r = new Test () ;
r.x = 20;

//
//
//
//
//
//

Greii x trebuie s aparin


unui obiect
Declar o referin
Creaz un obiect
Corect, x este privat, dar
Main() e membr a clasei

}
Exemplul 3:
using System;
class Test

t
private int x;
// Metode publice
public int GetX()

{
return x;

// Cmp privat

Capitolul 4.

Programare Orientat pe Obiecte n C#

59

public void SetX(int n)

{
x = n;

// Metodele clasei au acces


/ / l a cmpurile private

}
class Program
{
static void Main()
{
Test r;
// Declar o referin
r = new Test(); // Creeaz un obiect
r.x = 20;
//
// Greit. x este private
r.SetX(lO);
// Corect. SetX() este public
Console.WriteLine (r,.GetX () ) ;
}

}
Ieire: 10
Programul de mai sus are dou clase. n clasa Program, metoda Main(),
creaz un obiect de tip Test, care mai apoi este utilizat pentru accesarea
membrilor si publici.

Metode. Parametrii metodelor.


Metoda este un bloc de cod care poate fi apelat din diferite pri ale
programului i chiar din alte programe. Cnd o metod este apelat, i execut
codul, apoi transfer controlul codului care a apelat-o. Metodele pot fi
implementate ca membri ai claselor sau ai structurilor sau ca prototipuri n interfee.
Metodele pot s aib sau s nu aib parametri i pot s returneze sau nu valori.
Dac nu returneaz valori, returneaz void. De asemenea, metodele pot fi statice
sau ne-statice.
ATENTIE
!

Spre deosebire de C sau C++, n C# nu exist metode globale. Metodele nu


se pot declara n afara unui tip de date.
Sintaxa minimal a unei metode este:
[ModificatorAcces]

TipRetur NumeMetod (ListaParametri)

t
// codul metodei

}
Apelul unei metode:
NumeMetod (ListaArgumente ) ;

Argumentele (sau parametrii actuali) sunt valorile sau obiectele cu care se


apeleaz metodele.

Partea I. Limbajul C#

60

Parametrii unei metode pot fi precedai n C# de cteva cuvinte cheie, numite


modificatori. Modificatorii sunt: ref, out, params. Acetia controleaz modul n
care argumentele sunt transmise unei metode.

Parametri valo are


n mod implicit, tipurile valoare sunt pasate metodelor prin valoare. Aceasta
nseamn c atunci cnd un obiect de tip valoare este transmis ca argument unei
metode, o copie temporar a obiectului este creat de ctre metod pe stiv. Cnd
metoda i termin execuia, copiile temporare sunt distruse, n general avei
nevoie doar de valoarea argumentelor, ns sunt situaii cnd dorii s modificai
valoarea argumentelor. n acest caz, mecanismul transmiterii prin valoare nu v
ajut.
Exemplu:
using System;
class S

{
public void Schimba(int x, int y) // x, y - parametri
{
//
formali
int aux;
// x, y, aux - variabile locale
aux = x; x = y; y = aux;

}
}
class Test
{
static void Main()

{
S s = new S () ;
int a = 10, b = 20; II a, b - variabile locale
// a, b - argumente pasate prin valoare
s.Schimba(a, b);
Console.WriteLine("a = {0}, b = {1}", a, b) ;

}
}
Programul afieaz: a = 1 0 , b = 20
Observm c a i b au rmas nemodificai n urma apelului, deoarece la
transmiterea prin valoare x i y sunt copii locale ale argumentelor a i b.
Argumentele nu trebuie s fie n mod obligatoriu variabile. Poate fi argument orice
expresie care se evalueaz la tipul parametrului formal.

Parametri referin
i

Dorim s modificm programul anterior, astfel nct valorile a i b s se


modifice dup apel. Se aplic modificatorul ref asupra parametrilor formali i
asupra parametrilor actuali astfel:

Capitolul 4.

Programare Orientat pe Obiecte n C#

61

public void Schimba(ref int x, ref int y)

{
int aux;
aux = x; x = y; y = aux;

}
int a = 10, b = 20;
s .Schimba(ref a, ref b ) ;
//s.Schimba(2*a, b - 1); //
//
Rulai programul. Va afia: a = 20,

// Iniializare obligatorie
// Apel
Greit! Argumentele nu
sunt variabile de memorie
b = 10

Cnd dorim s pasm argumente prin referin, atunci:


> Trebuie utilizat modificatorul ref att n definiie, ct i n apelul metodei.
> Este obligatoriu ca argumentul transmis funciei s fie o variabil, iar
acestei variabile trebuie s-i fie atribuit o valoare nainte de a fi utilizat ca
parametru actual.
3arametrii referin au urmtoarele caracteristici:
Nu aloc memorie pe stiva programului pentru parametrii formali.
Parametrul formal este de fapt un alt nume (un alias) pentru variabila de apel,
referind aceeai zon de memorie. Din aceast cauz, orice modificare asupra
valorii parametrului formal n timpul execuiei metodei, se exercit direct
asupra parametrului actual i persist dup apelul metodei.

3arametri de ieire
Parametri de ieire sunt utilizai pentru a transmite date din interiorul metodei
ap 'e codul care a apelat-o. Nu conteaz valorile iniiale ale argumentelor, ci doar
ne e finale.

lerine:
>
>

Trebuie utilizat modificatorul out att n definiie, ct i n apelul metodei.


Este obligatoriu ca argumentul transmis funciei trebuie s fie o variabil i
nu o expresie. Acestei variabile nu este nevoie s-i fie atribuit o valoare
nainte de a fi utilizat ca parametru actual.

Exemplu:
sLass OutParam
public void Metoda(out int x)

{
// int y = x; // Eroare!
x = 100;
// Iniializare nainte de
x++;
// a se citi din variabila x

Partea I. Limbajul C#

62

class Program
{
static void Main(string[] args)

{
OutParam op = new OutParam{);
int z;
// Nu e nevoie de iniializare
op.Metoda(out z) ;
System.Console.Write(z) ;

}
}
La fel ca n cazul parametrilor referin, parametrii de ieire (output parameters)
sunt a//as-uri pentru parametrii actuali. Orice schimbare asupra unui parametru de
ieire, se produce de fapt asupra argumentului funciei.
Parametrii de ieire au urmtoarele caracteristici:
n interiorul metodei, parametrilor de ieire trebuie s li se atribuie valori
nainte de a se utiliza valoarea acestora. Din acest motiv, valorile iniiale
ale parametrilor actuali (argumente) sunt nenecesare i nici nu este nevoie
s iniializai argumentele nainte de apelul metodei.
Tuturor parametrilor de ieire trebuie s le fie atribuie valori nainte de
revenirea din apel.

Parametri tablou
Parametrii tablou (parameter array) admit zero sau mai muli parametri
actuali pentru un acelai parametru formal.
Restricii:
*

Poate exista doar un singur parametru tablou n lista de parametri


formali.
Dac exist un parametru tablou, atunci acesta este ultimul n lista
de parametri formali.
Pretinde modificatorul params n declaraie, dar nu este permis n
apelul metodei.

Parametrii tablou se declar ncadrnd tipul parametrului la stnga cu modificatorul


params, iar la dreapta cu operatorul de indexare: [ ].

Exemplu:
class Params
{
public void Print(params int[] x)

{
foreach (int i in x)
System.Console.Write(i + " ");
System.Console.WriteLine();

}
}

Capitolul 4.

Programare Orientat pe Obiecte n C#

63

class Program
{
static void Main(string[] args)
{

Params p = new Params( ) ;


p . P r i n t (1, 3 ) ;
p . P r i n t (2, 4, 6, 8) ;
i n t [] a = { 10, 20, 30 } ;
p .P r in t( a ) ;

// n
/ / (*)
/ / (**)

}
Ieire:
1 3
2 4 6 8
10 20 30
Invocarea metodei se poate face n dou moduri: o lista separat prin virgul cu
valori de tipul parametrului (*), sau un tablou de elemente (**).
O ultim observaie: n C# tablourile sunt tipuri referin, astfel nct
parametrii tablou sunt i ei referine.

Suprancrcarea metodelor
C# suport suprancrcarea metodelor clasei (overloading). Este vorba
depre procedeul prin care definii dou sau mai multe metode cu acelai nume, n
aceeai clas. Suprancrcarea are i restricii: metodele trebuie s difere prin
numrul i/sau tipul parametrilor formali.

Exemplu:
n clasa O v e rlo a d in g dorim s suprancrcm metoda: v o id F ( i n t a)
c la s s O v e rlo a d in g
{
v o id F ( i n t a) { }
v o id F (c h a r b) { }
v o id F ( i n t a, ch a r b) { }
v o id F ( i n t a, i n t b) { >
/ / i n t F ( i n t a ) {}
}

{}

/ / C o re ct
/ / C o re ct
/ / C o re ct
/ / G r e it! Tipul parametrului
// formal este acelai

Partea I. Limbajul C#

64

Membrii statici ai unei clase


n mod implicit, metodele i cmpurile clasei sunt ne-statice. Pentru a putea
invoca o metod ne-static, avei nevoie de un obiect de tipul clasei. Metodele
statice se pot apela n lipsa obiectelor. Ele au comportamentul unor funcii globale,
care ns nu sunt vizibile dect n cadrul clasei. De asemenea, cmpurile declarate
static, se aloc n memorie i pot fi folosite, chiar dac nu ai construit nici un
obiect.

Accesarea membrilor statici.


Fie clasa:
class C
{
public static int x;
public static void F() {}

}
Accesarea acestor membri se face prin numele clasei, astfel; C .x i c . F ( ) ;
Exemplul 1:
class Program
{
static int x = 10;
static void F()

{
}
int y = 20;
void G()

// Membri ne-statici

{
}
static void Main(string[] args)

{
// Membrii statici aparin clasei
x = 100;
// Corect
F();
// Corect
Program.x= 100; // Corect! Accesare prin
Program.F();
// numele clasei.

//
//

// Membrii ne-statici aparin obiectelor


y = 200;
// Greit
G ();
// Greit
Program p = new Program();
p.y = 100;
// Corect
p.G();
// Corect

Capitolul 4.

Programare Orientat pe Obiecte n C#

65

Observaie:
C#admite iniializarea datelor membre, la momentul declarrii lor, aa ca
mai sus: int y = 20; sau int x = 10;
Exemplul 2:
Cnd accesai membrii statici din afara clasei trebuie s folosii sintaxa:
NumeClas.MembruStatic;
class ClasaMea
{
public static string s = "Ionel";
public static void F() { }

}
class Test
{
static void Main(string[] args)

{
//
//

s = "Marcel";
// Greit
ClasaMea.s = "Marcel"; // Corect
F ();
// Greit
ClasaMea.F ();
// Corect

}
}

Constante
Dac dorii s pstrai valori care nu se vor schimba pe parcursul execuiei
programului i n acest scop vrei s le protejai la scriere, vei declara constante. n
C# , constantele apar n dou forme:
1.
2.

Constante locale.
Constante membre ale clasei.

Att constantele membre, ct i cele locale, se introduc cu cuvntul cheie const.


Constantele locale se declar n corpul metodelor i sunt vizibile doar n corpul
acestora:
void Metoda(int a)

{
const int x = 100;
// Iniializare obligatorie
// x++
// Eroare!
a = x;
// Corect

}
Constantele membre se comport la fel ca valorile statice. Sunt vizibile n fiecare
instan (obiect) al clasei i sunt disponibile chiar n lipsa obiectelor clasei.
Exemplu:

Partea I. Limbajul C#

66

using System;
class C
{
public const int H = 24;

}
class TestConst
{
static void Main(string[] args)

{
Console.Write(C.H);

}
}

De reinut:
Constantele trebuie iniializate la declarare.
Constantele membre se acceseaz la fel ca membrii statici:
NvmeClas.NumeConstant.

Constructori
Constructorul de instan este o metod special a clasei, care are rolul de
a creea, a construi obiecte. O clas are cel puin un constructor. De fiecare dat
cnd instaniai un obiect de tip struct sau class, se apeleaz constructorul
clasei.
Exemplu:
class Maina
{
public string marca;
public int pre;

}
class Test
{
static void Main(string[] args)

{
Maina m = new Masinaf); // Apelul constructorului

}
}
Observai c instanierea obiectului presupune de fapt apelul constructorului clasei:
Maina (). Toate clasele au un constructor. Putei defini proprii constructori. n

cazul n care nu o facei, compilatorul va genera un constructor n mod implicit.


Clasa Maina nu definete un constructor. n aceast situaie, compilatorul
genereaz un constructor implicit, fr parametri, Maina (), care construiete
obiectul, dar nu intreprinde alt aciune.

Capitolul 4.

Programare Orientat pe Obiecte n C#

67

Constructorul implicit iniializeaz cmpurile clasei cu urmtoarele valori


implicite:
Tipurile numerice (int, short, etc.) i tipul enum cu valoarea 0.
Tipul bool cu valoarea false.
Tipul char cu ' \ 0 ' .
Tipurile referin (inclusiv string sau tablouri) cu nuli.
n mod frecvent vei dori s stabilii starea iniial a obiectului prin setarea unor
valori iniiale ale datelor membre. Pentru aceasta, vei defini unul sau mai muli
constructori. De exemplu, pentru clasa Maina, putei scrie:
using System;
class Maina

{
public string marca;
public int pre;
public Maina(string m, int p) // Constructor
{
marca = m;
pre = p;

}
}
class Test

{
static void Main(string[] args)

{
// Maina m = new Maina (); // Greit! Nu mai exist
// constructorul implicit!
// Se invoc constructorul Maina(string, int)
Maina m = new Maina("Audi", 50000);
Console.Write(m.marca + " " + m.pret);

}
}
Ieire: Audi 50000

ATENIE !
n momentul n care ai definit cel puin un constructor, compilatorul nu mai
sintetizeaz constructorul implicit. De aceea, dac dorii i unul fr parametri,
trebuie s-l definii.
Exemplu:
class Maina

{
public string marca;
public int pre;

Partea I. Limbajul C#

68

public Maina()

// 1

{
marca = "Fiat";
pre = 1000;

}
public Maina(string m)

// 2

i
marca = m;
pre = 20000;

}
public Maina(int p)

// 3

{
marca = "Ford";
pre = p;

}
public M aina(string m, int p) // 4
{
marca = m;
pre = p;

>
}
Acum putei crea obiecte de tip Maina n mai multe moduri:
Maina
Maina
Maina
Maina

ml =new Maina();
// constructor 1
m2 =new Maina("Opel"); // constructor 2
m3 =new Maina(2000);
// constructor 3
m4 = new Maina("Renault", 15000);
// constructor 4

Caracteristicile metodelor constructor

Sunt metode care se apeleaz ori de cte ori, un obiect este creat.
Au acelai nume ca cel al clasei.
Nu au tip de retur, deci nu returneaz nimic, nici mcar void.
Pot fi suprancrcai, la fel ca oricare metod a clasei.
Pot s fie declarai static, pentru iniializarea membrilor statici ai clasei.
De regul se declar public, ns dac dorii ca un anumit constructor s
nu poat fi invocat din afara clasei, l declarai private. Procedai n
acest fel, mai ales cnd o clas conine numai membri statici. n aceast
situaie este inutil s permitei crearea de instane ale clasei (obiecte).

Constructori de copiere
Dac dorii ca un obiect s fie creat ca o copie fidel a unui alt obiect, atunci
este convenabil s definii un constructor de copiere (copy constructor). C# nu
furnizeaz un constructor de copiere implicit, aa cum ofer un constructor de
instan implicit. De aceea va trebui s-l definii dumneavoastr.
Exemplu:

Capitolul 4.

Programare Orientat pe Obiecte n C#

69

using System;
class C

{
private int x;

// Cmp privat

public C(int a) // Constructor de instan

{
x = a;

}
public C(C ob)
{
x = ob.x;

// Constructor de copiere

}
public int GetX()

{ return x; } // Metod accesor

}
class TestCopyCtor

{
static void Main(string[] args)

{
C cl = new C(10);
// Apeleaza C(int)
C c2 = new C(cl); // Apeleaza C(C)
Console.WriteLine(c2.GetX()); // Afieaz: 10

}
}
Din exemplu vedem c parametrul constructorului de copiere are tipul clasei, iar
argumentul de apel este un obiect (c l) al clasei.

Cuvntul cheie t h i s
this este o referin la obiectul curent. Toate metodele nestatice ale clasei
posed aceast referin i au acces la ea.
Exemplificm utilizarea referinei this n urmtoarele circumstane:
1. Pentru rezolvarea ambiguitilor care apar cnd numele parametrilor
formali ai unei metode coincid cu numele altor membri.
2. Returnarea de ctre o metod a unei referine la obiectul curent.
using System;
class Copil
{
private string n u me;
private int v a r s t a ;

Partea I. Limbajul C#

70

// Parametrii formali au aceleai nume cu ale cmpurilor


public Copil(string nume, int varsta)

{
this.nume = nume;
this.varsta = varsta;

// cazul 1
// cazul 1

}
public Copil ModificVarsta(int varsta)

{
this.varsta = varsta;
return this;

// cazul 1
// cazul 2

}
public void AfiseazaO
{
Console.WriteLine(nume + " " + varsta);

}
}
class Test_this
{
static void Main(string[] args)

{
Copil c = new Copil("Alin",.17);
c .Afiseaza ();
// Ieire: Alin 17
c.ModificVarsta(18);
c.Afiseaza();
// Ieire: Alin 18

}
}
Ce s-ar fi ntmplat dac constructorul clasei s-ar fi definit astfel:
public Copil(string nume, int varsta)

{
nume = nume;
varsta = varsta;

}
Nu este eroare la compilare. Dar parametrul formal nume ascunde cmpul clasei,
astfel nct metoda nu acceseaz cmpul privat al clasei, ci realizeaz o inutil
autoatribuire a parametrului formal. Oricare membru al clasei poate fi accesat n
metodele clasei astfel: this .membru. n acest fel, this.nume = nume;
realizeaz o iniializare corect a cmpului nume.
Mai observm c metoda ModificVarsta () returneaz o referin la
obiectul curent. Cine este de fapt obiectul curent ? Asta nu vom ti, pn n
momentul n care metoda este apelat: c.ModificVarsta (18) ; Prin urmare, c
refer obiectul curent i this refer evident acelai obiect. De altfel, n momentul
apelului, this refer deja obiectul alocat cu new, pentru c c transfer n this
referina ctre obiect.
Exist i alte situaii n care avei nevoie de this, aa cum vom vedea mai
departe.

Capitolul 4.

Programare Orientat pe Obiecte n C#

71

Destructorul clasei
Destructorul clasei este o metod special care distruge instanele claselor.
Dac o clas poate avea mai muli constructori, n schimb nu poate avea dect un
singur destructor. Un destructor se declar astfel:
class Avion
// Membrii clasei
~Avion()
// Destructor
{
// Eliberarea resurselor gestionate de obiect

}
}
n majoritatea covritoare a cazurilor, nu vei avea de implementat un destructor,
deoareace C# are un garbage collector care distruge obiectele nefolositoare n
mod automat. Vei implementa un destructor doar n situaii n care obiectele
gestioneaz resurse care nu sunt controlate de .NET Framework.
Nu vom intra n alte detalii care ies din cadrul propus n aceast lucrare.
Este bine s reinei totui cteva informaii utile n legtur cu destructorii:

IMPORTANT

Destructorii au acelai nume cu cel al clasei, prefixat cu caracterul


O clas poate avea un singur destructor.
Destructorii nu se apeleaz niciodat. Ei se invoc n mod automat.
Constructorii nu au parametri i nu accept modificatori.
n structuri nu se pot defini destructori.
Destructori nu pot fi suprancrcai.

Proprieti
Proprietile reprezint o facilitate important a limbajului C#. Sunt membri
ai clasei care permit accesul direct la starea obiectului. Starea unui obiect este
dat de valorile datelor membre. Cu ajutorul proprietilor vei accesa cmpurile
private, ca i cnd ar fi fost declarate public, fr ca prin aceasta s se ncalce
principiul proteciei datelor, care cere ca datele membre s fie private. n realitate,
proprietile implementeaz nite metode speciale, numite accesori.
Exemplu:
using System;
class Copil

{
p r i v a t e s t r i n g nume;
p r i v a t e int varsta;

// Cmpuri private

Partea I. Limbajul C#

72

public Copil(string n, int v)

// Constructor

{
nume - n ;
varsta = v;

}
public string Nume

// Proprietatea Nume

{
get

{
return nume;

}
set

{
nume = value;

}
}
public int Varsta

// Proprietatea Varsta

{
get

{
return varsta;

}
set

{
varsta = value;

}
}
}
class TestProprietati

{
static void Main(string[] args)

{
Copil c = new Copil("Valentin", 18);
Console.WriteLine(c.Nume + " " + c.Varsta); // get
c.Nume = "Andrei";
// set
c.Varsta = 2 0 ;
// set
Console.WriteLine(c.Nume + " " + c.Varsta); // get

F iecare proprietate returneaz i eventual seteaz i valoarea unui cmp privat. Sa u implementat dou proprieti: Nume i Varsta. Toate proprietile au tip.

Capitolul 4.

Programare Orientat pe Obiecte n C#

73

Prototipul proprietii este format din tipul returnat de ctre proprietate (aici
string, respectiv int) i numele proprietii (Nume i Varsta). Tipul proprietii,

este tipul cmpului pe care l gestioneaz proprietatea.


Corpul proprietii conine doi accesori: get i set. Unul din ei poate s lipseasc.
get are urmtoarele caracteristici:
s Nu are parametri
s Are tip de retur de acelai tip cu al proprietii.
set are urmtoarele caracteristici:

s
s

Are un singur parametru implicit, numit value, de acelai tip cu


proprietatea, value reine valoarea cmpului gestionat de proprietate.
Are tipul de retur void.

Tipul proprietii

Numele proprietii

public string Nume


{
get

get nu are parametri. Retumeaz


o valoare de tipul proprietii

return nume;

set nu are parametri explicii.


Parametrul implicit este value

set

{
nume = value;

}
}
Accesorii pot fi declari n orice ordine. Nici o alt metod n afar de get i set nu
poate exista n corpul proprietii. Accesorii se apeleaz n mod implicit.
Citirea i scrierea ntr-o proprietate se face la fel ca pentru un cmp public:
Expresia c.Nume = "Andrei"; atribuie cmpului privat nume valoarea
"Andrei" n felul urmtor: set se apeleaz n mod implicit, iar parametrul
su implicit value, primete valoarea "Andrei". n corpul metodei, prin
nume = value; are loc atribuirea necesar.
Expresia c.Nume (scris n contextul unei afiri) retumeaz valoarea
proprietii, deci a cmpului nume, astfel: get se apeleaz n mod implicit.
Metoda get returnaz valoarea proprietii, deci a cmpului privat nume.

Proprietile nu ncalc principiul proteciei datelor


Aparent, un cmp declarat p u b lic (o practic descurajat n OOP) se
acceseaz n mod identic cu o proprietate asociat unui cmp privat, iar
proprietatea pare c nu protejeaz cmpul de aciuni nedorite. Nu este de loc aa.
n primul rnd avei libertatea s creai proprieti:
Read-Only, adic proprieti care nu implementeaz metoda get.
Write-Only, adic proprieti care nu implementeaz metoda set.
Nu putei defini o proprietate din care s lipseasc att get ct i set.

Partea I. Limbajul C#

74

n al doilea rnd, metoda set se poate implementa de asemenea manier,


nct cmpul asociat proprietii (backing field) s fie complet protejat de aciuni
nedorite.

Exemplu:
n set putei plasa orice cod defensiv de protecie a cmpului asociat
proprietii:
using System;
class ntreg
{
private int n;
public int N
{
get { return n; }

// Cmp privat

set
{
// Cod care protejeaz n de aciuni nedorite
if (value > 1000) n = 1000;
else
if (value < 0) n = 0;
else n = value;

}
}
}
class Test
{
static void Main(string[] args)

{
ntreg i = new ntreg();
i.N = 1200;
// set
Console.Write(i.N + " "); // get
i.N = -10;
// set
-Console-Write(i.N);
// get

}
}
Ieire: 1000 0

Proprieti statice
Proprietile se pot declara static. Procedai astfel cnd dorii s le
asociai unor cmpuri statice. Proprietile statice nu pot accesa ali membrii ai
clasei, dect pe cei statici i exist independent de existena instanelor clasei. Se
acceseaz prin numele clasei, la fel ca ali membri statici.

Capitolul 4.

Programare Orientat pe Obiecte n C#

75

Exemplu:
class Numr
{
private static int nr;
public static int Nr

// Cmp static
// Proprietate static

{
get { return nr; }
set { nr = value; }

}
}
class TestConst
{
static void Main(string[] args)

{
Numar.Nr = 100;
// set
System.Console.Write(Numar.Nr); // get

}
}

Convenie de notare
Pentru claritate, se obinuiete ca numele proprietii s fie acelai cu cel al
cmpului privat asociat. Diferena este c n timp ce cmpul ncepe cu liter mic,
proprietatea ncepe cu liter mare. Sfatul nostru este s urmai aceast convenie.

Proprieti implementate n mod automat


Aceste tipuri de proprieti, au urmtoarele caracteristici:
Nu se asociaz nici unui cmp al clasei.
Compilatorul aloc memorie pentru valorile furnizate, n funcie de tipul
proprietii.
Accesorii get i set nu au corp.
Nu pot fi read-only (nu poate lipsi get) i nici write-only (nu poate lipsi
set).

Exemplu:
using System;
class X

{
public int Valoare
{
get; set;
1

// Proprietate
// implementat
// n mod automat

Partea I. Limbajul C#

76

class TestAutoPropertie
{
static void Main(string[] args)

{
X x = new X ();
x.Valoare = 1 0 ;
Console.Write(x.Valoare);

// set
// get

}
}
Vei utiliza o proprietate automatic atunci cnd nu avei nevoie s impunei
restricii speciale valorilor sale.

Restriciile proprietilor
Proprietile nu definesc o locaie de memorie. Din acest motiv, nu pot fi
transmise cu modificatorii o u t sau ref.
Nu pot fi suprancrcate.

Indexatori
Indexatorii permit instanelor unei clase sau ale unei structuri s fie indexate,
la fel ca elementele unui tablou. Indexatorii i proprietile sunt similari din mai
multe puncte de vedere:
Sintax asemntoare.
Pot avea unul sau doi accesori.
Nu definesc o locaie de memorie.
Codul accesorilor poate s fie asociat sau s nu fie cu un cmp al
clasei.
Exist i diferene:
O proprietate acceseaz de regul un singur cmp privat, n timp ce
un indexator poate accesa mai muli membrii ai clasei.
Numele unui indexator este ntotdeauna this.
Un indexator este ntotdeauna un membru de instan. Din aceast
cauz nu poate fi declarat static.

Sintax:
TipReturnat this[int index]

{
get

{
/ / S e returneaz valoarea precizat prin index

}
set

{
// Se modific valoarea precizat prin index

}
}
TipReturnat este tipul de baz al indexrii. Parametrul index primete valoarea

indexului elementului care va fi accesat.

Capitolul 4.

Programare Orientat pe Obiecte n C#

77

Exemplu:
using System;
class Tablou

{
private int[] a;
// Tablou coninut - Cmp privat
private int n;
// Dimensiunea tabloului
private const int MAX = 1000;
public Tablou(int dim)

// Constructorul clasei

{
n = dim;
a = new int [n];

}
public int this[int index]

// Indexator

{
get
{

// Returnez a[index] doar dac index este


/ / n intervalul [0, MAX]
if (index < 0)
return a [0];

else
if (index > MAX)
return a[MAX];
else
return a [index];

>
set
{

// Seteaz a[index] doar dac index este


/ / n intervalul [0, MAX]
if (index < 0)
a [0 ] = value;
else
if (index > MAX)
a[MAX] = value;
else
a[index] = value;

}
}
1
;lass Testlndexer

fl
static void Main(string[] args)

{
Tablou t = new Tablou(100);
for (int i = 0; i < 10; i++)
t[i] = i;
// set
t [-1] = 10;
// set

Partea I. Limbajul C#

78

for (int i = 0; i < 10; i++)


Console.Write(t[i] + " ");

// get

Ieire:
10 1 2 3 4 5 6 7 8 9

n exemplul de mai sus se aplic operatorul [] referinei t, accesndu-se n felul


acesta elementele tabloului a, coninut n clas.
Dac o clas conine ca i cmp privat o colecie, iar acea colecie suport
operaia de indexare, atunci putei defini un indexator care v va permite s
accesai elementele coleciei cu ajutorul operatorui [] aplicat referinei la obiectul
de tipul clasei (mai sus, t [ i ] ).

Operatori de conversie
n capitolul 3, paragraful Conversii ntre tipuri, am vzut c ntre tipurile
predefinite se pot face conversii implicite sau explicite. Conversiile explicite se
realizeaz cu ajutorului operatorului ( ).

Exemplu:
double x = 2.3;
int y = 6;
x = y;
// Conversie implicit
y = (double)x; // Converise explicit

C# v permite s definii un tip special de operatori n clase i structuri, care


realizeaz conversii implicite sau explicite ntre tipul clasei sau a structurii i alte
tipuri predefinite sau tipuri class sau struct.
Operatorii de conversie sunt metode statice, introduse cu cuvntul cheie
operator.

Sintax:
public static explicit operator Tipl

(Tip2 t)

{
// Cod care convertete n mod explicit t spre TipulClasei

}
sau
public static implicit operator Tipl[Tip2 t)

{
// Cod care convertete n mod implicit t spre TipulClasei

Capitolul 4.

Programare Orientat pe Obiecte n C#

79

Tipl este tipul spre care se face conversia. Tip2 este tipul care se convertete
spre Tipl. Unul dintre cele'dou tipuri trebuie s fie de tipul clasei sau structurii
care conine operatorul de conversie.

Exemplul 1:
Definim doi operatori care realizeaz conversii explicite de la tipul
Bancnota spre int i de la int spre tipul Bancnota;
// conversii_explicite.cs
using System;
class Bancnota

{
private int valoare;
public Bancnota(int v)

// Constructor

{
valoare = v;

}
// Operator de conversie explicit de la int la Bancnota
public static explicit operator Bancnota(int v)

{
return new Bancnota(v);

}
// Operator de conversie explicit de la Bancnota la int
public static explicit operator int(Bancnota b)

{
return b.valoare;

}
}
class TestConversieExplicita

{
static void Main()

{
int val = 100;
Bancnota b = (Bancnota)val;
Console.WriteLine((int)b);

// Conversie explicit
// Conversie explcit

Partea I. Limbajul C#

80

Exemplul 2:
Modificm programul anterior, astfel nct s obinem operatori de conversii
implicite:
// conversii_iroplicite.cs
using System;
class Bancnota

{
private int valoare;
public Bancnota (int v)

// Constructor

{
valoare = v;

}
// Operator de conversie implicit de la int la Bancnota
public static implicit operator Bancnota(int v)

{
return new Bancnota(v);

}
// Operator de conversie implicit de la Bancnota la int
public static implicit operator int(Bancnota b)

{
return b.valoare;

}
}
class TestConversielmplicita

l
static void Main()

int val = 100;


Bancnota b = val;
Console.WriteLine(b);

// Conversie implicit
// Conversie implicit

}
}
Observai c nu a mai fost necesar utilizarea operatorului ( )
operator.

type cast

Clase interioare
O clas interioar (inner class sau nested class) este o clas a crei definiie
se gsete n interiorul definiiei altei clase.
1.

Pentru a instania un obiect de tipul clasei interioare, nu este nevoie de un


obiect de tipul clasei exterioare:

Capitolul 4.

Programare Orientat pe Obiecte n C#

81

Exemplu:
using System;
class A

// Clasa container

{
public class B // Clasa interioar
{
public void F() { Console.Write("F()"); }

}
}
class TestlnnerClass

{
static void Main()

{
A.B obj = new A.B(); // Creeaz un obiect de tip B
obj.F();
// Afieaz: F();

}
}
2.

Metodele clasei interioare pot accesa toi membrii clasei care o conine, prin
intermediul operatorului ' . ' :

Exemplu:
using System;
public class Exterior

{
private int x ;
public Exterior(int y)

// Constructor

{
x = y;

}
public class Interior

{
public void Scrie(Exterior o)

{
// Acces permis la membrii clasei Exterior
System.Console.WriteLine(o.x);

}
}
}

public class TestlnnerClass


{
static void Main()

Partea I. Limbajul C#

82

{
Exterior ol = new Exterior(100);
// Instanierea unui obiect de tip Interior
Exterior.Interior o2 = new Exterior.Interior();
o 2 .Scrie(ol);
// Afieaz: 100

}
}

Continere
9

Cnd o clas are ca membri unul sau mai multe obiecte de tip clas, vorbim
despre coninere (containment) sau compoziie.
n figur, ilustrm clasa Calculator. Un
Calculator
calculator are mai multe componente. Acestea sunt
instane ale altor clase : Monitor, Tastatura,
Mouse i UnitateCentrala.

IMPORTANT
Tipul de relaie care se modeleaz n cazul continerii
este: HAS A (ARE UN, ARE O).

Exemplu:

Unitate central

Programul de mai jos definete trei clase:


Motor, Caroserie, Maina. Clasa Maina are ca

membri privai cte o referin spre obiecte de tip


Motor i Caroserie.

Figura 4.1

class Motor { /* ... */ }


class Caroserie { /* ... */ }
class Maina

{
private string marca;
// Maina ARE O caroserie c i ARE UN motor m
private Caroserie c;
private Motor m;
// Constructorul clasei
public Maina(Caroserie c, Motor m, string marca)

{
this.c = c;
this.m = m;
this.marca = marca;

}
}

C onin ere

Capitolul 4.

Programare Orientat pe Obiecte n C#

83

class TestContinere

{
public static void Main()

{
Caroserie C = new Caroserie();
Motor M = new Motor();
Maina mea = new Maina(C, M, "Volvo");

}
}

Clase pariale
Definiiile claselor, structurilor i interfeelor se pot mpri n mai multe fiiere
surs. Ca alternativ, putei fragmenta o clas n interiorul aceluiai fiier. Pentru a
separa n blocuri o definiie de clas, utilizai cuvntul cheie parial.

Exemplu:
using System;
partial class A

{
public void F()

{
System.Console.Write ("F() ");

}
}
partial class A

{
public void G()

{
System.Console. WriteLine ("GO ") ;

}
}
public class TastPartialClass

{
static void Main()

{
A a = new A () ;
a.F<) ;

a . G() ;
}
}
Ieirea programului : F () G ()

84

Partea I. Limbajul C#

Practic, este vorba despre o singur clas cu numele A, a crei definiie a fost
fragmentat. Compilatorul unific definiiile pariale i instaniaz n mod corect
obiectul a de tip A.
Mediul Visual C# 2008 genereaz n mod curent asemenea definiii pariale.
Dac creai un proiect de tip Windows Forms, vei constata c definiia de clas a
formei principale, s-i spunem Forml, este fragmentat n dou fiiere diferite:
Form1.cs i Form l.Designer.es.

Clase sigilate
sealed este un cuvnt cheie. Cnd modificatorul sealed este aplicat unei
clase, are efectul de a mpiedica alte clase s o moteneasc.

Exemplu:
se a le d c la s s A { / * . . . * / }
c la s s B : A { / * . . . * /

/ / Eroare

Suprancrcarea operatorilor
Toi operatorii unari i binari au implementri predefinite care sunt
disponibile n orice expresie n care sunt implicate tipuri predefinite. C# v permite
s redefinii semnificaia unui operator standard, astfel nct operatorul respectiv s
poat fi aplicat instanelor clasei voastre. n acest fel sporii funcionalitatea
claselor.
Ce nelegem prin suprancrcarea operatorilor (operator overloading)? Este
un mecanism prin care instanele clasei pot fi integrate n expresii aritmetice sau
logice n calitate de operanzi, cu utilizarea operatorilor specifici tipurilor predefinite:
+,
*, /, <, >, etc. Cnd definii o metod de tip operator, de exemplu pentru
operaia de adunare, atunci spunem c am suprancrcat operatorul +.
S presupunem c avem o clas care descrie o fracie i dorim s efectuam
operaii cu instane de tip F r a c ie , n felul acesta:
F r a c ie f l = new F r a c i e ( ) ;
F r a c ie f2 = new F r a c i e ( ) ;
F r a c ie f = f 1 + f 2;
n C# operatorii suprancrcai sunt metode statice ai crui parametri sunt
operanzii, iar valoarea returnat este rezultatul operaiei.
Sintaxa de declarare a unui operator pretinde folosirea cuvntului cheie
o p e ra to r, urmat de simbolul operatorului care se redefinete.

Capitolul 4.

Programare Orientat pe Obiecte n C#

85

Sintaxa
n cazul operatorilor binari:
public static Tip operator op(Tipl operandl, Tip2 operand2)

{
// operaii

}
n cazul operatorilor unari:
public static Tip operator op(Tip operand)

{
// operaii

}
op este operatorul care se suprancarc: +,

/,
etc.
Pentru operatorii unari, operandul trebuie s fie de acelai tip cu clasa
pentru care suprancrcai operatorul. Pentru operatorii binari, cel puin unul dintre
cei doi operanzi trebuie s fie de tipul clasei. Tip este tipul de retur al operaiei i
de regul este un obiect de tipul clasei.

Suprancrcarea operatorilor binari


n exemplul de mai jos, clasa Fracie, suprancarc operatorii +, ==, !=:
// fractie.cs
using System;
public class Fracie

{
private int numrtor;
private int numitor;
private static int Cmmdc(int a, int b)

{
if (b == 0) return a;
return Cmmdc(b, a % b) ;

}
public Fracie(int numrtor, int numitor) // Constructor

{
int div = Cmmdc(numrtor, numitor);
numrtor /= div; numitor /= div;
this.numrtor = numrtor;
this.numitor = numitor;

}
public static Fracie operator + (Fracie fl, Fracie f2)

{
int A = fl.numrtor * f2.numitor +
f2.numrtor * fl.numitor;

Partea I. Limbajul C#

86

int B = f1.numitor * f2.numitor;


int cmmdc = Cmmdc(A, B) ;
A /= cmmdc;
B /= cmmdc;
return new Fracie(A, B ) ;

}
public static bool operator = (Fracie f1, Fracie f2)

{
if (fl.numitor == f2.numitor &&
fl.numrtor == f2.numrtor)
return true;
return false;

}
public static bool operator !=(Fracie f1, Fracie f2)

{
return !(fl == f2);

}
// Suprascrie Object.ToStringO
public override string ToStringO
{
String s = numrtor.ToString() + "/" +
numi tor. ToStringO ;
return s ;

}
public class TestFractie

{
static void M a i n ()

{
Fracie a = new Fracie(3, 4);
Console.WriteLine("a = {0}", a .ToString());
Fracie b = new Fracie(2, 4);
Console.WriteLine("b = {0}", b .ToString());
Fracie c = a + b; // operatort
Console.WriteLine("c = a + b = {0}",
c.ToStringO);
Fracie d = new Fracie(2, 4);
if (d == b)
// operator==
Console.WriteLine("d = b = {0}", d) ;
if (a != b)
// operator!=
Console.WriteLine(a + " != " + b);
a += b;

// operator +=

Capitolul 4.

Programare Orientat pe Obiecte n C#

87

Console.WriteLine("a = " + a);

}
}
Ieire:
a = 3/4
b = 1/2
c = a + b = 5/4
d = b = 1/2
3/4 != 1/2
a = 5/4

De retinut:

>
>
>
>

>

Operatorul de atribuire = nu se suprancarc. El este furnizat n mod


implicit de ctre compilator (c = a + b).
Operatorii unari au un parametru, iar cei binari doi parametri: n ambele
cazuri, cel puin unul dintre operanzi trebuie s fie de tipul clasei sau al
structurii.
Operatorii unari au un singur parametru.
C# pretinde ca n situaia n care suprancrcai == atunci trebuie s
suprancrcai i !=. Similar, operatorii < i > trebuie suprancrcai n
perechi, la fel ca i <= cu >=.
Dac suprancrcai operatorul +, atunci C# sintetizeaz automat +=.
Aceeai regul este valabil i pentru + cu +=, * cu *=, etc.

Metoda ToString()
n clasa Fracie, am definit metoda ToString(). De fapt, am redefinit
pentru Fracie, aceast funcie. ToStringO este o metod a clasei object,
clasa de baz a tuturor claselor. Rolul ei este de a returna o reprezentare a
obiectului clasei ntr-un obiect de tip string. De cte ori dorii o conversie
particular spre string a obiectelor clasei, redefinii aceast metod motenit.
Pentru aceasta folosii cuvntul cheie override. Observai c metoda
ToStringO se apeleaz n mod implicit atunci cnd transferai obiectul ntr-un
context n care se cere un string: apelul Console .WriteLine ("a = " + a) ;
pune a ntr-un context n care se ateapt un string, deci a se convertete la
string prin apelul implicit al metodei ToString ().

Suprancrcarea operatorilor unari


Pentru exemplificarea suprancrcrii operatorilor unari definim o clas simpl:
using System;
public class ntreg

Partea I. Limbajul C#

88

private int n;
public ntreg(int i)
{
n = i;

// Constructor

}
// Operatorul de incrementare
public static ntreg operator + + (ntreg x)

{
return new ntreg(++x.n);

}
// Operatorul unar public static ntreg operator - (ntreg x)

{
return new ntreg(-x.n);

}
public override string ToStringO
{
String s = string.Format("{0}", n);
return s;

}
}
public class TestOpUnari

{
static void Main()

{
ntreg x = new ntreg(10);
x++;
// Incrementare
Console.WriteLine(x + " " + -x) ; / /

Scrie: 11 -11

}
}

NOT:
Nu este nevoie s creai dou versiuni diferite ale. operatorului ++ ca s
suporte incrementare prefixat i sufixat. O singur versiune este suficient, iar
compilatorul are grij s implementeze diferenierea ntre prefixare i sufixare.

IMPORTANT___________________________________________
Este recomandabil s nu modificai operanzii pasai metodelor operator. In
loc de aceasta, creai noi instane de tipul valorii de retur i returnai aceste
instane. Urmnd aceast practic, vei evita probleme la depanare.

Operatorii care pot fi suprancrcai:


Operatori unari:
++, ,true, false
Operatori binari: +, -, *, /, %, &, | , A, ,

Capitolul 4.

Programare Orientat pe Obiecte n C#

89

Operatori relaionali: = cu !=, < cu >, <= cu >= (acetia trebuie suprancrcai n
perechi).

Aciuni nepermise la suprancrcarea operatorilor:


>
>
>
>

Crearea unui nou operator (se pot suprancrca doar operatori predefinii).
Schimbarea sintaxei unui operator.
Redefinirea modului de lucru a unui operator cu tipuri predefinite.
Schimbarea precedenei sau asociativitii unui operator.

Structuri
Structurile sunt tipuri de date definite de programator, asemntoare
claselor. Se definesc cu ajutorul cuvntului cheie struct.
Structurile sunt asemntoare claselor prin faptul c pot s conin cmpuri,
metode, constructori, proprieti, operatori, tipuri imbricate, indexatori.
Difer de clase n urmtoarele privine:
Structurile sunt tipuri valoare, iar clasele sunt tipuri referin.
Nu suport motenirea.
Nu suport constructori fr parametri.
Nu au destructori.

Sintaxa:
[ModificatorAcces] struct
{
II

NumeStructur

membrii structurii

Exemplu:
using System;
struct Punct

i
private double x;
private double y;
public Punct(double _x, double _y) // Constructor
{
x = _x;

y = _y;
}
public double X

{
get { return x; }

// Proprietatea X

Partea I. Limbajul C#

90

set { x = value; }

>
public double Y

// Proprietatea Y

{
get { return y; }
set { y = value; }

}
}
class TestStruct
{
static void M a i n (string[] args)

{
Punct pi = new Punct(2.3, 3.5);
Console.Write("x = {0}, y = {1}", pl.X, pl.Y);

}
}
Structurile sunt recomandabile pentru obiecte mici, aa cum este un obiect de tip
Punct, care trebuie instaniate n numr mare, eventual ntr-o bucl. Pentru c
sunt tipuri valoare, se construiesc pe stiva programului, care se acceseaz mai
rapid dect memoria Heap.

Interfete
9

O interfa este un tip referin care descrie un set de metode, dar nu le


implementeaz. Clasele i structurile pot implementa interfeele. Cnd o clas
implementeaz o interfa, trebuie s implementeze toate metodele acelei
interfee. n felul acesta, clasa "semneaz un contract, pe care se oblig s-l
respecte.

Sintaxa minimal:
[modificatori] interface Numelnterfat
{
// Corpul interfeei

}
Modificatorii pot fi public, private, protected, internal, protected
internal. Cuvntul cheie interface preced numele interfeei. Este o practic
comun ca numele interfeei s nceap cu litera I. Exemple: icomparable,
ICloneable, IControl, etc.

Implementarea interfeelor de ctre clase


O clas sau o structur poate implementa una sau mai multe interfee, ca
mai jos:

Capitolul 4.

Programare Orientat pe Obiecte n C#

91

interface II { /*...*/ }
interface 12 { /*...*/ }
class C : II, 12
{ /*...*/ }

Exemplu:
using System;
interface IPrintable

{
void Print(string s);

}
public class Mail : IPrintable

{
private string s;
public Mail(string s)

// Constructor

{
this.s = s;

}
// Implementarea metodei interfeei (obligatoriu!)
public void Print(string a)

{
Console.WriteLine(s + a);

1
)
public class TestOpUnari

{
static void Main()

{
Mail m = new M ail("Prietenilor mei ");
m .Print("Salut!");

}
}
Ieire:
Prietenilor mei Salut!

Ceea ce trebuie s reinei despre interfee este:


>
>
>
>
>

O interfa nu se poate instania.


Interfeele nu conin cmpuri, ci doar metode, proprieti, evenimente.
Interfeele nu conin implementri ale metodelor.
Clasele i structurile pot moteni (impelmenta) una sau mai multe interfee.
O interfa poate la rndul ei s moteneasc o alt interfa.

92

Partea I. Limbajul C#

Motenire
Motenirea este unul dintre cele mai importante i mai puternice concepte n
Programarea Orientat pe Obiecte. Motenirea v permite s definii o nou clas
care incorporeaz i extinde o clas existent.
Diagrama de mai jos prezint o ierarhie de clase bazat pe motenire. Un
animal este o fiin, un om este o fiin, un cine este un animal, un brbat este
om, .a.m.d. Vom generaliza cu afirmaia urmtoare:
Motenirea modeleaz relaia IS A (ESTE UN, ESTE O).
Spunem c Om i Animal motenesc clasa Fiina. Ele sunt clase
derivate din clasa Fiina, iar aceasta din urm este clas de baz pentru Om i
Animal. Un obiect de tipul clasei derivate, conine ca subobiect, un obiect de tipul

Figura 4.2

Ie ra rh ie d e clase bazat p e m o ten ire

clasei de baz. Aadar, un obiect de tip Om conine ca subobiect un obiect de tip


Fiina, iar un obiect de tip Femeie, conine un subobiect de tip Om, care la rndul
su include un subobiect de tip Fiina.

Specializare i generalizare
Una dintre cele mai importante relaii ntre obiecte n lumea real este
specializarea, care poate fi descris ca o relaie IS A. Cnd spunem c un cine
esfe un animal, ne gndim de fapt c un cine este un tip specializat de animal.
Cinele este un animal pentru c are toate caracteristicile unui animal, dar
specializeaz aceste caracteristici conform speciei sale. O pisic este un animal,
deci are n comun cu cinele caracteriscticile animalelor (ochi, gur, etc) dar difer
fa de un cine prin caracteristici specifice pisicilor.
Pe de alt parte, tipul Animal, generalizeaz tipurile Pisic i Cine.
Aceste relaii sunt ierarhice. Ele formeaz un arbore. Urcnd n arbore,
generalizm; cobornd, specializm.

Capitolul 4.

Programare Orientat pe Obiecte n C#

93

Motenirea presupune att specializare ct i generalizare. n C#, dubla


relaie de specializare i de generalizare este implementat folosind principiul
motenirii.

Implementarea motenirii
Fie clasa A care motenete clasa B.
motenire:
class B

Operatorul : exprim relaia de

// B - C l a s a d e b a z

{
/ / M e m b rii c l a s e i B

}
class A : B
/ / A - C la s a d e r i v a t
i
/ / M e m b rii c l a s e i A

>
Sintaxa A : B se numete specificaie de clas de baz (base class specification).
Membrii clasei derivate sunt:
> Membrii definii n propria clas.
> Membrii clasei de baz.
Se spune despre o clas c extinde clasa sa de baz, pentru c include membrii
clasei de baz, plus orice caracteristic i funcionalitate suplimentar furnizat de
propria declarare.
Clasa B din figura 4.2 are un cmp i o metod. Clasa A, n dreapta, i
definete proprii membri: un cmp i o metod i n plus motenete clasa B, deci
are un cmp i o metod suplimentare pentru c un obiect de tip A include un
subobiect de tip B.

Clasa A
Metoda 2
Clasa B
Metoda 1
Cmpul 1

Cmpul 2
Clasa B
Metoda 1
Cmpul 1

Figura 4.3. Clasa A motenete clasa B

Partea I. Limbajul C#

94

IMPORTANT______________________________ ____________
n C# toate clasele sunt clase derivate. Oricare clas deriv n mod direct
sau indirect din clasa object. Dac o clas nu specific n mod explicit
derivarea dintr-o alt clas, atunci ea motenete direct clasa object. n felul
acesta, object este baza tuturor ierarhiilor de clase.

Exemplu:
Cele dou declarri ale clasei Avion specific acelai lucru: faptul c Avion
deriv din object:
// Derivare implicit
// din object
class Avion
{
// membrii clasei

// Derivare explicit
// din object
class Avion : object
{
// membrii clasei

Alte cteva aspecte trebuie reinute n legtur cu motenirea n C#:


>

O clas poate moteni o singur alt clas i oricte interfee


n C# o clas poate moteni o singur clas de baz. Acest tip de motenire se
numete motenire singular (single inheritance).
O clas C# poate moteni n schimb, oricte interfee.
Fie clasele A i B i interfeele l , 12, 13. Dac A motenete B i interfeele
l , 12, 13, atunci n lista care specific relaia de motenire, clasa B trebuie s
fie precizat naintea interfeelor:
// Corect

c la s s A : B, I I ,
{
}
>

// Incorect

12, 13

c la s s A : I I ,
{
}

B, 12, 13

C# nu admite motenirea multipl


Motenirea multipl (multiple inheritance) are loc atunci cnd o clas are mai
multe clase de baz. Dintre limbajele importante, doar C++ suport acest tip
de motenire.
// Incorect n C#
class A : B, C, D
{

}
>

nlimea arborelui relaiilor de motenire poate fi orict de mare


Mai jos, A, B, i c sunt clase. Rdcina ierarhiei este object. Din object
deriv D, din D deriv c, din c deriv B, iar din B deriv A:

Capitolul 4.

Programare Orientat pe Obiecte n C#

95

// Corect
class C : D { }
class B : C { }
class A : B { }

Accesarea membrilor motenii


O instan a unei clase motenete toi membrii clasei de baz, cu excepia
constructorilor. Totui accesul la membrii clasei de baz poate fi restricionat, cu
ajutorul modificatorilor de acces. Acetia sunt: public, private, protected,
internal i protected internal Programul urmtor, testeaz modul n care
modificatorii de acces controleaz modul de acces la membrii clasei de baz.
using System;
class Animal
// Clasa de baz
{
private string hrana;
protected int speranta_viata;
public string Hrana

// Cmpuri
// Proprietate

{
set { hrana = value; }
get { return hrana; }

}
protected void SeHraneste()

// Metod

1
Console.WriteLine("Animalul se hrnete");

>
1
class Pisica : Animal

// Pisica - clas derivat

{
private string rasa;
public string Rasa
{
set { rasa = value;
get { return rasa;

}
}

}
public void Toarce()

{
/* Membrii protejai i cei publici ai clasei de baz
pot fi accesai din metodele clasei derivate */

/ / hrana = "lapte";

// Eroare! -cmp privat


speranta_viata = 12; // Corect! -cmp protejat
Hrana = "lapte";
// Corect! -proprietate public
SeHraneste();
// Corect! -metod protejat
Console.WriteLine("Pisica toarce");

}
}

Partea I. Limbajul C#

96

public class TestAccesMembri


{
static void Main()

{
//
//
//

Animal a = new Animal();


a.hrana = "carne";
// Eroare! -cmp privat
a .speranta_viata = 10;
// Eroare! -cmp protejat
a.Hrana = "carne";
// Corect! -proprietate public
a .SeHraneste();
// Eroare! -metod protejat
/*

II

//
II
II

Toi membrii clasei Animal sunt membri ai clasei


Pisica. Membrii private i protected nu pot fi
accesai din exteriorul clasei Pisica */

Pisica p = new Pisica();


p.hrana = "lapte";
p .speranta_viata = 12;
p.Hrana = "lapte";
//
p .SeHraneste();
//
p.rasa = "siameza";
//
p.Rasa = "Siameza";
//
p.Toarce();
//

// Eroare! -cmp privat


// Eroare! -cmp protejat
Corect! -proprietate public
Eroare! -metod protejat
Eroare! -cmp privat
Corect! -proprietate public
Corect! -metod public

Ieire:
Animalul se hrnete
Pisica toarce

Se desprind urmtoarele reguli:


Metodele unei clase au acces la toi membrii declarai n acea clas,
indiferent de nivelul de protecie a membrilor.
Metodele clasei derivate pot accesa membrii publici i pe cei protejai ai
clasei de baz.
Metodele clasei derivate nu pot accesa membrii privai ai clasei de baz.
Din exteriorul clasei derivate i a celei de baz, se pot accesa numai
membrii publici ai clasei de baz. Membrii protejai se comport n acest
caz la fel ca cei privai.
Membrii unei clase marcai cu modificatorii internai, sunt vizibili (accesibili)
pentru toate clasele din acelai fiier sau din acelai assembly.
Membrii unei clase marcai protected internal sunt vizibili tuturor care o motenesc
i n plus, tuturor claselor din acelai assembly.

Capitolul 4.

Programare Orientat pe Obiecte n C#

97

Constructorii claselor derivate


Constructorii clasei de baz nu se motenesc. Constructorul clasei derivate
apeleaz In schimb constructorul bazei, pentru a construi poriunea din obiect
specific bazei.
Exemplu:
using System;
class Baza

{
public Baza()

{
Console.WriteLine("Constructor Baza");

}
}
class Derivat ; Baza

{
public Derivat()

{
Console.WriteLine("Constructor Derivat);

}
}
public class TestConstructor

{
static void. Main()

{
}

Derivat d;
d = new Derivat(); // Apelul constructorului clasei
// derivate

)
Ieire:
Constructor Baza
Constructor Derivat

Exemplul de mai sus pune n eviden faptul c la construirea unei instane a


clasei, constructorul Derivat () execut constructorul clasei Baza naintea
executrii propriului cod. Are loc un apel implicit al constructoului fr parametri
Baza().
Limbajul C# permite i apelul explicit al constructorului bazei. Sintaxa
corespunztoare este:
public Derivat() : base()

{
}

Partea I. Limbajul C#

98

Dac constructorul bazei are parametri, atunci apelul implicit nu poate avea loc.
Constructorul derivat trebuie s invoce n mod explicit constructorul bazei,
furnizndu-i i argumentele corespunztoare:
Exemplu:
using System;
class Baza
{
private int x;
public Baza(int y)

{
x = y;

>
}
class Derivat : Baza
{
private char c;
public Derivat(char a, int b)

: b ase(b)

{
c = a;

}
}
public class TestConstructor
{
static void Main()

{
Derivat d = new Derivat('T', 10);

}
}
Constructorul clasei derivate trebuie s aib suficieni parametri pentru a iniializa
i cmpurile bazei.
Cum se construiete o instan a clasei derivate ?
Cnd se invoc constructorul clasei derivate, ordinea construciei instanei este:
1. Iniializarea membrilor de tip instan a clasei derivate.
2. Apelul constructorului clasei de baz.
3. Executarea corpului constructorui clasei derivate.
n cazul n care lanul ierarhic al motenirii conine mai multe clase, atunci fiecare
constructor i execut mai nti constructorul bazei sale naintea propriului corp.

Capitolul 4.

Programare Orientat pe Obiecte n C#

99

Membrii ascuni
Dac n clasa derivat avei un cmp cu acelai nume cu al unuia din clasa
de baz, sau avei o metod cu aceeai signatur (acelai nume i aceeai list de
parametri formali) cu a uneia din clasa de baz, atunci numele membrilor din clasa
de baz sunt ascunse metodelor clasei derivate. Pentru a accesa membrii ascuni
ai bazei, se ntrebuineaz new n faa membrilor bazei i cuvntul cheie base,
pentru accesarea membrilor ascuni.
Exemplu:
using System;
class Baza

{
public int camp = 10;
public void Metoda()

{
Console.WriteLine("Baza.Metoda() " ) ;

}
}
class Derivat : Baza

{
new public int camp = 20;
new public void Metoda()

{
b as e.Metoda();
Console.WriteLine("Derivat.Metoda() " + base.camp);

}
}
public class TestMembriAscunsi

{
static void Main()

{
Derivat d = new Derivat();
d.Metoda();

}
}
Ieire:
Baza.Metoda()
Derivat.Metoda() 10
Baza.Metoda()

Partea I. Limbajul C#

100

Polimorfism
Polimorfismul este unul dintre conceptele fundamentale ale programrii
orientate pe obiecte. Reprezint caracteristica unei entiti de a se comporta n
moduri diferite, n funcie de context. n particular, este caracteristica unei variabile
referin de a putea referi obiecte de tipuri diferite. C# admite polimorfismul bazat
pe motenire. Acest tip de polimorfism v permite s invocai runtime metode ale
claselor derivate cu ajutorul unei referine la clasa de baz.

Conversia referinelor
i
Dac avei o referin la un obiect al clasei derivate, putei obine o referin
la partea de baz a obiectului, folosind operatorul de conversie () ca mai jos:
class Baza
{
public void Metoda()

{
System.Console.WriteLine("Baza.Metoda()") ;

}
}
class Derivat : Baza
{
public void Metoda() // sau new public void Metoda()

{
System.Console.WriteLine("Derivat.Metoda()");

}
}
public class TestConversieRef
{
static void Main()

{
Derivat d = new Derivat();
d.Metoda();
// Upcast
Baza b = (Baza)d;
b.Metoda () ;

}
}
Ieire:
Derivat.Metoda()
Baza.Metoda()

Capitolul 4.

Programare Orientat pe Obiecte n C#

101

Se constat c referina la
partea de baz a obiectului nu
poate vedea restul obiectului
clasei
derivate,
deoarece
privete printr-o referin b la
clasa de baz. Prin b vei
putea s invocai
numai
Metoda () clasei de baz.
Conversia unei referine a unui
obiect derivat spre o referin
a clasa de baz se numete
upcast.

Metode virtuale
n paragraful anterior am artat c ntr-o clas derivat putei defini o metod
cu acelai prototip cu al unei metode din clasa de baz, dar c o referin la un
obiect de tipul clasei de baz nu poate invoca noua metod definit cu new.
Pentru ca o referin la un obiect al bazei s poat accesa membri ai
obiectelor derivate, altfel spus, pentru a obine polimorfism bazat pe motenire,
este nevoie de urmtoarele:
> Clasa de baz declar acel membru virtual.
> Clasa derivat redefinete acel membru, cu exact aceeai semntur i tip
de retur, adugnd cuvntul cheie override, naintea tipului de retur.
Exemplu:
using System;
namespace Polimorfism
{
class Baza
{
virtual public void Metoda()

{
Console.WriteLine("Metoda() din Baza");

}
1
class Derivat : Baza
{
override public void Metoda()

{
Console.WriteLine("Metoda() din Derivat");

}
}
class TestPolimorfism
{
static void Main(string[} args)

Partea I. Limbajul C#

102

{
Derivat d = new Derivat();
d.Metoda();
// Ieire: "Metoda() din Derivat"
// Polimorfism
Baza b = new Baza();
b.MetodaQ;
// Ieire: "Metoda() din Baza"
b = new Derivat();
b.Metoda();
// Ieire: "MetodaO din Derivat"

>
}
}
Primul apel b.Metoda ( ) ; invoc metoda din clasa de baz, deoarece tipul
referinei este Baza i tipul obiectului referit este Baza. Al doilea apel invoc
metoda redefinit n clasa derivat. Referina b este n continuare de tip Baza, dar
tipul obiectul referit este de tipul clasei derivate. Acesta este manifestarea
polimorfismului bazat pe motenire.
n cazul unui lan de derivare care pornete de la o clas de baz cu metode
virtuale, n clasele derivate avei opiunea de a redefini sau nu acele metode.
Exemplu:
using System;
class A
{
virtual public void F()
{ Console.WriteLine("F() din A"); }

}
class B : A { }
class C : B

// B nu redefinete F()

{
override public void F()
{ Console.WriteLine(" F () din C"); }

}
class D : C { }

// D nu redefinete F()

class Test

{
static void Main(string[] args)

{
A a = new B ();
a F () ;
a = new C() ;
a .F () ;
a = new D() ;
a .F () ;

}
}

//
//
//
//
//
//

a refer un obiect de tip B


Ieire: MF() din A"
a refer un obiect de tip C
Ieire: "F() din C"
a refer un obiect de tip D
Ieire: ,fF() din C"

Capitolul 4.

Programare Orientat pe Obiecte n C#

103

Dac o referin de tipul clasei de baz refer un obiect de tip derivat i prin acea
-eferin invocai o metod virtual, atunci se apeleaz cea mai apropiat metod
override definit pe lanul ierarhic. Dac nu exist metode redefinite, atunci se
invoc metoda virtual din clasa de baz.

Restricii
j

Reinem urmtoarele aspecte:


Se pot declara virtual urmtorii membri: metode, proprieti,
evenimente i indexatori.
Cmpurile nu pot fi declarate virtual.
Metodele redefinite cu override trebuie s aib acelai nivel de
accesibiliate cu metodele virtuale corespunztoare. De exemplu nu este
corect ca o metod virtual declarat public s fie redefinit cu o
metod declarat private.
Nu se pot redefini metodele non-virtuale.
Nu pot fi redefini metodele statice.

Modificatorul

s e a le d

Aplicat unei clase, modificatorul sealed mpiedic alte clase s o


moteneasc, sealed poate fi aplicat i unei metode sau unei proprieti care
redefinete o metod sau o proprietate a clasei de baz. n aceast situaie, se
permite altor clase s moteneasc clasa care are un membru sealed, dar
metoda sau proprietatea sealed nu mai poate fi redefinit n clasele derivate.

Exemplu:
class A

{
protected virtual void F() { /*...*/ }
protected virtual void G{) { /*...*/ }

}
class B
{

: A

sealed protected override void F() { /*...*/ }


protected override void G() { /*...*/ }

}
class D : B
// Corect. B poate fi motenit
{
protected override void F() { /*...*/ } // Eroare !
protected override void G() { /*...*/ } // Corect

}
Cnd se aplic unei metode sau unei proprieti, modificatorul sealed trebuie s
fie folosit ntotdeauna cu override.

Partea I. Limbajul C#

104

Utilitatea polimorfismului
n practic se opereaz deseori cu colecii de obiecte. Mai precis, cu colecii
de referine la obiecte. Dac obiectele sunt legate printr-o relaie de motenire
avnd o clas de baz comun, atunci nu trebuie ca ele s fie de acelai tip. Dac
toate obiectele redefinesc o metod virtual a clasei de baz, atunci putei invoca
aceast metod pentru fiecare obiect.
using System;
class LimbaVorbita

// Clasa de baz

{
virtual public void SeVorbeste()

{ } // nu va fi invocat

}
class Engleza : LimbaVorbita

{
override public void SeVorbesteO
{ Console.WriteLine("Engleza") ; }

}
class Franceza : LimbaVorbita

{
override public void SeVorbesteO
{ Console.WriteLine ("Franceza"); }

}
class Spaniola : LimbaVorbita

{
override public void SeVorbesteO
{ Console.WriteLine("Spaniola") ; }

}
class Catalana : Spaniola

{
override public void SeVorbesteO
{ Console.WriteLine("Catalana") ; }

}
class Test

{
static void Main(string[] args)

{
LimbaVorbita[] L = new LimbaVorbita[4];
L [0] = new Engleza(); L[l] = new Franceza();
L [2] = new Spaniola(); L[3] = new Catalana();
foreach (LimbaVorbita lv in L)
lv.SeVorbeste();

}
}
Ieire:
Engleza
Franceza
Spaniola
Catalana

Capitolul 4.

Programare Orientat pe Obiecte n C#

105

Tabloul LimbaVorbita reine referine ale unor obiecte de tipuri diferite, dar care
sunt legate prin relaie de motenire, avnd ca baz a ierarhiei clasa
LimbaVorbita. Dac relaia de motenire nu ar exista, atunci referinele ar fi
trebuit s fie de acelai tip. Programul implementeaz polimorfismul. Interfaa de
apelare unic ( lv. SeVorbeste () ) care se utilizeaz pentru fiecare obiect, duce
la aciuni specifice, n funcie de obiectul referit.

Rezumatul capitolului

Clasele sunt entiti logice care modeleaz obiecte din lumea real sau
obiecte abstracte. Clasele ncapsuleaz date i metode care opereaz cu
aceste date.
Constructorii unei clase sunt metode speciale care au rolul de a creea, a
construi obiecte.
Destructorul clasei este o metod special care distruge instanele
claselor.
Proprietile sunt membri ai clasei cu ajutorul crora se acceseaz
cmpurile private ca i cnd ar fi fost declarate public, fr ca prin aceasta
s se ncalce principiul proteciei datelor.
Suprancrcarea operatorilor este mecanismul prin care instanele clasei
pot fi integrate n expresii aritmetice sau logice n calitate de operanzi, cu
utilizarea operatorilor specifici tipurilor predefinite:
<, >, etc.
Motenirea este mecanismul care permite s s se defineasc o nou
clas care incorporeaz i extinde o clas existent.
Polimorfismul este caracteristica unei variabile referin de a putea referi
obiecte de tipuri diferite. C# admite polimorfism bazat pe relaia de
motenire.

ntrebri i exerciii
1.

Care este diferena dintre un obiect i o clas ? Dar dintre o referin i un


obiect ?
2. Indicai principalele deosebiri care exist ntre membrii statici i cei nestatici
ai unei clase.
3. Ce relaie se modeleaz la motenire ? Dar la coninere ?
4. Implementai o clas cu numele Persoana i o a doua clas cu numele
Elev. Clasele trebuie s aib constructori, cmpuri private i proprieti.
5. Scriei o clas cu numele BigNumber care implementeaz operaii cu
numere mari. Suprancrcai cel puin operatorii de adunare, scdere i
nmulire.

Partea I. Limbajul C#

106

Capitolul 5

Trsturi eseniale ale limbajului C#


Acest capitol prezint delegrile, evenimentele, genericele, coleciile,
mecanismul de tratare a excepiilor n C#, un subcapitol dedicat manevrrii
stringurilor i un paragraf care se ocup de operaiide intrare i ieire cu
fiiere text.

Delegri
O delegare este un tip referin, utilizat s ncapsuleze o list ordonat de
metode cu aceeai semntur i acelai tip de retur. Lista de metode se numete
lista de invocare. Cnd un delegat este invocat, el apeleaz toate metodele din
lista de invocare. O delegare cu o singur metod n lista sa este similar cu un
pointer la funcii n C++, ns o delegare este un tip referin i ofer sigurana
tipurilor (type-safe). Capacitatea unei delegri de a invoca mai multe metode se
numete multicasting.

Declarare
O delegare este un tip, aa cum i clasele sunt tipuri. Un tip delegare
trebuie declarat nainte de crearea obiectelor de tipul su. Declararea este creat
cu cuvntul cheie delegate, urmat de tipul de retur i de signatura metodelor pe
care delegarea le accept.

Exemplu:
delegate void DelegareaMea(int x ) ;

Expresia declar tipul delegat DelegareaMea. Obiectele de tipul acesta vor


accepta numai metode cu un singur parametru de tip int i cu tipul de retur void.
Tipurile delegat nu au corp.

Crearea obiectelor delegare


O delegare este un tip referin. Un asemenea tip, conine referina spre
obiect, i obiectul propriuzis.

Referinele (aici, referina se numete d) se declar simplu:


DelegareaMea d;

Obiectele de tip delegare se creeaz n dou moduri:


1.

Cu sintaxa specific instanierii obiectelor:

Capitolul 5.

Trsturi eseniale ale limbajului C#

107

d = new DelegareaMea{ReferinOblect.Metod);

sau
d = new DelegareaMea(NumeClas .MetodStatic) ;

Este important de reinut c delegrile pot ncapsula att metode de


instan ct i metode statice.
Cu sintaxa simplificat, care necesit doar precizarea metodelor ataate
delegrii:

2.

d = ReferinObiect.Metod;

sau
d = NumeClas.MetodStatic;

Invocarea metodelor ataate unei delagri


Prezentm un exemplu care declar un tip delegat i o referin la cest tip.
Apoi ataeaz delegrii cateva metode i n cel din urm le invoc.
using System;
class Simplu

{
// Metod de instan care potrivete delegrii
public void F (string s)

{
Console.WriteLine(s + "F() ") ;

1
// Metod static care potrivete delegrii
public static void G (string s)

{
Console.WriteLine(s + "G() ") ;

}
}
// Declar tipul delegat Del
delegate void D e l (string s) ;
class Program

1
static void Main()

{
Del d;
// Declar o referina de tip Del
Simplu s = new Simplu();
// Acum atam metode delegrii d
d = s.F;
// Lista de invocare: F()
d += Simplu.G;
// Lista de invocare: F(), G()
d += Simplu.G;
// Lista de invocare: F(), G(), G()

Partea I. Limbajul C#

108

// Delegarea d invoc acum toate metodele din list


d("Prima invocare: ");
d -= s.F;
// Lista de invocare: G ()
d ("A doua invocare: ") ;

}
}
Ieire:
Prima invocare: F()
Prima invocare: G ()
Prima invocare: G ()
A doua invocare: G()
A doua invocare: G()

Exemplul anterior descrie modul n care putei atribui o metod listei de invocare a
delegrii, cu operatorul de atribuire =, apoi putei aduga sau elimina alte metode
cu acelai prototip cu operatorii += sau -=.

Invocarea delegrilor cu tipuri de retur


Dac o delegare are o valoare de retur i mai mult de o metod n lista de
invocare, atunci valoarea care se returneaz n urma invocrii delegrii este
valoarea returnat de ultima metod din lista de invocare. Valorile de retur ale
tuturor celorlalte metode din list sunt ignorate.
Exemplu:
using System;
// Declar tipul delegat DelTest
delegate int DelTest();
class Test
{
private int x = 0;
// Metode cu acelai prototip cu al delegrii
public int F()

{
x += 2;
return x;

}
public int G()

{
x += 6;
return x;

}
}
class Program
{

Capitolul 5.

Trsturi eseniale ale limbajului C#

109

static void Main()

{
Test s = new TestQ ;
DelTest d;
// Referin la tipul delegat
// Atam metode delegrii d
d = s.F;
// Lista de invocare: F()
d += s.G;
// Lista de invocare: F(), G()
d += s.F;
// Lista de invocare: F(), G(), F()
Console.WriteLine(d()); // Afieaz: 10

}
}

Evenimente
Aplicaiile cu interfa grafic cu utilizatorul sunt sensibile la evenimente ca:
click cu mouse-ul pe suprafaa unei ferestre, apsarea unei taste, deplasarea
mouse-ului deasupra unui control, etc. Sistemul de operare ntiineaz fereastra
activ despre apariia unei aciuni, iar programatorul poate decide dac va trata
acest eveniment. Evenimentele pot avea o mare diversitate i nu sunt ntotdeauna
cauzate de o aciune direct a utilizatorului aplicaiei; de exemplu curgerea unui
interval de timp, terminarea copierii unor fiiere, primirea unui mail.
Evenimentele C# permit unei clase sau un obiect s notifice, s ntiineze
alte clase sau obiecte c ceva s-a ntmplat.
n terminologia specific, clasa care semnaleaz evenimentul se numete
publisher, iar clasele care sunt informate despre faptul c a avut ioc evenimentul
se numesc subscribers. Clasele care subscriu evenimentului (clasele subscriber)
definesc metode pentru tratarea acestui eveniment (event handler-e).
Exist o mare asemnare ntre delegri i evenimente.
Un eveniment este un membru public al clasei care public evenimentul.
Atunci cnd are loc o aciune, acest membru al clasei publisher se activeaz,
invocnd toate metodele care au subscris evenimentului. Activarea se numete
declanare (firing the event).

Lucrul cu evenimente
Pentru utilizarea evenimentelor, programatorul trebuie s scrie cod dup cum
urmeaz:
1. Declar un tip delegat. Aceast declarare poate avea loc n clasa
publisher sau n afara oricrei clase, pentru c este o declarare de tip.
Evenimentul i handler-e le de evenimente trebuie s aib o semntur i
un tip de retur identice.

no

Partea I. Limbajul C#
2.

Declar evenimentul. Evenimentul se declar ca membru public n clasa


publisher, cu ajutorul cuvntului cheie event,. El depoziteaz i invoc
lista de handler-e.
3. Scrie cod care declaneaz evenimentul. Codul se scrie n clasa
publisher. Apelarea evenimentului duce la invocarea tuturor metodelor
handier nregistrate cu acest eveniment.
4. Declar event handler-e\e. Se declar n clasele subscriber i sunt
metode (event handler-e) care se execut cnd evenimentul se
declaneaz.
5. nregistrareaz
handler-ele.
Aceasta
presupune
conectarea
evenimentului la metodele handler. Codul se scrie n clasele subscriber
sau n alte clase, dar nu n publisher.
Este important de reinut c prin mecanismul de semnalare i de tratare a
evenimentelor, se realizeaz o decuplare a obiectelor de tip publisher de obiectele
de tip subscriber. Clasa publisher nu tie nimic despre obiectele sau clasele
subscriber care vor fi notificate.
Programul care urmeaz, declar tipul delegat Timp. Metodele handler
trebuie s potriveasc acestui tip, adic s nu aib parametri formali i tipul de
retur s fie void. Clasa Publisher (evident, poate fi oricare alt nume), declar
evenimentul ca i cmp public cu numele eveniment, de tipul Timp. Metoda
Declaneaz () declaneaz evenimentul prin apelul eveniment (). De fapt,
evenimentul ca atare este trecerea a 3 secunde, iar eveniment () declaneaz
apelul metodelor handler din lista de invocare a evenimentului. Programul declar
dou clase subscriber, A i b , care definesc cte o metod de tratare a
evenimentului care se semnaleaz n clasa Subscriber. nregistrarea handlerelor are loc n Main (), dar s-ar fi putut face i n metode ale claselor subscriber.
// event.cs
using System;
public delegate void Timp(); // Declararea tipului delegat
// Publisher nu tie nimic despre obiectele pe care le va
// notifica sau despre metodele inregistrate evenimentului
public class Publisher
{
public event Timp eveniment; // Declararea evenimentului
public void Declaneaz()

{
while

(true)

{
// Execuia programului se ntrerupe 3 secunde
System.Threading.Thread.Sleep(3000);
/ / N e asigurm c exist metode nregistrate
if (eveniment != nuli)
eveniment(); // Declaneaz evenimentul

Capitolul 5.

Trsturi eseniale ale limbajului C#

111

// o dat la trei secunde

}
/ Clase Subscr i b e r
class A

{
public void HandlerAQ

{
Console.WriteLine("Obiect A, notificat la {0}",
DateTime.Now.) ;

}
}
class B

{
public void HandlerBQ

{
Console.WriteLine("Obiect B, notificat la {0}",
DateTime.Now);

}
}
class Test

{
static void Main()

{
Publisher p = new Publisher!);
// Obiectele a si b vor fi notificate la declanarea
// unui eveniment

A a = new A ();
B b = new B ();
// Clasele A i B subscriu acestui eveniment
p.eveniment += a.HandlerA; // nregistrarea metodelor
p.eveniment += b.HandlerB; // handler
// Apeleaz metoda care declaneaz evenimentul
p.Declaneaz ();

1
1
Programul afieaz la fiecare trei secunde, cte dou linii:
Obiect
Obiect
Obiect
Obiect

A,
B,
A,
B,

notificat
notificat
notificat
notificat

la
la
la
la

12.06.2008
12.06.2008
12.06.2008
12.06.2008

10:13:22
10:13:22
10:13:25
10:13:25

112

Partea I. Limbajul C#

Pentru determinarea datei i a orei curente, se utiiizeat proprietatea Now, a clasei


System.DateTime.

IMPORTANT___________________________________________
nregistrarea metodelor ataate unui eveniment se face cu operatorul +=,
iar ndeprtarea lor din lista de invocare, se face cu -=.

Publicarea evenimentelor n mod specific .NET


Tratarea evenimentelor presupune existena unui tip delegat. Acesta poate fi
creat de dumneavoastr, ns o mai bun alternativ este folosirea tipului delegat
predefinit al platformei .NET.

Cnd evenimentul nu transmite date handler-elor


public
delegate void EventHandler(object sender, EventArgs e);
sender este o referin ia obiectul (de tip publisher) care declaneaz
evenimentul, iar e este o referin la un obiect de tip EventArgs. Declararea de
mai sus nu trebuie fcut n program, pentru c o face platforma .NET. Ceea ce
avei de fcut n programul events.cs, este s tergei linia care declar tipul
delegat Timp i s v declarai un eveniment n clasa Publisher, astfel:
public event EventHandler eveniment;

Handler-ele trebuie s aib desigur, aceeai semntur i tip de retur, cu a tipului


EventHandler:
public void HandlerA(object sender, EventArgs e)

i
public void HandlerB(object sender, EventArgs e)

O ultim modificare pe care o facei, este nlocuirea apelului eveniment!) ; cu


apelul eveniment (this , new EventArgs ());

Cnd evenimentul transmite date handler-elor


Obiectul de tip EventArgs nu conine n realitate date utile i este folosit
atunci cnd un eveniment nu transmite date de stare unui event handler. Dac
dorii s transmitei handler-elor informaii suplimentare despre eveniment, putei
crea o clas, de exemplu MyEventArgs, care menine aceste informaii. Aceast
clas trebuie s fie derivat (s moteneasc) clasa EventHandler, aa cum se
vede n programul care urmeaz. n aceast situaie, vei crea un tip delegat cu o
semntur compatibil .NET. Vom rescrie programul anterior. Tipul delegat se va
declara ca mai jos:

Capitolul 5.

Trsturi eseniale ale limbajului C#

113

public delegate void Timp(object sender, MyEventArgs ev);


sender este o referin la object, deci poate referi obiecte de orice tip, inclusiv
Publisher. n apelul eveniment (this, ev) ; argumentele sunt: referina this
la obiectul de tip Publisher i referina ev la un obiect de tip MyEventArgs.
using System;
public class MyEventArgs : EventArgs

1
private DateTime momentul;
public DateTime Momentul

// Cmp
// Proprietate

1
set

{
momentul = value;

}
get

{
return this.momentul;

}
}
)
// Declar tipul delegat cu prototipul cerut de .Net
public delegate void Timp(object sender, MyEventArgs ev);
public class Publisher

{
public event Timp eveniment;

// Declar evenimentul

public void Declaneaz()

{
while

(true)

{
// Execuia programului se ntrerupe 3 secunde
System.Threading.Thread.Sleep(3000);
// Ne asigurm ca exist
if (eveniment != null)
{
// metode nregistrate
MyEventArgs ev = new MyEventArgs();
e v .Momentul = DateTime.Now;
// Declaneaz invocarea handler-elor
eveniment(this, ev);

}
}
}
}
// Clase Subscriber

Partea I. Limbajul C#

114

class A
{
public void HandlerA(object sender, MyEventArgs e)

{
Console.WriteLine("Obiect A, notificat la {0}",
e .Momentul) ;

}
}
class B
{
public void HandlerB(object sender, MyEventArgs e)

{
Console.WriteLine("Obiect B, notificat la {0}",
e .Momentul);

}
}
class Test
{
static void Main()

{
Publisher m = new Publisher ();
A a = new A(); // Obiectele a si b vor fi notificate
B b = new B(); // la apariia evenimentului
// nregistrarea metodelor handler

m .eveniment += a .HandlerA;
m.eveniment += b.HandlerB;
m.Declaneaz();

}
}
Ieirea programului este identic cu cea a programului anterior.

De retinut:
j

Dac vrei s scriei cod eficient, vei trata evenimentele folosind clasele de
baz EventHandler i EventArgs, iar delegrile vor avea prototipul compatibil
.NET, chiar dac C# admite orice model delegat.

Generice
Programarea Generic sau programarea cu abloane este un stil de
programare diferit de Programarea Orientat pe Obiecte. Au n comun
abstractizarea datelor i reutilizarea codului, dar abordrile sunt diferite. n timp ce

Capitolul 5.

Trsturi eseniale ale limbajului C#

115

OOP ncapsuleaz n acelai obiect date care reflect starea obiectului, mpreun
cu metode care descriu capabilitile lui, scopul programrii generice este scrierea
de cod care s fie independent de tipurile de date.

Clase generice
S presupunem c ai definit o clas stiva ca mai jos:
public class Stiva

{
private int[] a;
private int re
public Stiva(int max)
{ a = new i n t [max]; }
public void Push(int val)
{ a[n++] = val; }
public int Pop()
{ return a [ n ]; }

1
Acesta stiv memoreaz n cmpul a de tip tablou de int, un numr de valori
ntregi. Dac dorii s depozitai valori de tip double, string sau oricare alt tip,
suntei nevoii s rescriei codul, nlocuind tipul int cu noul tip. C# v ofer
posibilitatea s scriei doar o singur definiie de clas, care s lucreze cu toate
tipurile dorite. Vei scrie o clas generic.
Clasele generice sunt tipuri parametrizate. Clasa generic se va numi
Stiva<T> i se va rescrie astfel:
// stiva_generic.cs
using System;
public class Stiva<T>

{
private T[] a;
private int n;
public Stiva(int max)
{ a = new T [max]; }
public void Push(T val)
{ a[n++] = val; }
public T Pop()
{ return a[--n]; }

// Constructor

Partea I. Limbajul C#

116

public class TestGeneric

{
static void Main()

{
// Se creeaz o stiv de int
(T = int)
Stiva<int> sl = new Stiva<int>(100);
s l .Push(2);
s l .Push(4);
s l .Push(6);
Console .WriteLine (sl.Pop () + " " + sl.PopO +
sl.PopO ) ;
// Se creeaz o stiv de string (T = string)
Stiva<string> s2 = new Stiva<string>(50);
s 2 .Push("Marcel");
s 2 .Push("Ionel");
s 2 .Push("Alin");
Console.WriteLine(s2.Pop() + " " + s2.Pop() +
s2.Pop ()) ;

II

II

If

II

1
}
Ieire:
6 4 2
Alin Ionel Marcel

Numele clasei generice este Stiva<T>. De fapt, nu este o clas real, ci


este un ablon de clas. Pe baza ablonului de clas se vor genera clase reale,
pentru valori particulare ale parametrului T.
Parametrul ablonului este T. Se numete parametru tip sau parametru
generic.
Expresia Stiva<int> sl = new Stiva<int> (100) ; creeaz pe
baza ablonului stiva<T> o clas cu numele stiva<int>, apoi instaniaz un
obiect de acest tip, deci o stiv de ntregi.
Argumentele cu care se nlocuiesc parametrii tip se numesc argumente
tip. Mai sus, T este parametru tip, iar int este argumentul tip.
O clas poate avea mai muli parametri generici. Programul urmtor declar
o clasa generic (nu uitai, o clas generic este un ablon de clas), cu doi
parametri tip, TI i T2:
using System;
public class A<T1, T2>

{
private TI a;
private T2 b;
public A(TI a, T2 b)

{
this.a = a;
this.b = b;

// Constructor

Capitolul 5.

Trsturi eseniale ale limbajului C#

117

public void Print()

{
Console.WriteLine ( a + " " + b) ;

}
public class TestGeneric

1
static void Main()

1
A<string, int> ml = new A<string, int>("Alin", 18);
m l .Print();
A<string, string> m2 = new A<string, string>("UNU",
"DOI");
m2 .Print () ;
A<double, char> m3 = new A<double, char>(2.3, 'F');
m3.Print();

)
}
ieire:
Alin 18
1 2
2.3 F

Expresia A<string, int> ml = new A<string, int> ("Alin", 18);


genereaz pe baza ablonului a < t i , T2> o clas cu numele A<string, int>,
apoi instaniaz un obiect ml de acest tip. Similar se genereaz i celelalte clase,
respectiv obiecte. n felul acesta, metoda Print() a primit o funcionalitate
extins.

Metode generice
Toate metodele unei clase generice sunt la rndul lor generice, deoarece pot
utiliza parametrii generici ai clasei. n afara genericitii implicite, putei defini
metode cu proprii parametri generici, care nu depind de cei ai clasei.

Exemplu:
using System;
public class C<U>

{
private U u;
public C(U u)
{

// Constructor generic

Partea I. Limbajul C#

118

this.u = u;

}
// Metoda generic - are proprii parametri generici
public void F<V1, V2>(V1 a, V2 b)

{
Console.WriteLine(a.ToString() + " " + u .ToString() +
" " + b .ToString());

}
}
public class TestMetodaGenerica
{
static void Main()

{
C<int> cl = new C<int>(104);
// U = int
cl,F<string, string>(Sa traiti", "ani!");
C<char> c2 = new C<char>('F ');
c2.F<string, int>("Iulia", 8);

// U = char

}
}
Ieire:
S traiti 104 ani!
Iulia F 8

Expresia C<int> cl = new c<int>(104) ; genereaz clasa C<int> pe baza


ablonului de clas c<T>.
Expresia cl.F<string, string>("Sa traiti", "ani!"); genereaz
metoda F<string, string>() pe baza ablonului de metod F < v i, v 2 > ( v l
a, V2 b) , apoi apeleaz metoda cu dou argumente de tip string. Metodele cu
proprii parametri generici i sporesc funcionalitatea n raport cu celelalate metode
ale unei clase ablon.

Avantajele programrii generice


Acest model de programare permite implementarea algoritmilor generici.
Pentru asemenea algoritmi, datele se manipuleaz n acelai fel ca n cazul
algorimilor non-generici, n timp ce tipurile de date utilizate pot s fie schimbate de
ctre programator dup necesiti. Genericele se remarc prin calitatea i elegana
codului, sintaxa uor de neles. Codul se poate reduce semnificativ ca volum
atunci cnd avei sarcini de programare cu cod repetabil.
Folosirea tipurilor generice este recomandat de asemenea pentru sigurana
tipurilor care se creeaz (corectitudinea tipurilor se verific n timpul compilrii),
pentru performana n timpul rulrii i nu n ultimul rnd pentru creterea
productivitii n programare.

Capitolul 5.

Trsturi eseniale ale limbajului C#

119

Colecii
!
Platforma .Net conine clase specializate pentru depozitarea datelor.
Aceste clase implementeaz stive, cozi, liste, tabele de dispersie (hash-tables).
Coleciile non-generice sunt definite n spaiul de nume System. Collections.
Coleciile generice se definesc n System.Collections .Generic,
Cele dou tipuri de colecii implementeaz aproximativ aceleai tipuri de
structuri de date, ns cele generice sunt mai performante i furnizeaz o mai mare
siguran a tipurilor. Prezentm modul de utilizare a ctorva containere generice.

Clasa generic s ta ck < T >


stack<T> este o colecie de instane de acelai tip T, care implementeaz
operaii specifice unei stive (LIFO). Managementul memoriei se face automat.
Exemplu:
using System;
using System.Collections.Generic;
class StivaGenerica

i
public static void Main()

{
// Declar o stiv vid cu elemente de tip string
Stack<string> st = new Stack<string>();
// Adaug cteva elemente n stiv
st.Push("UNU"); st.Push("DOI");
s t .Push("TREI"); s t .Push("PATRU");
Console.WriteLine("Nr. de elemente:

{0}", st.Count);

foreach (string s in st)


// Se parcurge stiva
Console.WriteLine(s);
// P o p () scoate elementul din vrful stivei
Console .WriteLine ("Scoate '{0}'", st.PopO);
// Peek() returneaz elementul din vrful stivei
// fr s-l scoat din stiv
Console.WriteLine("Vrful stivei: {0}", st.Peek());
st.Clear(); // terge toate elementele

}
}
Ieire:
N r . de elemente: 4
PATRU
TREI

Partea I. Limbajul C#

120

DOI
UNU
Scoate 'PATRU'
Vrful stivei: 3

Clasa generic List<T>


Clasa reprezint o list de obiecte care poate fi accesat prin index.
Implementeaz metode pentru cutarea, sortarea i manipularea obiectelor. Este
echivalentul clasei non-generice ArrayList, dar mai performant dect aceasta.
Exemplu:
using System;
using System.Collections.Generic;
public class ListaGenerica

{
public static void Main()

t
// Creeaz lista copii cu elemente de tip string
List<string> copii = new List<string>();
// Adaug elemente n list
copii.A d d ("Ionel"); copii.Add("Radu");
copii.Add("Viorel"); copii.Add("Adisor");
copii.A d d ("Nelutu");
// Parcurge colecia
foreach (string c in copii)
Console.Write(c + " " );
Console.WriteLine("\nNr. copii: {0}", copii.Count);
// Contains() returneaz true dac un element exist
Console.WriteLine("Viorel exista ? {0}\n",
copii.Contains("Viorel"));
Console.WriteLine("Insereaz \"Alin\" " +
"pe poziia 2:");
copii.Insert(2, "Alin");
foreach (string c in copii)
Console.Write(c + " ");
Console.WriteLine("\ncopii[3] = {0}", copii[3]);
Console.WriteLine("\nSorteaza alfabetic: ");
copii.Sort();
for (int i = 0; i < copii.Count; i++ )
Console.Write(copii[i] + " ");

Capitolul 5.

Trsturi eseniale ale limbajului C#

121

Console.WriteLine("\n\nSterge \"Nelutu\":");
copii.Remove("Nelutu");
freach (string c in copii)
Console.Write(c + " ");
Console.WriteLine("\n\nSterge lista de copii:");
copii.Clear ();
Console.WriteLine("Nr. copii: {0}", copii.Count);

ieire:
Ionel Radu Viorel Adisor Nelutu
N r . copii: 5
Viorel exista ? true
Insereaz "Alin" pe poziia 2:
Ionel Radul Alin Viorel Adisor Nelutu
copii[3] = Viorel
Sorteazs alfabetic:
Adisor Alin Ionel Nelutu Radu Viorel
terge "Nelutu":
Adisor Alin Ionel Radu Viorel
terge lista de copii:
N r . de copi: 0

Clasa generic D ic tio n a ry C T k e y , T v a lu e >


Clasa este echivalentul clasei map din STL, C++. Realizeaz o mapare, o
coresponden biunivoc ntre o mulime de chei i o mulime de valori. Cheile sunt
unice, n sensul c nu pot exista mai multe chei identice n dicionar. Fiecrei chei i
corespunde o singur valoare asociat.
Clasa ofer metode care implementeaz operaii rapide de inserare a
perechilor cheie-valoare, de tergere i de cutare a valorii dup cheia asociat. n
dicionar, perechile cheie-valoare sunt ncapsulate n obiecte de tip
KeyValuePair.

Exemplu:
using System;
using System.Collections.Generic;

Partea I. Limbajul C#

122

public class AgendaTelefonica

{
public static void Main()

{
// Un dicionar cu cheia string i valoarea int
Dictionary<string, int> T =
new Dictionary<string, int>();
// Adaug elemente in dicionar.
T.A d d ("Ionescu", 209791); // Insereaz cu Add()
T .Add("Pop", 232145);
T["Vlad"]
= 213048;
// Insereaz cu operatorul
T["Cazacu"]= 219465;
// de indexare
Console.WriteLine("Cheia Vlad are valoarea:
T ["Vlad"]) ;

{0}",

// Cu operatorul de indexare poate schimba valoarea


// asociat unei chei existente
T ["Vlad"] = 215773;
Console.WriteLine("Cheia Vlad are valoarea: {0}\n",
T["Vlad"]);
// Dac cheia nu exist in dicionar, se adaug o
// nou pereche cheie-valoare
T ["Dragnea"] = 279950;
// ContainsKey() se folosete pentru a testa
// existena unei chei nainte de inserare
// if (!T.ContainsKey("Simion"))
T .A d d ("Simion", 200371);
/ / I n dicionar elementele se memoreaz ca perechi
// cheie-valoare n obiecte de tip KeyValuePair
foreach (KeyValuePair<string, int> p in I)
Console.WriteLine("{0, -7}
{1, 10}",
p.Key, p.Value);
// terge o pereche cheie-valoare
T .Remove("Ionescu");
if ( !T .ContainsKey("Ionescu") )
Console.WriteLine("\nCheia Ionescu nu exista");

}
}
Ieire:
Cheia Vlad are valoarea: 213048
Cheia Vlad are valoarea: 215773

Capitolul 5.
Ionescu
Pop
Vlad
Cazacu
Dragnea
Simion

Trsturi eseniale ale limbajului C#

123

209791
232145
215773
219465
279950
200371

Cheia Ionescu nu exista

Tratarea excepiilor
n timpul execuiei unui program pot aprea situaii excepionale, cum ar fi
operaii ilegale executate de propriul cod, care pot duce la ntreruperea execuiei
programului sau la un comportament neateptat. Aceste situaii se numesc
excepii. C# ofer un mecanism de tratare a excepiilor, bazat pe cuvintele cheie
try, catch i finally.
Erorile din timpul rulrii programului se propag n program cu ajutorul
acestui mecanism de tratare a excepiilor. Vei include codul care este probabil s
arunce excepii, ntr-un bloc try. Cnd excepia se produce, fluxul de execuie al
programului este dirijat direct n blocul de cod numit catch, care prinde i
trateaz excepia. Excepiile neprinse, sunt captate de ctre un handler furnizat
de ctre sistem, care afieaz un mesaj de eroare.
Tipurile execepiilor care pot s apar sunt reprezentate de ctre clase
specializate ale platformei .NET, clase care deriv din clasa Exception.
Pentru tratarea excepiilor, vei proceda astfel:
try

{
// Cod care poate arunca excepii

}
catch(System.Execption e)

{
// Cod care trateaz excepia

1
finally

{
II Cod care se execut dup try-catch indiferent

// dac se arunc sau nu execepii

}
Exemplu:
using System;
class TestExceptii

Partea I. Limbajul C#

124

{
public static void Main()

{
int [] a = { 2, 4, 6, 8 };
try
{
Console.WriteLine(a[4] ) ;

>
catch (Exception e)

{
Console.WriteLine("Excepie!\n" + e .ToString());

}
finally

{
Console.WriteLine (a [3]);

}
}
}
Ieire:
Excepie!
System.IndexOutOfRangeException: Index was outside the bounds
of the array at TestExceptii.Main() in c:\teste\Program.cs:
line 7

8
Blocul catch declar o variabil de tip execpie (e) care poate fi utilizat pentru a
obine informaii suplimentare. Codul din blocul finally se execut indiferent
dac se arunc sau nu o excepie n blocul try, permind programului s
elibereze resursele (fiiere deschise, memorie alocat, etc.). Dac excepia se
produce, atunci blocul finally se execut dup catch.
Blocul finally poate s lipseasc. Pentru acelai bloc try, se pot declara mai
multe blocuri catch, fiecare dintre ele, preciznd o posibil excepie care se poate
lansa din try.

Manevrarea stringurilor
Tipul string n C# este un alias pentru clasa System. String din .Net
Framework. Este un tip referin. Obiectele de tip string ncapsuleaz un ir de
caractere n format Unicode. Stringurile sunt imutabile. Odat creat, un obiect de
tip string nu mai poate fi schimbat; toate operaiile care modific un string
returneaz un alt string modificat.

Capitolul 5.

Trsturi eseniale ale limbajului C#

125

Operaii i metode
string definete operatorii relaionali =, != i operatorii de concatenare +,
+=. Definete de asemenea mai multe metode utile. Vom exemplifica utilizarea
ctorva dintre ele.
using System;
class Teststring

{
public static void Main()

{
string sl = "Salut", s2 = "salut";
if (sl != s2) // Compar stringurile, nu obiectele
Console.WriteLine("sl != s2") ;
if ( sl.ToUpper) == s2.ToUpper() )
Console.WriteLine(sl.ToUpper()); //Afieaz SALUT
sl += s2;
// sl este acum "Salutsalut"
// Insereaz irul " " ncepnd cu poziia 5
string s = sl.Insert(5, " "); // sl nu se modific!
Console.WriteLine(s); // Afieaz: "Salut salut"
// Extrage din s, ncepnd cu poziia 6,
/ / u n substring format din 3 caractere
s = s .Substring(6, 3);
Console.WriteLine(s); // Afieaz: "Salut salut"

}
}

Formatarea stringurilor
Pentru formatarea stringurilor exist n clasa string metodele statice
Format(), suprancrcate.

Exemplu:
using System;
class Teststring
{
public static void Main()

{
int x = 123; double y = 23.4589;
string s = String.Format("x = {0}, y = {1}", x, y) ;
Console.WriteLine(s); // Afieaz: 123 23.4589

}
}
Mai sus, {0 } se refer la primul obiect (x) din lista de parametri, iar {1 } identific
cel de-al doilea obiect (y).

126

Partea I. Limbajul C#

Opiunile de formatare sunt diverse. Putei stabili aliniere justify la stnga


sau la dreapta i formatul de afiare a numerelor:

Exemplu:
f l o a t x = 1 23 .34 5 6F ; d o u b le y = 2 3 .4 5 8 9 ; s t r i n g s;
s = S t r i n g . F o rm a t( "x = { 0 ,1 2 :E 3 } \n y = { 1 , 1 2 : F 2 } " , x , y ) ;
C o n s o le . W r ite L in e ( s ) ;
A f i e a z :
x =
1 . 233E+002
y =
2 3 .4 6
Specificatorul {0 ,1 2 :E 3} se interpreteaz astfel: 0 - identific primul obiect
(x), 12 este limea cmpului de afiare, E cere afiare n format tiinific, iar 3 este
numrul de zecimale care se afieaz.
Specificatorul { 1 ,1 2 :F 2 } se interpreteaz astfel: 1 - identific al doilea
obiect (y), 12 este limea cmpului de afiare, F impune afiare n virgul fix, iar
2 este numrul de zecimale care se afieaz. Dac dorii aliniere la stnga, se
pune semnul - dup virgul: { 1 ,- 1 2 ;F 2 }.
Stringurile se pot formata pentru afiare dup aceleai reguli i cu ajutorul
metodelor C o n so le .W r ite () i C o n sole .W r ite L in e ():

Exemplu:
d o u b le x = 2 3 . 4 5 8 9 ;
C o n s o le .W r ite L in e ( " |x = { 0 , 1 0 : F 2 } | " , x ) ;
C o n s o le .W r ite L in e ( " |x = { 0 , - 1 0 : F2 } | " , x ) ;

Afieaz:
|x =
23.46|
|x = 23.46
|

Transformarea stringurilor n valori numerice


n C# nu exist metode sau operatori care s citeasc date numerice din
stream-ur\ i s le formateze direct n valori numerice, aa cum sunt funciile
s c a n f {) din limbajul C, sau operatoul de extracie din C++. De regul, vei citi
datele ca stringuri. Din aceste stringuri, vei extrage valorile numerice.
Tipurile predefinite ( in t , d o u b le , f l o a t , etc.) definesc metoda P a r s e ().
Aceasta preia stringul citit i l transform n valoarea numeric corespunztoare.

Exemplu :
in t n = i n t . Parse("652");
/ / n = 652
d o u b le d = d o u b l e . P a r s e ( " - 2 0 . 2 3 5 " ) ; / / d = - 2 0 . 2 3 5

Capitolul 5.

Trsturi eseniale ale limbajului C#

127

/ Citim un numr real de la tastatur:


string s = Console.ReadLine();
// s = "91.045"
double f = double.Parse(s);
// f = 91.045

Citirea unui ir de valori numerice


Dac este nevoie s citii un ir de valori numerice dintr-un stream, de
exemplu de la tastatur, atunci trebuie s precizai caracterul sau caracterele
separatoare ntre numere.
Un caz simplu este acela n care toate numerele sunt desprite printr-un
singur spaiu i se gsesc pe o singur linie. Se citete linia ntr-un string, apoi se
desparte stringul n substringuri reprezentnd numerele. Pentru aceasta, utilizai
metoda Split (). Aceasta returneaz un tablou de stringuri reprezentnd
numerele citite.
Exemplu:
string linie = Console.ReadLine();
string[] s = linie.Split(' '); // Separatorul este
int x;
// caracterul spaiu
foreach (string nr in s)
// Parcurge tabloul de stringuri
x = int.Parse(nr);
Console.Write(x + " ");

// Le transform n valori int

Metoda Split () este suprancrcat. Una dintre versiuni are ca parametru


un ir de caractere char[]. n acest ir vei introduce toate caracterele
separatoare pe care le considerai necesare. Al doilea parametru al metodei, v
permite s nlturai toate substringurile vide din tabloul de stringuri rezultat n
urma splitrii. Se obin stringuri vide n situaia cnd n stringul iniial apar doi sau
mai muli separatori consecutivi.
Exemplu:
using System;
public class TestSplit
{
static void Main()

{
char[] sep = { '\n', ' 1, '.', '!' } ;
string s = "12
27\n... 496!";
string[] w = nuli;
// Tabloul w preia substringurile fr separatori din s
w = s .Split(sep,StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < w.Length; i++)

{
int x = int.Parse(w[i]) ;

Partea I. Limbajul C#

128

Console.Write(w[i] +

}
}
}
Ieire:
12_ 27_ 496_

Cunosctorii limbajului C au remarcat desigur similitudinea ntre metoda S p l i t ()


i funcia s t r t o k ( ) .

Citiri i afiri din fiiere de tip text


Toate intrrile i ieirile n C#, la fel ca n C++ sau Java, presupun folosirea
sfream-urilor. Un stream este o reprezentare abstract a unui dispozitiv fizic
(memorie, fiier, reea, etc.), n care informaia se poate accesa doar cte un byte
odat. ntr-un stream informaia circul ntr-un singur sens. De exemplu, un
program nu va scrie datele direct ntr-un fiier, ci le va scrie ntr-un stream de ieire
care reprezint fiierul.
Exist stream-uri de intrare i sfream-uri de ieire. Din sfream-urile de intrare
programul citete date, iar n cele de ieire scrie date. Pstrnd dispozitivul n
form abstract, destinaia sau sursa sfream-ului poate fi ascuns. Aceasta
permite reutilizarea codului, iar codul este similar atunci cnd aplicaiile scriu sau
citesc din fiiere sau din reea, de pe disc, din memorie, sau din oricare alt
dispozitiv.
.NET Framework definete n spaiul de nume System.IO acele clase care
reprezint stream-un cu fiiere. Sunt mai multe astfel de clase. n acest paragraf ne
referim la doar un singur aspect: citirea i scrierea datelor numerice din fiiere text.
lat un program pentru exemplificare:
using System;
using System.IO;
class FileReadWrite
{
static void Main()

{
string fin = @"C:\teste\numere.in";
string fout = @"C:\teste\numere.out";
// Deschide fiierele de intrare i de ieire
StreamReader sr = new StreamReader(fin);
StreamWriter sw = new StreamWriter(fout);
string[] s = nuli;
string linie = nuli;

Capitolul 5.

Trsturi eseniale ale limbajului C#

129

int x = 0;
// Citete cte o linie pn la ntlnirea
// sfritului de fiier
while ( (linie = sr.ReadLine()) != nuli )

{
s = linie.Split(' '); // Desparte linia in stringuri
foreach (string nr in s)

{
x = int.Parse(nr); // Obine valoarea numeric
sw.Wr ite("{0, -5}", x) ; // O scrie n fiier

}
sw.WriteLine();

}
sr.Close();
sw.Close();

// nchide fiierele

}
}

Exemplu : Dac numere.in conine valorile:


12 335 561
0 25 5 76
99 1 773 67 3
Atunci numere.out va avea:
12
0
99

335
25
1

561
5
773

76
67

Observaii:
i
>

>

>
>

Clasele StreamReader i streamWriter citesc, respectiv scriu caractere


din stream-uri. Conin metodele ReadLine (), respectiv WriteLine).
Acestea citesc sau scriu din stream pn la caracterul newline.
O constant ir de caractere se numete ir verbatim, dac se prefaeaz cu
caracterul @. Exemplu: @"C:\teste\numere.in". Efectul este c secvenele
escape din interior nu se mai evalueaz. Deci irul verbatim din exemplu este
echivalent cu "C:\\teste\\numere.in".
n expresia sw.Write (" {0, -5}", x) 0 semnific primul obiect de afiat,
adic x, iar -5 cere alinierea la stnga a rezultatului pe un cmp de lime 5.
Dac fiierul de intrare poate avea ca separatori ntre dou numere pe aceeai
linie mai mult dect un singur spaiu, atunci vei folosi versiunea Split () cu
separatori, aa cum am artat n paragraful Transformarea stringurilor n
valori numerice1'.

Partea I. Limbajul C#

130

Rezumatul capitolului

O delegare este un tip referin, utilizat s ncapsuleze o list ordonat de


metode cu aceeai semntur i acelai tip de retur. Lista de metode se
numete lista de invocare. Cnd un delegat este invocat, el apeleaz toate
metodele din lista de invocare.
Evenimentele C# permit unei clase sau un obiect s notifice, s ntiineze
alte clase sau obiecte c ceva s-a ntmplat.
Un eveniment este un membru public al clasei care public evenimentul.
Atunci cnd are loc o aciune, acest membru al clasei publisher se
activeaz, invocnd toate metodele care au subscris evenimentului.
Scopul programrii generice este scrierea de cod care s fie independent
de tipurile de date.
Exist clase generice i metode generice. Clasele generice sunt tipuri
parametrizate. Parametrii lor se numesc parametri tip sau parametri

generici.

Coleciile sunt clase specializate pentru depozitarea datelor. Biblioteca


.NET definete colecii generice i colecii non-generice.
Coleciile implementeaz stive, cozi, liste, tabele de dispersie (hash-

tables).

Tipurile predefinite (int, double, float, etc.) definesc metoda Parse ().
Aceasta preia stringul citit i l transform n valoarea numeric
corespunztoare.
Clasele
StreamReader i StreamWriter citesc, respectiv scriu
caractere din stream-uh. Conin metodele ReadLine(), respectiv
writeLine (). Acestea citesc sau scriu din stream pn la caracterul

newline.

ntrebri i exerciii
1.

Ce rol ndeplinete un tip delegat ntr-un program ?

2.

Cum putei elimina o metod din lista de invocare a unei delegri ?

3.

De ce se spune c aplicaiile Windows sunt conduse de evenimente ?

4. Evideniai asemnrile i deosebirile dintre tipul tablou i tipul List<T>.


5.

S se citeasc din fiierul text matrice.in elementele unui tablou


bidimensional de valori ntregi. S se afieze n fiierul matrice.out ptratul
valorii fiecrui element al tabloului.

Capitolul 6.

Aplicaii de tip Windows Forms

131

Partea a II - a

Programare Windows
cu Visual C# 2008 Express Edition
Capitolul 6

Aplicaii de tip Windows Forms


Visual C# 2008 Express Edition (VCSE) ofer suport pentru dezvoltarea
urmtoarelor tipuri de aplicaii:

Aplicaii
Aplicaii
Aplicaii
Aplicaii

Windows de tip Windows Forms.


Windows de tip WPF ( Windows Presentation Foundation).
de tip consol.
de tip bibliotec dinamic.

Aplicaiile de tip Windows Forms i cele WFP faciliteaz prin designer-ele integrate
dezvoltarea interfeelor grafice cu utilizatorul (user interface).

Aplicaii cu interfa grafic cu utilizatorul


Biblioteca .NET conine un numr mare de clase definite n spaiul de nume

System.Windows.Forms, cum sunt: Button, TextBox, ComboBox, Label, etc.


Instanele acestor clase identific controalele Windows. Controalele sunt elemente
de interfa grafic ale unei aplicaii Windows.
Un programator hardcore poate s codeze cu ajutorul acestor clase o
aplicaie cu interfa grafic orict de complicat fr a utiliza mediul integrat, ns
munca este imens. Este de preferat s lsai Visual C# s genereze pentru voi
acel cod necesar interfeei grafice, ca s v putei concentra pe funcionalitatea
aplicaiei. Vei utiliza pentru aceasta Windows Form Designer i Toolbox. Cu
mouse-ul, prin drag and drop vei alege controalele necesare din Toolbox i le vei
aranja pe suprafaa formelor n Windows Form Designer. Vei seta proprietile
controalelor. Pe msur ce facei toate acestea, designerul genereaz codul C#
aferent, pe care l scrie n fiierul <nume>. designer .cs, unde <nume> este
numele formei respective.
Aadar, sunt trei etape importante n crearea unei aplicaii cu interfa
grafic:
1. Adugarea controalelor pe suprafaa formelor.
2. Setarea proprietilor iniiale ale controalelor din fereastra
Properties.
3. Scrierea handlerelor pentru evenimente.

132 Partea a II-a. Programare Windows cu Visual C# Express Edition

Realizarea unei aplicaii simple de tip Windows Forms


Vom crea o aplicaie numit Salut, care are un singur buton plasat pe o
form. La apsarea lui, apare o fereastr sistem de tip MessageBox, care afieaz
un mesaj de salut. Urmai paii:
n meniul File, click New Project.

1.

2. n fereastra New Project, n panoul Templates, alegei Windows Forms


Application.
3.

n cmpul Name, scriei Salut, apoi click OK.


n acest fel ai creat un nou proiect Windows Forms. Acum urmeaz:

4.

Din Toolbox, tragei un buton pe suprafaa formei.


S a lu t - M ic ro s o ft V is u a l

File

jJ

Edit
j

View
J

Project

Ctt2 0 0 8
Build

.....

iS

Toolbox

xj;-- -

-r 9 X

Express E ditio n

Debug

Data

Format

Pointer

Forml.cs [Design]*

8 Foriril

fib) Button
0

Checkbox

i|>; CheckedListBox
T f ComboBox
2 ? DateTimePicker

Tools

Window

Help

* ft....
|
.A. .....
......
.<2L :i . i!

AII Windows Forms


- Common Controls
^

......

buttonl

..

f[ .2'7 1

.. -

Solution Explorer - Salut

r ? X

3 Solution 'Salut' (1 project)


I & ' 3 Salut
80-
Properties
$
ReFerences
3 3 Forml.cs
^ Forml.Designer.es
^ Forml.resx
Program.es

Label

A LinkLabel
l&i*j ListBox
UstView

5.

Click dreapta pe butonul cu eticheta buttonl. Alegei Properties din


meniul contextual.

6.

n fereastra Properties, schimbai valoarea proprietii Text n Apasa.

Capitolul 6.
Toolbox

Aplicaii de tip Windows Forms

133

+ AII Windows Forms

b u ttonl System.Windows.Forms.

- Common Controls
|^

i n i k

Pointer

|abj Button
: 0

CheckBox

CheckedListBox

Imagelndex

ImageKey
ImageList

I
I (none)
(none)

RightToLeft

No

ComboBox

A
A

1 (none)

Apasa

DateTimePicker

Text Align

Labei

TextlmageRelc Overlay

LinkLabel

UseMnemonic

MiddleCenter
True

UseVisualStylel True

; i f ryj ListBox

UseWaitCursor False

; V ' ListView

B !iefu:v.

7.

Urmeaz tratarea evenimentului Click, pentru ca aplicaia s rspund


acestui eveniment. Avei dou variante:
a. Dublu click pe suprafaa butonului.
b. n fereastra Properties, click pe iconul fulger", numit Events. Din
lista de evenimente la care poate rspunde butonul, selectai
evenimentul Click i apsai Enter.
n ambele situaii se deschide Editorul de Cod. Fiierul deschis este
Forml.es, iar metoda nou creat este buttonl_Click. Acesta este
handler-ul de eveniment. Va fi invocat n mod automat la click pe buton.

8.

n corpul metodei, scriei codul:


private void buttonl_Click(object sender, EventArgs e)

{
MessageBox.Show("Salut lume !");

}
9.

Compilai i rulai aplicaia cu F5.

' -.rorml
V using
using
usmg
using
using
using
: using
: using

, button1_Ck>Xob|ed

System;
System.Collections.Generic;
System.CoroponentKode1 ;
System.Data;
System.Drawing;
System.Linq;
System.Text;
System.Windows.Forms;

Fereastra
aplicaiei

; namespace Salut

;f
public partial class Foiini : Form
{
public FormlO
{
InitialiseComponent();

>

private void buttol_Cliek(object


(
Jle5sage So* .Show ("Salut lume '")

Message Box

134 Partea a Il-a. Programare Windows cu Visual C# Express Edition

Observaie:
j

Pentru afiarea mesajelor de informare se utilizeaz metoda static Show()


a clasei System.Windows.Forms.MessageBox.

Controale, proprieti i evenimente


Controale
Controalele sunt instane ale unor clase .NET definite n spaiul de nume
System.Windows.Forms. Marea majoritate a acestor clase deriv din clasa
Control, care definete funcionalitatea de baz a oricrui control. Aa se explic
faptul c unele proprieti i evenimente sunt comune tuturor controalelor. Clasele
de tip control sunt organizate ierarhic, pe baza releiei de motenire, aa cum se
vede din diagrama parial de mai jos:
Object

" 1 ---I

Fig. 6.1

S t r u c t u r a ie r a r h ic a c o n t r o a l e l o r . N E T

n mod evident, diagrama de mai sus este incomplet. Numrul de controale este
mult mai mare.

Proprieti
Proprietile sunt membri ai claselor din care fac parte. Ele definesc
caracteristicile controalelor, de pild culoarea, poziia, dimensiunile acestora.
Controalele motenesc proprietile claselor printe. n unele cazuri le suprascriu
(override), pentru a obine un comportament particular i definesc de asemenea
altele noi.
Fereastra Properties a mediului integrat este un instrument important.
Selectnd un control, avei acces vizual la proprietile i evenimentele pe care le
suport controlul. Controalele se creaz cu adevrat run-time, ns proprietile lor
iniiele pot fi stabilite design-time n aceast fereastr. Desigur c aceste
proprieti se pot modifica programatic n timpul execuiei programului.

Capitolul 6.

Aplicaii de tip Windows Forms

135

Evenimente
ncepnd cu aceast parte a lucrrii, ne vom preocupa doar de
evenimentele pe care le genereaz controalele Windows,

IMPORTANT
Programele cu interfa grafic cu utilizatorul sunt conduse de evenimente
event-driven)
n momentul n care utilizatorul acioneaz asupra unui control, cum ar fi
click pe un buton, sistemul de operare simte i transmite controlului un mesaj.
Controlul genereaz atunci un eveniment specific acelei aciuni, ca un semn c
ceva s-a ntmplat. Programatorul poate s trateze sau nu acel eveniment. Dac
alege s o fac, atunci el trebuie s scrie o metod handler, aa cum este
buttonl_ciick () n paragraful anterior. Aceast metod se apeleaz n
momentul n care evenimentul are loc, iar codul ei asigur funcionalitatea dorit a
controlului.
Toate controalele au evenimente pe care le pot genera. Amintii-v c
evenimentele sunt membrii ai claselor de tip control definite de .NET.

Tratarea evenimentelor
n partea teoretic a lucrrii am discutat despre mecanismul tratrii
evenimentelor n C#. Un obiect public un eveniment, iar alte obiecte subscriu
acestui eveniment. Cnd evenimentul se declaneaz, toate obiectele care au
subscris sunt informate, n sensul c handlerele acestora se vor invoca.
S presupunem c avem o form, pe care ai aezat un buton. Vrem s
tratm evenimentul click pe buton. Cine este publisher ? Desigur, butonul. i cine
este subscriber ? Este fereastra printe, adic forma. Deci n clasa ataat formei
vom defini o metod handler. Cum are loc subscrierea ? Vom vedea cu exemplul
practic care urmeaz. Din fericire, codul necesar subscrierii i definiia metodei de
tratare a evenimentului se genereaz n mod automat, atunci cnd utilizai panoul
Properties.

Cum se creaz handler-ele


Pentru acelai control putei trata mai multe evenimente, definind desigur
cte un handler specific. Mai mult dect atat, un acelai handler poate fi utilizat
pentru mai multe controale, aa cum vom vedea n continuare.
Vom realiza un proiect cu trei controale de tipuri diferite. Pentru fiecare
control tratm evenimentul Click. n mod evident, putem scrie cte un handler care
s rspund fiecrui control. Vom proceda ns altfel. Vom crea un singur handler
pentru Click pe oricare control. Acest lucru este posibil, datorit signaturii speciale
a handlerelor .NET:

136 Partea a Il-a. Programare Windows cu Visual C# Express Edition


private void NumeHandler(object sender, EventArgs e)

{
// Cod care trateaz evenimentul

}
sender este o referin la obiectul (controlul) care a generat evenimentul. Astfel,
n corpul handlerului putem identifica acel control i putem trata n mod difereniat.

Aplicaia C lic k E v e n t
Pentru realizarea proiectului, urmai paii de mai jos:
1.

Creai un proiect de tip Windows Forms, cu numele ClickEvent.

2.

Facei click drept pe suprafaa formei i alegei Properties.

3.

Schimbai (opional) titlul formei (implicit este Form l) n ClickEvent,


modificnd valoarea proprietii Text. Modificai proprietatea Name la
valoarea FormaMea. Este noul nume al clasei formei. Numele implicit era
Forml.

4.

(Opional). n Solution Explorer facei click drept pe fiierul Forml.cs i


redenumii-l FormaMea.es. Dac fereastra Solution Explorer no e vizibil,
atunci din meniul View, alegei Solution Explorer.

5.

Tragei cu mouse-ul pe suprafaa formei din Toolbox trei controale diferite,


de exemplu un Button, un CheckBox i un TextBox.

6.

Selectai butonul i setai proprietatea Text la valoarea Apasare, iar


proprietatea Name la valoarea buton (implicit aceasta era buttonl).

7.

Selectai check box-ul i setai proprietatea Text la valoarea Validare, iar


proprietatea Name la valoarea verif (implicit aceasta era checkBoxl).

8.

Selectai csua de text i atribuii proprietii Name valoarea edit (implicit


aceasta era textBoxl).

9.

Selectai butonul i din Properties apsai butonul Events (fulgerul). Vei


crea un handler pentru tratarea evenimentului Click generat de buton.
Avei varianta simpl de a face dublu click pe eticheta Click din Properties
sau un simplu dublu click pe suprafaa butonului. n aceast variant se
genereaz metoda cu prototipul:
private void buton_Click(object sender, EventArgs e)

A doua variant este s dai alt nume metodei, din fereastra Properties,
editnd cmpul din dreapta etichetei Click. Putei pune de pild numele
eveniment_Click, apoi apsai Enter.

Capitolul 6.

Aplicaii de tip Windows Forms

+ All Windows Forms

137

buton System.Windows.Forms.Button

Common Controls

I ^ Pointer

Button
ChecKBox

eveniment_Click y

Apasare

MouseCaptureChangec

CheckedListBox

MouseClick

If* ComboBox

validare

DateTimePicker

Paint

B Behavior

Label

LinkLabel

ChangeUICues
ControlAdded
ControlRemoved

1*1 ListBox

ListView
i-

MaskedTextBox

HelpRequested
QueryAccessibilityHelp

MonthCalendar

StyleChanged

Notifylcon

SystemColorsChanged

10. n Editorul de Cod, completai corpul metodei generate, ca mai jos:


private void eveniment_Click(object sender,EventArgs e)

{
Control c = (Control)sender;

// Conversie explicit
//
(downcast)
MessageBox.Show("Ati fcut click pe controlul: " +
c.Name + " cu eticheta: " + c.Text);

}1
11. Acum subscriem cu acelai handler, pentru evenimentele generate de
CheckBox i TextBox. Selectai pe rnd cte unul dintre controale, i din
fereastra Properties, apsai butonul Events, apoi alegei din lista din
dreapta etichetei Click acelai handler. eveniment_ciicJc.
ve rif System,Windows .Forms. CheckBox

,0

Apasare
MouseCaptureChar eveniment_Click
MouseClick
O

-----------------------

validare

0 Behavror
1

ChangeUICues
ControlAdded

12. Compilai i rulai cu F5 (sau click pe butonul cu iconul din bara de


instrumente Standard).

138 Partea a Il-a. Programare Windows cu Visual C# Express Edition


J4 XT''?*
' ... - . . . ,

yA S M

Apasare

F I validare

Ati fcut click pe controlul: verif cu eticheta: validare

OK

Observaii:
j

n corpul handlerului, c.Name i c.Text sunt proprieti ale controalelor,


reprezentnd numele obiectului care reprezint controlul, respectiv
eticheta afiat pe control. TextBox nu are proprietatea Text.
Expresia Control c = (Control) sender ; necesit o conversie
explicit (downcast), deoarece sender e de tip object, Control e
subclas pentru object (sau object), iar conversiile implicite au loc
numai de la subclase la superclase.

O privire n spatele scenei


Ne referim la proiectul realizat n paragraful anterior. Am utilizat Windows
Forms Designer care include ntre altele Editorul de Cod i fereastra Properties,
pentru scrierea codului i tratarea evenimentul Click. Pe msur ce operam n
mod vizual, mediul integrat lucra pentru noi, translatnd aciunile n cod C#. S
vedem:
A) . Dup primul pas de creare a proiectului, aveam o form goal, cu eticheta
Forml. S-au generat fiierele de baz ale proiectului: Forml.es,
Forml.Designer.es i Program.cs.
B) . n urma plasrii controalelor pe form i a setrii proprietilor Name i Text
pentru form, buton, butonul de validare i controlul de tip TextBox, dar i a
redenumirii fiierelor proiectului, n Solution Explorer putei identifica:
FonuaMea.es, FormaMea.Designer.es, Program.es.

Fiierul P ro g ra m .e s
Fiierul conine metoda Main(). Este punctul de intrare n aplicaie. n
Solution Explorer, facei click drept pe Program.es i alegei View Code:

Capitolul 6.

Aplicaii de tip Windows Forms

139

// fragment din codul Program.es


static v o i d Main()

{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FormaMea());

}
Partea important este faptul c metoda Main() din clasa P r o g r a m apeleaz
metoda Run ( ) .R u n () e metod static a clasei Application. R u n () lanseaz
n execuie aplicaia. O instan a clasei FormaMea este creat i este fcut
vizibil. n acest fiier ar trebui s nu modificai nimic.

Fiierul F o rm a M e a .e s
Fiierul implementeaz n general constructorii clasei, i toate metodele
definite de programator.
n Solution Explorer, facei click drept pe fiierul F o r m a M e a .cs i alegei
View Code:
II fragment din codul FormaMea.es
namespace C lickEvent
{
p u bl ic p a rtial class FormaMea

: Form

{
p u b l i c F o r m a M e a ()

{
I n i t i a l i z e C o m p o n e n t ();

}
}
p r i va te v o i d e v e n i m e n t _ C l i c k (object sender, E v e n tArgs e)
{

Control c = (Control)sender;

// Conversie explicit
// (downcast)
MessageBox.Show("Ati fcut click pe controlul: " +
c.Name + " cu eticheta: " + c.Text);

}
}

Observaii:

Fierul definete clasa FormaMea. Cuvntul cheie p a r t i a l spune faptul


c definiia clasei se va completa n alt fiier (FormaMea.D e s i g n e r .cs).
Forma M e a motenete clasa Form din .NET, pentru ca s aib toate
caracteristicile unei forme Windows.
Constructorul clasei, care se invoc la crearea formei, apeleaz metoda
I n i t i alizeCom ponent (). Aceast metod execut tot codul necesar la

140 Partea a II-a. Programare Windows cu Visual C# Express Edition


iniializarea aplicaiei: crearea controalelor, setarea proprietilor iniiale,
etc. Cu alte cuvinte, tot ce ai setat design-time.
Practic, dumneavoastr vei coda mai mult n acest fiier. Este locul unde
definii de regul metode, proprieti i evenimente noi ale clasei.
Oricnd dorii ca o metod s fie apelat odat cu crearea formei, putei
alegei constructorul clasei n acest scop:

public FormaMea)
// Constructor
{
// Aici putei apela metode.
// Controalele nu exist nc
InitializeComponent();
// Si aici putei apela metode.
// Forma i controalele sunt deja create

Cnd dorii ca un cod s fie executat ca rspuns la o aciune a user-ului,


vei identifica evenimentul care se declaneaz la aceaa aciune, i-l vei
trata. Vei scrie codul dorit n handler-ul de eveniment.

Fiierul F o rm a M e a.D e s ig n e r.es


Fiierul reine tot ce s-a stabilit n etapa de design, relativ la form i
controale. Codul fiierului se genereaz n mod automat.
n Solution Explorer, facei click drept pe fiierul FormaMea.Designer.es
i alegei View Code:
// fragment din codul FormaMea.Designer.es
namespace ClickEvent

{
partial class FormaMea
{

II...
private void InitializeComponent()

{
II...
}
private System.Windows.Forms.Button buton;
private System.Windows.Forms.CheckBox verif;
private System.Windows.Forms.TextBox edit;

}
}

IMPORTANT! Fierul completeaz definiia clasei FormaMea reinnd


toate setrile fcute design-time.
IMPORTANT! Remarcm trei cmpuri private: referinele buton, verif i
edit. Cmpurile au aprut sub numele: buttonl, checkBoxl i

Capitolul 6.

Aplicaii de tip Windows Forms

141

textBoxl, n momentul n care ai plasat controalele pe form. Numele


actuale s-au generat automat, atunci cnd din fereastra Properties ai
modificat proprietatea Name.
IMPORTANT! Cele trei referine sunt coninute n clasa FormaMea.
Amintii-v relaia care se modeleaz la coninere: HAS A. ntradevr,
forma are un sau conine un buton, are un check box i are un text box.

etoda In itia lize C o m p o n e n tf)


Redm fragmentele semnificative de cod din acest metod:

private void InitializeComponent()

(
// Instanierea (crearea) celor trei controale
// prin apelul constructorilor
t h i s . b u to n = new S y s te m .W in d o w s . F o rm s . B u t t o n ( ) ;
t h i s . v e r i f = new S y s te m .W in d o w s . F o rm s . C h e c k B o x ( ) ;
th is .e d it
= new S y s te m .W in d o w s . F o rm s . T e x t B o x ( ) ;

// Setarea proprietilor iniiale ale controlului


// buton ca urmare a aciunilor de design n fereastra
// Properties i Form D e s i g n e r .
t h i s . b u t o n . L o c a t io n = new S y s t e m .D r a w in g .P o in t ( 7 8 ,
t h i s . b u t o n . Name = " b u t o n " ;

23);

this.buton.Size = new System.Drawing.Size(75, 23);


this.buton.Text = "Apasare";
// Subscrierea la evenimentul Click
this.buton.Click
+= new System.EventHandler(this.eveniment_Click);
// Setri similare pentru celelalte dou controale

II...
II Adugarea controalelor pe form
t h i s . C o n tr o ls .A d d (t h is . e d i t ) ;
th is .C o n tr o ls .A d d (th is . v e r i f ) ;
t h i s . C o n tr o ls .A d d (th is .b u to n );

// Setarea proprietilor formei


this.Name = "FormaMea";
this.Text = "ClickEvent";
// Afiarea controalelor pe form
t h i s . R e s u m e L a y o u t ( f a ls e ) ;
t h i s . P e rfo rm L a y o u t( ) ;

Se impun cteva precizri cu privire la metoda lnitalizeComponent():

142 Partea a II-a. Programare Windows cu Visual C# Express Edition


1.
2.
3.
4.

Codul metodei se genereaz n mod automat. Nu este indicat s


modificai manual acest cod. Operai cu Form Designer i fereastra
Properties i modificrile se produc de la sine.
Metoda construiete controalele prin apelul constructorilor acestora.
Metoda stabilete proprietile iniiale ale controalelor i ale formei.
Metoda stabilete subscrierea formei la evenimentele generate de ctre
controale. Subscrierea se face astfel:
this.buton.Click += new
System.EventHandler(this.eveniment_Click);
this.edit.Click += new
System. EventHandler(this.eveniment_Click) ;
this.verif.Click += new
System.EventHandler(this.eveniment Click);
this este referina la obiectul de tip FormaMea. O subscriere ca aceasta
este la fel de corect:
buton.Click += eveniment_Click;
edit.Click += eveniment_Click;
verif.Click += eveniment_Click;

Altfel spus, obiectul referit de this (forma) subscrie la evenimentele Click


generate de ctre fiecare control, setnd pentru fiecare caz, acelai
handler :eveniment_Click.
5. Putei, cu siguran, s tratai un eveniment oarecare, scrind manual codul
necesar subscrierii i definind un handler adecvat, fr utilizarea panoului
Properties. Totui, e mult mai comod s utilizai facilitile mediului
integrat.
6. Ca idee general, numele fiierului <nume_form>.Designer.es, ne
spune c este generat n ntregime de ctre compilator. n general, nu se
fac modificri manuale n acest fiier.

Declanarea programatic a unui eveniment


Putei constrnge programatic un control s genereze evenimentul Click,
chiar dac userul nu a acionat click pe acel control. Se utilizeaz metoda
Perf ormClick (). Vom face un mic proiect:

Aplicaia R a is e E v e n t
1. n meniul File, alegei NewProject.
2.

n panoul Templates, selectai Windows Forms Application.

3.

In cmpul Name, scriei de exemplu RaiseEvent ca nume de proiect.

Capitolul 6.

Aplicaii de tip Windows Forms

143

4.

Din Toolbox, aducei pe form dou butoane.

5.

Facei dublu click pe primul buton pentru a trata evenimentul Click. n


Editorul de Cod, scriei n corpul handler-ului:
private void buttonl_Click(object sender, EventArgs e)

{
// Declaneaz evenimentul Click pentru al doilea
// buton
button2.PerformClick() ;

1
6.

Facei dublu click pe al doilea buton pentru a trata evenimentul Click. n


Editorul de Cod, scriei n corpul handler-ului:
private void button2_Click(object sender, EventArgs e)

{
MessageBox.Show("Ati fcut click butonul doi !");

}
7.

Apsai F5 pentru compilare i rulare.

Ati fcut click pe al doilea buton!

b u (to n 2

Mesajul se afieaz indiferent de butonul pe care facei click.

Crearea programatic a unui control


Pn n prezent, controalelelor prezente pe form le-au fost setate
proprietile design-time. Crearea lor are loc totui run-time, odat cu crearea
formei. Putei utiliza oricare handler de eveniment pentru a crea i a seta proprieti
run-time pentru oricare control Windows.

144 Partea a II-a. Programare Windows cu Visual C# Express Edition

Aplicaia D tp R u n tim e
Realizm o aplicaie care n timpul execuiei, prin apsarea unui buton, creaz
un nou control pe form, de exemplu un DateTimePicker. Un control
DateTimePicker afieaz data curent.
1. n meniul File, alegei NewProject.
2. n panoul Templates, selectai Windows Forms Application.
3. In cmpul Name, scriei de exemplu DtpRuntime ca nume de proiect.
4. Din Toolbox, tragei pe form un buton.
5. Facei dublu click pe suprafaa butonului pentru a trata evenimentul Click,
n Editorul de Cod, scriei n corpul handler-ului:
private void buttonl_Click(object sender, EventArgs e)

{
// Creaz runtime un obiect de tip D.T.P.
DateTimePicker dtp = new DateTimePicker();
// Location e poziia colului stnga sus al D.T.P.
dtp.Location = new Point(20, 20);
// Adaug controlul pe form
this.Controls.A d d (dtp);

L Ma Mi J V
1
7
14
21
28
j

2
88
15 16
22 23
29 30

S 0

3 4 5 6
10
11 12 13
17 18 19 20
2425
27
31

iAzi: 26.07.2008

Capitolul 7.

Controalele Windows Forms

145

Capitolul 7

Controalele Windows Forms


Exist o mare diversitate de controale predefinite .NET. ntr-o clasificare
relativ dup funcionalitate, distingem:

Controale pentru declanarea evenimentelor, cum este Button.


Controale pentru editare de text, cum sunt TextBox sau RichTextBox.
Controale pentru afiare de informaii pentru utlizator, cum sunt Labei i
LinkLabel,

Controale pentru afiare de liste, cum sunt ListView sau ListBox.


Controale pentru afiarea informaiilor din baze de date, cum este
DataGridView.

Controale de tip container, cum sunt GroupBox sau Panel.


Controale de tip meniu sau bar de instrumente, cum sunt MenuStrip
sau ToolStrip.

_a cele de mai sus se mai adaug i alte tipuri de controale, care vor fi descrise n
cele ce urmeaz, nsoite de exemple practice.

Controlul Button
n spaiul de nume System.Windows.Forms se definesc trei controale care
deriv din clasa ButtonBase: Button, CheckBox i RadioButton.
Button este de departe cel mai comun control. Pentru a inspecta
proprietile i evenimentele unui buton, este suficient s creai rapid o aplicaie de
tip Windows Forms, s aducei pe form un buton i s parcurgei fereastra
Properties. De multe ori ns nu este de ajuns pentru a v lmuri. De aceea, v
sftuim ca s avei mereu deschis Helpul mediului integrat i s v obinuii s
cutai rapid acolo oricare clas, proprietate sau cod exemplificator. Din meniul
Help, alegei Contents. n panoul din stnga, expandai nodul .Net Framework
SDK. Apoi expandai .Net Framework Class Library. Expandnd mai departe
nodul System.Windows.Forms Namespace, ntreaga galerie de clase de tip
control v este accesibil cu toate informaiile necesare.
Revenind la Button, acesta poate genera mai multe tipuri de evenimente,
ns n proporie covritoare, evenimentul Click este cel mai folosit.

Aplicaia B u tto n E x a m p le
Vom face o mic aplicaie care trateaz alte dou tipuri de evenimente i
pune n eviden cteva dintre proprietile butoanelor.
1.

n meniul File, alegei NewProject.

146 Partea a II-a. Programare Windows cu Visual C# Express Edition


2. n panoul Templates, selectai Windows Forms Application.
3.

In cmpul Name, scriei de exemplu ButtonExample ca nume al


proiectului.

4.

Din Toolbox, tragei cu mouse-ul pe suprafaa formei un control de tip


SplitContainer. Acesta are aici rolul de a izola partea din stnga de cea
din dreapta a formei.

5. n panoul din stnga aducei un buton, iar n cel din dreapta, plasai dou
butoane.

6.

Acionai dublu click pe button 1 pentru a trata evenimentul Click. n corpul


handlerului introducei codul:
private void buttonl_Click(object sender, EventArgs e)
{
// Dac butonul este andocat (umple panoul)
if (buttonl.Dock == DockStyle.Fill)

{
/ / l readucem la forma i eticheta iniiale
buttonl.Dock = DockStyle.None;
buttonl.Text = "buttonl";

}
else
// l andocm i schimbm eticheta
buttonl.Dock = DockStyle.Fill;
buttonl.Text = "Fill !!";

}
7.

Selectai button2 i din fereastra Properties setai proprietatea BackColor


la valoarea Red. i proprietatea Text la valoarea Rou.

8.

Selectai button2, iar din fereastra Properties, apsai butonul Events


(fulgerul). Facei dublu click pe evenimentul MouseEnter. Acesta se
declaneaz atunci cnd mouse-ul intr pe suprafaa controlului. n corpul
hand/er-ului scriei codul:

Capitolul 7.

Controalele Windows Forms

147

private void button2_MouseEnter(object sender,


EventArgs e)
{
// Setm fundalul la culoarea galben
button2.BackColor = Color.Yellow;
button2.Text = "Galben";

}
9.

Selectai button2 i facei dublu click pe evenimentul MouseLeave. Acesta


se declaneaz atunci cnd mouse-ul iese de pe suprafaa controlului. n
corpul hand/er-ului scriei codul:
private void button2_MouseLeave(object sender,
EventArgs e)

// Resetm culoarea fundalului i textul


button2.BackColor = Color.Red;
button2.Text = "Rou";

}
10. Selectai button3 i din fereastra Properties setai proprietatea Text la
valoarea ieire.
11. Facei dublu click pe butonul cu eticheta Ieire, pentru a trata evenimentul
Click. Introducei n corpul handlerului de eveniment, codul:
private void button3_Click(object sender, EventArgs e)

{
Application.Exit(); // Ieire din aplicaie

}
12. Apsai pentru rulare F5, sau iconul * .

La click pe buttonl, acesta se andocheaz, apoi la un nou click, revine la


starea iniial. La intrarea cu mouse-ul deasupra butonului cu eticheta Rou,
acesta i schimb culoarea i eticheta, iar la ieirea mouse-ului revine la
starea iniial. Utilizai metoda Application.Exit () de cte ori dorii s
ncheiai aplicaia.

148 Partea a II-a. Programare Windows cu Visual C# Express Edition

Controalele Labei i LinkLabel


Controalele Labei au menirea de a plasa un text pe o form, cu informaii
pentru utilizator. Aa cum putei vedea din fereastra Properties, controalele Labei
suport evenimente, ns de regul nu le vei trata.
.NET Framework definete i clasa LinkLabel, derivat din Labei.
Aceasta afieaz o poriune din text ca un hyperlink. La un click pe hyperlink, putei
deschide pagini WEB, lansa n execuie diverse diverse aplicaii i n general putei
utiliza handler-ul de tratare a evenimentului Click, pentru orice aciune.

Aplicaia L a b e lE xa m p le
Vom realiza un proiect care exemplific cel mai simplu mod de utilizare a
etichetelor.
1. n meniul File, alegei NewProject.
2. n panoul Templates, selectai Windows Forms Application.
3.

4.

In cmpul Name, scriei de exemplu LabelExample pentru numele


proiectului.
Din Toolbox, tragei cu mouse-ul pe suprafaa formei un control de tip
Labei, i dou controale de tip LinkLabel.

5.

Selectai controlul de tip Labei i n fereastra Properties setai valoarea


proprietii Text la valoarea "Un control de tip Labei".

6.

Selectai primul control LinkLabel i n fereastra Properties setai


proprietatea Text la valoarea " Vizitai www.yahoo.com" , apoi expandai
nodul LinkArea i setai proprietatea Start la valoarea 9. Aceasta
nseamn c link-ul ncepe dup al 9-lea caracter al valorii proprietii
Text.
j

AutoEllipsis

ContextMenuStrip
Enabled
B

(none)
True
9; 2 4

Start

Length

24

LinkBehavior

7.

False

SystemDefault

Selectai primul control de tip LinkLabel, iar n fereastra Properties,


apsai butonul Events. Facei dublu click pe evenimentul LinkClicked.
Scriei n corpul handler-ului codul:
private void linkLabell_LinkClicked(object sender,
LinkLabelLinkClickedEventArgs e)

Capitolul 7.

Controalele Windows Forms

149

// Schimb culoarea link-ului dup click.


linkXabell.LinkVisited = true;
// Schimb textul n controlul Labei
labell.Text = "Se viziteaz www.yahoo.com";
// Folosete metoda Process.Start() pentru a
// deschide un URL cu browserul implicit
System.Diagnostics.Process.Start(
"http://www.yahoo.com");

}
8.

Selectai al doilea control LinkLabe!. n fereastra Properties setai


proprietatea Text la valoarea " Lansai Notepad", apoi expandai nodul
LinkArea i setai proprietatea Start la valoarea 8. Aceasta nseamn c
link-ul ncepe dup al 8-lea caracter al valorii proprietii Text:

U n control Labei

V isitati w w w .vaho o.com

Lansai N ote pad

9.

Selectai controlul LinkLabel cu textul Lansai Notepad", iar n fereastra


Properties apsai butonul Events. Facei dublu click pe evenimentul
LinkClicked. Scriei n corpul handler-ului codul:
private void linkLabel2_LinkClicked(object sender,
LinkLabelLinkClickedEventArgs e)

{
linkLabel2.LinkVisited = true;
labell.Text = "S-a lansat Notepad";
// Folosete metoda Start() pentru a lansa Notepad
System.Diagnostics.Process.Start("notepad");

10. Lansai n execuie cu F5.

150 Partea a Il-a. Programare Windows cu Visual C# Express Edition

aiiura
S-a lansat Notepad
Vizitai www.vahoo.com
Lansai Notepad

Observaii:
>

Proprietatea LinkArea a unui control LinkLabel, este o structur care


reine poziia primului caracter al link-ului i numrul de caractere din link,
lat cum putei crea programatic un LinkLabel care va fi adugat pe o
form:
void AddLinkLabel()

{
// Creaz o etichet
LinkLabel Ink = new LinkLabel();
Ink.Text = "Vizitai www.yahoo.com";
// 9 -poziia primului caracter al link-ului
Ink.LinkArea = new LinkArea(9, 24);
// Poziia de amplasare pe form
Ink.Location = new Point(20, 20);
// Adaug controlul pe forma curent
this.Controls.Add(Ink);

>

Aceast metod se poate apela n constructorul clasei formei, sau


ntr-un handler de eveniment.
Metoda Process.Start () din spaiul de nume System.Diagnostic
este suprancrcat i este util oricnd dorii s lansai n execuie o alt
aplicaie din propria aplicaie. De exemplu, apelul urmtor deschide
fiierul Salut.doc cu WordPa'd:
System.Diagnostics.Process.Start("wordpad.exe ,
@"c:\Salut.doc");

Capitolul 7.

Controalele Windows Forms

151

Controalele RadioButton, CheckBox i GroupBox


Aa cum am mai artat, controalele Button, RadioButton i CheckBox
deriv direct din clasa ButtonBase.
Un buton radio poate fi apsat sau nu. Se folosete atunci cnd utilizatorul
trebuie s fac o singur alegere ntre mai multe opiuni, iar acele opiuni se exclud
reciproc. De exempiu, trebuie s marcheze dac e brbat sau femeie, dac e
cstorit sau nu, etc.
Butoanele radio nu se pun niciodat direct pe form. Ele se grupeaz ntr-un
control container, de regul un GroupBox. n interiorul unui control container, radio
butoanele devin coerente din punct de vedere logic, n sensul c un singur buton
poate fi selectat la un moment dat.
Butoanele de validare (checkbox-urile) permit utilizatorului s aleag una
sau mai multe opiuni. De exemplu, utilizatorul poate sa bifeze mai multe sporturi
preferate. Pot s fie sau nu incluse n controale container.
Controalele RadioButton i CheckBox au proprietatea numit Checked,
care indic dac controlul este selectat sau nu.

Aplicaia G ro u p R ad io C h e c k
Proiectul ilustreaz un mod simplu de utilizare a controalelor RadioButton,
CheckBox i GroupBox.

1.

Din meniul File, alegei NewProject.

2. n panoul Templates, selectai Windows Forms Application.


3.

In cmpul Name, scriei de exemplu GroupRadioCheck pentru numele


proiectului.

4.

Selectai forma. n fereastra Properties setai proprietatea Text la


valoarea Formular.

5.

Din Toolbox, tragei cu mouse-ul pe suprafaa formei un control de tip


n fereastra Properties, etichetai controlul, setnd
proprietatea Text la valoarea Excursii.

GroupBox.

6.

Din Toolbox, tragei cu mouse-ul pe suprafaa primului GroupBox, nc


dou controale de tip GroupBox. n fereastra Properties, selectai-le pe
rnd i etichetai-le astfel: Tara, respectiv Transport.

152

Partea a Il-a. Programare Windows cu Visual C# Express Edition

7.

Pe suprafaa groupbox-ului cu numele Tara, aducei din Toolbox cinci


radio butoane. Selectai-le pe rnd i din fereastra Properties setai-le
proprietile Text (etichetele) la valorile: Austria, Grecia, Frana, Italia,
Germania.

8.

Pe suprafaa groupbox-ului cu numele Transport, aducei din Toolbox


dou butoane de validare. Selectai-le pe rnd i din fereastra Properties
setai-le proprietile Text (etichetele) la valorile: Avionul, respectiv
Balonul.

9.

Pe suprafaa groupbox-ului cu eticheta Excursii, aducei dou butoane.


Selectai primul buton i setai proprieatea Text la valoarea &Verifica.
Ampersandul are ca efect sublinierea caracterului care i urmeaz,
informnd userul c poate s acceseze butonul de la tastatur cu
combinaia: Alt + litera subliniat. Selectai cel de-al doilea buton i setai-i
proprietatea Text la valoarea &Ieire.

1II3I
Excursii
Tara

Transport

Austria

I ! Avionul

Grecia

[~~l Balonul

Frana

Italia

Germania

Verifica
Ieire

10. Facei dublu click pe butonul Verifica, pentru a trata evenimentul Click. n
handler-ul de eveniment, scriei codul evideniat cu bold:
private void buttonl_Click(object sender,
EventArgs e)

Capitolul 7.

Controalele Windows Forms

153

{
string msg = "Vom pleca in ";
// Verific care dintre butoanele radio e apsat
if (radioButtonl.Checked)
msg += radioButtonl.Text;
if (radioButton2.Checked)
msg += radioButton2.Text;
if (radioButton3.Checked)
msg += radioButton3.Text;
if (radioButton4.Checked)
msg += radioButton4.Text;
if (radioButton5.Checked)
msg += radioButton5.Text;
// Verific starea butoanelor de validare
bool firstDest = false;
if (checkBoxl.Checked)

{
msg += " cu " + checkBoxl.Text;
firstDest = true;

}
if (checkBox2.Checked)
if (firstDest)
msg += " si cu " + checkBox2.Text;
else
msg += " cu " + checkBox2.Text;
// Afieaz mesajul
MessageBox.Show(msg + " !");
// Restablete starea iniial
checkBoxl.Checked = false;
checkBox2.Checked = false;
radioButtonl.Checked = true;

1
11. Facei dublu click pe butonul Ieire, pentru tratarea evenimentului Click. n
Editorul de Cod vei scrie:
private void button2_Click(object sender, EventArgs e)

{
Application.Exit(); // Ieire din aplicaie

}
12. Rulai aplicaia cu F5 sau acionai butonul
La rulare, obinei:

din Standard Toolbar.

154

Partea a Il-a. Programare Windows cu Visual C# Express Edition

Excursii
T ara

T ransport

Austria

Avionul

Grecia

Balonul

Frana

Italia

Germania

Verifica

Ieire

Controlul TextBox
Platforma .NET ofer dou controale pentru editare de text: TextBox i
RichTextBox. Ambele clase deriv din clasa TextBoxBase. TextBox este un
control cu mai puine faciliti dect RichTextBox, ns este foarte util pentru
introducerea de date mici ca dimensiuni de la tastatur.

Principalii membri ai clasei TextBox


De la clasa printe TextBoxBase, motenete proprieti i metode pentru
manipularea textului, cum este selectarea textului, copiere, tiere i lipire din
clipboard, ca i un mare numr de evenimente. Descriem o parte dintre membrii
clasei.
Proprieti :
Multiline
AcceptsReturn

PassworChar
Text

- Returneaz sau seteaz o valoare boolean care indic


dac text box-ul poate avea mai multe linii
- Returneaz sau seteaz o valoare care indic dac la
apsarea Enter ntr-un TextBox multilinie se va trece la
linie nou sau se activeaz butonul implict al formei
- Returneaz sau seteaz un caracter folosit s mascheze
parola
- Returneaz sau modific textul n control

Metode:
C o p y ()
Paste()

Copiaz textul selectat n Clipboard


Lipete n control coninutul Clipboard-ului

Capitolul 7.
Cut ()
Clear ()
Select()
SetBounds()

Undo()

Controalele Windows Forms

155

Mut textul selectat n Clipboard


terge textul din control
Selecteaz un interval de text n control
Seteaz limitele controlului, la locaia i la dimeniunile
specificate
Anuleaz ultima operaie efectuat n text box

Evenimente:
-

Click
GotFocus
Leave
TextChanged

Se declaneaz
Se declaneaz
Se declaneaz
Se declaneaz

la click n control
cnd controlul primete focusul
cnd focusul prsete controlul
cnd proprietatea Text se schimb.

Aplicaia T extB o xE xam p le


Proiectul urmtor relev cteva dintre caracteristicile controlului TextBox.
1.

Creai un proiect de tip Windows Forms Application, cu numele


TextBoxExample.

2.

Din Toolbox, plasai cu mouse-ul pe suprafaa formei trei controale de tip


Labei, trei controale de tip TextBox i un buton, apoi aranjai-le aa ca n
figur:

ID-lit

Parola:

L ..................... ............

r------------------- ---------- 1
CNP:

| Autentificare |

3.

Selectai primul control de tip TextBox. Din fereastra Properties setai


proprietatea Name la valoarea idTextBox. Setai n acelai mod pentru al
doilea control proprietatea Name la valoarea parolaTextBox i
cnpTextBox pentru al treilea control de tip TextBox. Pentru eticheta
CNP, setai proprietatea Name la valoarea cnpLabel, iar pentru buton,
autentifButton.

156 Partea a II-a. Programare Windows cu Visual C# Express Edition


4.

Iniial, numai primul cmp text este activ, celelalte dou fiind dezactivate,
n acest scop se utilizeaz proprietatea Enabled. Dorim ca nc de la
apariia formei controalele parolaTextBox i cnpTextBox s fie
dezactivate. Pentru aceasta, vom scrie codul necesar n constructorul
formei. Selectai forma, apoi n Properties setai cmpul Name la valoarea
TextBoxEx. n felul acesta, ai modificat numele clasei formei, care iniial
era Forml. Facei click drept n SolutionExplorer pe numele formei i
alegei View Code. n constructorul clasei introducei urmtoarele:
public TextBoxEx()

// Constructorul formei

{
InitializeComponent();
// Caracterul
mascheaz parola
parolaTextBox.PasswordChar =
// Controlul de tip TextBox pentru parol
// este iniial vizibil, dar dezactivat
parolaTextBox.Enabled = false;
// Eticheta i TextBox-ul pentru CNP, ca i
// butonul Aut en tificare sunt iniial invizibile
cnpLabel.Visible
= false;
cnpTextBox.Visible = false;
autentifButton.Visible = false;

}
5.

Pentru testarea validitii


PreviewKeyDown:

ID-ului

introdus,

tratai

evenimentul

private void idTextBox_PreviewKeyDown(object sender,


PreviewKeyDownEventArgs e)

{
// Dac tasta apsat este Tab
if (e.KeyCode == Keys.Tab)
if (idTextBox.Text == "ionel")
// ID corect, activm cmpul pentru parol
parolaTextBox.Enabled = true;
else
MessageBox.Show("Utilizatorul nu exista!");

}
6. Tratai evenimentul PreviewKeyDown pentru verificarea parolei:
private void parolaTextBox_PreviewKeyDown
(object sender, PreviewKeyDownEventArgs e)

{
// Dac tasta apsat este Enter
if (e.KeyCode == Keys.Enter)

Capitolul 7.

Controalele Windows Forms

157

// Dac cmpul Text are valoarea "parola"


if (parolaTextBox.Text == "parola")

{
// Eticheta i controlul de tip text
// pentru CNP devin vizibile
cnpLabel.Visible = true;
cnpTextBox.Visible = true;
// TextBox-ul pentru CNP primete focusul
cnpTextBox.Focus();
// Butonul devine vizibil pe form
autentifButton.Visible = true;

}
else

{
MessageBox.Show("Parola incorecta!");
// terge textul din control
parolaTextBox.Clear();

}
}
}
7.

Pentru CNP, dorim s nu permitem introducerea altor caractere dect cifre.


Pentru aceasta, tratai evenimentul KeyPress i pentru toate caracterele
cu codul ASCII mai mic dect 48 sau mai mare dect 57, setai
proprietatea Handled la valoarea true. n felul acesta, evenimentul nu
mai este transmis controlului, iar caracterul apsat nu va mai fi afiat.
private void cnpTextBox_KeyPress(object sender,
KeyPressEventArgs e)
{
// Daca nu e cifr, nu se afieaz
if (e.KeyChar < 48 || e.KeyChar > 57)
e .Handled = true;

}
8.

Tratai evenimentul Click pentru butonul Autentificare. Dublu click pe buton


n Form Designer. Vei cere ca numrul total de cifre s fie 13:
private void autentifButton_Click(object sender,
EventArgs e)

{
// Dac lungimea CNP este incorect
if (cnpTextBox.Text.Length != 13)

{
MessageBox.Show("CNP incorect!");
// Se terge textul din control
cnpTextBox.Clear();

158

Partea a II-a. Programare Windows cu Visual C# Express Edition


else
MessageBox.Show("Autentificare cu succes!");

}
9.

Compilai i rulai cu F5.

Utilizatorul va completa primul cmp de text cu ID-ul loner, dup care va apsa
Tab, al doilea cmp cu parola parola, dup care apas Enter, iar in al treilea va
trece un numr format din 13 cifre, apoi va face click pe buton. Aplicaia verific
corectitudinea ID-ului, a parolei i a CNP-ului, ntr-un mod, desigur rudimentar, dar
suficient pentru ceea ce ne-am propus.
La rulare, nainte de introducerea parolei, avem:

Dup introducerea parolei parola i a unui ID format din 13 cifre:

Vei constat c acele caractere tastate care nu sunt cifre nu apar n


TextBox-ul pentru CNP.

De retinut:

Proprietatea PasswordChar stabilete caracterul care mascheaz textul


introdus de utilizator.

Capitolul 7.

Controalele Windows Forms

159

Proprietatile Enabled i Visible au valorile true sau false. Implicit


este true. Valoarea false pentru Enabled, aduce controlul n stare
inactiv, n timp ce false pentru Visible face controlul invizibil pe
form. Sunt caracteristici ale tuturor controalelor, ntruct se
motenenesc de la clasa de baz Control.
Evenimentele PreviewKeyDown sau KeyPress au fost alese i n
funcie de abilitile parametrilor handler-elor lor. De exemplu, obiectul
KeyPressEventArgs, parametru al metodei cnpTextBox_KeyPress
conine proprietatea KeyChar, necesar identificrii codului ASCII al
caracterului introdus.
Metoda Focus (), motenit de la clasa Control, seteaz focusul pe
controlul curent.

ECemente de StiC
Este recomandabil ca n aplicaiile n care folosii mai multe controale, s
introducei propriile nume pentru referine i tipuri. Numele trebuie s fie sugestive,
adic s indice menirea i tipul controlului. Exemplu: idTextBox,
parolaTextBox, etc. Numele claselor trebuie s nceap cu liter mare, de
exemplu TextBoxExample. n felul acesta vei distinge uor referinele i tipurile.

Focusul Controalelor
Controlul care primete intrrile de la tastatur este cel care are focusul'.
n oricare moment, un singur control al aplicaiei poate avea focusul. Schimbarea
focusului se face acionnd tastele sgei, tasta Tab, sau mouse-ul.
Ordinea n care controalele primesc focusul se stabilete programatic cu
ajutorul proprietii Tablndex. Controlul cu valoarea 0 pentru Tablndex primete
primul focusul. Visual C# 2008 permite stabilirea design time a focusului
controlalor. n meniul View, alegei Tab Order, apoi facei click pe etichete pentru
modificri.

-V:;

II
A re "fo c u s "

J N u are "fo c u s "


?

J N u are "fo c u s "

| N u are "fo c u s "

Figura 7.1 F o cu s

sta b ilit design tim e

Figura 7.2

F o cu su l la ru lare

160 Partea a II-a. Programare Windows cu Visual C# Express Edition

Chei de accesare a controalelor


n timpul rulrii, un control poate primi n mod direct focusul de la tastatur,
srind peste ordinea stabilit prin Tablndex, cu ajutorul unei combinaii de taste:
Alt + Caracter. Este nevoie pentru aceasta ca valoarea proprietatii Text s
conin caracterul ampersand. Pentru exemplul de mai jos, proprietatatea Text are
valorile: SButonl, B&uton2, SEticheta.
Label-urile au Tablndex, chiar dac ele nu pot primi focusul. Dac le
accesai cu o combinaie de chei, controlul care urmeaz etichetei n ordinea de
indexare, va primi focusul.
Dup combinaia Alt+E, ComboBox-ul va primi focusul:

Controalele invizibile sau cele dezactivate nu pot fi accesate cu tasta Tab, i nu pot
primi focusul, chiar dac li s-a asociat un index de tabulare design time sau run
time.

Probleme propuse
1.

Realizai o aplicaie care folosete un text box ca editor de text. Explorai


proprietile clasei TextBox i testai-le pentru acest control (Exemplu:
culoarea fontului, dimensiune, culoare backgound, etc).
2. Realizai o aplicaie care utilizeaz un TextBox pentru introducerea
textului. La fiecare caracter introdus, culoarea fundalului i a textului
trebuie s se schimbe (alegei cte o list de culori complementare pentru
text i fundal, care se vor repeta ciclic).
3. Realizai un mic proiect a crui fereastr reprezint un formular care
trebuie completat de cte un elev, atunci cnd se nscrie la facultate.
Pentru preluarea datelor, se vor utiliza controale de tip TextBox,
CheckBox i RadioButton. La apsarea unui buton, toate datele
intruduse se vor lista ntr-un control de tip TextBox, ntr-o formatare aleas
de dumneavoastr.
4. Creai o aplicaie care preia adresa si numrul de telefon ale unei
persoane (introduse n controale de tip text diferite) i afieaz ntr-un
MessageBox toate informaiile culese.
5. Implementai o aplicaie care preia o comand de produse efectuat de
ctre un client i afieaz toate elemente sale

Capitolul 7.

Controalele Windows Forms

161

Controalele MenuStrip i ContextMenuStrip


Meniurile sunt controale familiare n peisajul aplicaiilor de zi cu zi. De
exemplu, utilitarul clasic Notepad are un meniu din care utilizatorul poate seta
riverse aciuni de formatare a textului sau de editare. Cu ajutorul controlului de tip
:ontainer MenuStrip se pot crea deosebit de uor asemenea meniuri.
Meniurile de context definite cu ContextMenuStrip se acceseaz cu click
crept i sunt folosite deseori n editare de text sau oriunde dorii s avei acces
rapid ia anumite opiuni, cum ar fi Cut, Copy, Paste. Un meniu contextual se
asigneaz ntotdeauna unui control, acelui control pe care facei click drept.

Principalii membri ai clasei MenuStrip


Clasa este bogat n proprieti, metode i evenimente. Din fericire, nu avei
~evoie dect extrem de rar s modificai valorile implicite ale proprietilor. De
asemenea, din mulimea de evenimente, tratai de regul doar evenimentul Click.
Urmeaz o prezentare selectiv a membrilor:
Proprieti :
-

Anchor

Backgrounglmage
1ClientSize

ContextMenu
Text

Determin modul n care se redimensioneaz controlul


n raport cu containerul su.
Returneaz sau seteaz imaginea afiat n control
Returneaz sau seteaz nlimea i limea zonei
client a controlului.
Seteaz meniul de context asociat
Reprezint textul asociat controlului

Metode:
FindForm()

Hide ()
Show()

Returneaz o referin la forma pe care se gsete


controlul
Ascunde controlul
Afieaz controlul

Evenimente:

C l ic k
MenuActivate
iLeave
TextChanged

Se declaneaz la click n control


Se declaneaz cnd utilizatorul acceseaz meniul cu
tastatura sau mouse-ul
Se declaneaz cnd focusul prsete controlul
Se declaneaz cnd proprietatea Text se schimb.

162 Partea a Il-a. Programare Windows cu Visual C# Express Edition

Aplicaia M e n u E x a m p le
Proiectul pe care l vom realiza pentru acomodarea cu cele dou controale
implementeaz:
Un editor de text rudimentar cu ajutorul unui control TextBox.
* Operaiile cut/copy/paste . Aceste sunt accesibile att dintr-un meniu ct
i dintr-un meniu contextual.
Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


MenuExample.

2.

Din Toolbox tragei cu ajutorul mouse-ului un control MenuStrip pe


suprafaa formei.

3.

Facei click pe caseta controlului, acolo unde scrie Type Here, i creai un
prim meniu numit Fiier, cu opiunile Nou i Ieire:

4.

Creai un al doilea meniu cu numele Editare i opiunile Copiaza,


Decupeaz i Lipete:

Capitolul 7.
5.

Controalele Windows Forms

163

Din Toolbox alegei un contrlol TextBox i plasai-l pe suprafaa formei.

6. Setai pentru TextBox proprietatea Multiline la true. Acest lucru se poate

face din Properties sau mai simplu cu ajutorul meniului contextual care
apare prin click pe sgeata din colul dreapta sus a controlului:

7.

Din Toolbox tragei pe suprafaa ferestrei aplicaiei un control de tip


ContextMenuStrip. Selectai controlul i introducei opiunile: Copiaza,
Decupeaz, Lipete:

8.

Acum vei asigna meniul de context controlului TextBox. Selectai controlul


TextBox i n Properties atribuii proprietii ContextMenuStrip valoarea
contextMenuStripl , adic referina la obiectul de tip meniu contextual
al aplicaiei:

164 Partea a Il-a. Programare Windows cu Visual C# Express Edition


CharacterCasing

B M

Normal

contextM enuStH v

El (Applicationsetting!
]j

El (DataBindings)

9. n continuare, vei trata evenimentul Click pentru fiecare dintre opiunile


meniului i ale meniului contextual:
a. n meniul Fiier, dublu click pe opiunea Nou. n corpul metodei
handler, scriei: textBoxl.Clear ()
n felul acesta, tergei
textul din controlul TextBox.
b. n meniul Fiier, dublu click pe opiunea Ieire. n corpul metodei
handler, scriei: Application.E xit ()
Astfel se iese din
aplicaie.
c. n meniul Editare, dublu click pe opiunea Copiaza. n corpul
metodei handler, scriei: textBoxl.Copy () ;. Metoda copiaz n
clipboard textul selectat.
d. n meniul Editare, dublu click pe opiunea Decupeaz. n corpul
metodei handler, scriei: textBoxl.Cut ()
Metoda terge din
control textul selectat i l copiaz n clipboard.
e. n meniul Editare, dublu click pe opiunea Lipete. n corpul
metodei handler, scriei: textBoxl.Paste () ;. Metoda scrie n
control textul memorat n clipboard.
f. Selectai meniul contextual din bara gri, din partea de jos a Form
Designer-ului. Vei face dublu click pe fiecare opiune a meniului
contextual i vei trata evenimentul Click n aceeai manier n
care ai procedat cu opiunile Copiaz, Decupeaz i Lipete ale
meniului aplicaiei.
10. Compilai i rulai cu F5.

Fiier

Editare

n orau-n care plou de trei ori pe sptmn


Un btrn i o btrn
Dou jucrii stricate

Decupeaz
Lipete

Capitolul 7.

Controalele Windows Forms

165

Forme
O form este un tip special de control care reprezint o fereastr. Este
folosit ca suport pentru alte controale. Prin setarea proprietilor se obin diferite
tipuri de ferestre, avnd diverse dimensiuni, aparene, stiluri i culori. Formele sunt
nstane ale clasei Form.

Principalii membri ai clasei Form


Din galeria de membrii ai acestei clase, prezentm:
Proprieti :
ClientSize

DialogResult

Modal

Size

Returneaz i seteaz suprafaa util a formei, pe care se


pot plasa controale sau se poate desena.
Seteaz valoarea pe care o returneaz o form cnd
funcioneaz ca dialog modal.
Stabilete dac o form se afieaz sau nu ca dialog
modal.
Returneaz sau modific dimensiunie formei.

A c t i v a t e ()
Close ()

Activeaz forma i i transfer focosul


nchide forma

Invalidate()

Show()
ShowDialog()
Text

Invalideaz ntreaga suprafa


cauzeaz redesenarea ei
Afieaz forma
Afieaz forma ca dialog modal
Specific un text n bara de titlu

Metode:

formei,

fapt

care

Evenimente:
Closing
Load

Se declaneaz cnd forma se nchide


Se declaneaz nainte ca forma s fie afiat pentru
prima oar.

166 Partea a II-a. Programare Windows cu Visual C# Express Edition

Crearea formelor
1. Crearea programatic a formelor
n mod programatic, o form se creaz foarte simplu:
Form f = new Form();
f.Show();

/ / S e instaniaz forma
// Se afieaz

O metod obinuit de creare a unei forme este de a defini o clas derivat din
clasa Form:
class FormaMea : Form
{
public FormaMea() // Constructorul clasei
{

}
// Ali membri ai clasei (cmpuri, proprieti, metode)

}
Dintr-o alt metod a aplicaei, instaniai forma:
FormaMea f = new FormaMea();
f .Show();

2.

Crearea formelor cu ajutorul Form Designer-ului

La crearea unui nou proiect de tip Windows Forms, mediul integrat genereaz
o clas cu numele implicit Forml, iar aceast clas se instaniaz n Main ():
Application.Run(new Forml());

Putei aduga proiectului oricte alte forme, n felul urmtor:


n Solution Explorer, acionai click drept pe numele proiectului, alegei Add, apoi
Windows Form... :
J Solution 'FormExample' (1 project)
F orm E n a r
ffl-- O ii Proper |fi| Build
ffl-

Refere

Rebuild

ffl- S B Form l!
!

ffl-

Form2|

I New Item ...

;.~~t
: 23
jij

Publish,,,
Add

Existing Item ,,,

Add Reference.,,

New Folder

Add Service Reference.,,

Windows Form .,,

Set as Startup Project

User C ontrol,.,

Debug

Ca variant alternativ, click drept pe numele proiectului, alegei Add, apoi New
Item....

Capitolul 1.

Controalele Windows Forms

167

n fereastra Add New Item - [nume proiect] selectai iconul Windows Form i
introducei un nume pentru noua form:

Dialoguri modale i dialoguri nemodale


Una dintre forme este fereastra de baz a aplicaiei. Celelalte forme
reprezint ferestre care pot fi fcute s apar ia un moment dat.

Dialoguri modale
Anumite tipuri de ferestre se prezint ca dialoguri cu utilizatorul. Acesta
introduce date n controale, pe care apoi le valideaz sau nu (apsnd de exemplu
butoanele OK sau Cancel). Acest tip de fereastr dialog nu permite utilizatorului s
acceseze alte ferestre ale aplicaiei pn cnd dialogul nu este nchis. De
exemplu, n Microsoft Word, cnd alegei Open n meniul File, se deschide un
dialog care v cere s alegei un fiier. Fereastra blocheaz aplicaia i nu putei
ntreprinde nici o alt aciune n editor, pn n momentul n care ai nchis dialogul.
Un asemenea tip de dialog, se numete dialog modal.
Un dialog modal este o form care se deschide cu metoda showDialog ():
class Forma : Form

{
// membrii clasei

1
Forma f = new Forma();
f .ShowDialog();

168 Partea a Il-a. Programare Windows cu Visual C# Express Edition

Aplicaia D ia lo g M o d a l
Realizm un proiect de tip consol care lanseaz o form ca dialog modal.
Urmai paii:
1.

n meniul File, alegei New Project.

2.

n panoul dialogului New Project selectai Empty Project, iar n caseta text
Name, introducei numele proiectului: DialogModal.

3.

n Solution Explorer, executai click drept pe numele proiectului i alegei


Add, apoi New Item....

4. n dialogul Add New Item, selectai iconul Code File, apoi n caseta Name,
introducei numele fiierului: Modal.cs.
5.

Fiierul Modal.cs se deschide n Editorul de Cod. Introducei codul:


u s i n g System;
u s i n g S y s t e m . W i n d o w s .F o r m s ;
class Forma

: Form

{
}
class P o gram

{
p u b l i c static v o i d Main()

{
Forma f = new F o r m a Q ;

// Instaniere

// Text n bara de titlu


f.Text = "Dialog Modal";

// Dialogul modal devine vizibil


f .S h o w D i a l o g ();
A p p l i c a t i o n .R u n () ;

// Lanseaz aplicaia

}
}
6.

nc nu putem compila, pentru c proiectul de tip consol nu introduce n


mod automat referine la bibliotecile dinamice .NET care implementeaz
spaiile de nume System.Windows i System.Windows.Forms. Vom
aduce aceste referine astfel: n Solution Explorer, click drept pe folderul

References:

Capitolul 7.
iW ; I I 181 g 8

UlSjl

:jp

Controalele Windows Forms


as

Stfi

A J

H-

( 3 Solution 'DialogModair (1 project)


t

169

. 5 ! D ia l o g M o d a l l
a -

________ _________________ ____________

i:J Modal,cs i

Add Reference,,,
Add Service Reference..

7.

n dialogul A d d Reference, selectai pe tab-ui .NET intrarea System, apoi


repetai
pasul
6
i
adugai
o
referin
la
bibliotecile

System.Windows.Forms:

Component Name -*

System.Transactions
System,Web
System, Web.Extensions
System. Web, Extensions. Design
System.Web.Mobile
System. Web. RegularExpressions
; System.Web.Services
System,Windows,Forms

System, Windows, Presentation
System. Workflow, Activities
System. Workflow.ComponentModel
System. W orkflow. Runtime
System. WorkflowServices
System, Xml
i Sv^hftm.Xml.l inn
...
;
;:.
_ i;
'..... ; .

Version

Runtime

|.A 1

2.0.0.0
2.0.0.0
3.5.0.0
3,5.0.0
2,0.0.0
2.0,0.0
2.0.0.0

v2 ,0.50727
v2 .0,50727
v2 ,0.50727
v2 .0.50727
v2 .0.50727
V2.0.50727
v 2 .0.50727

j i

ji

M
i g
3.5.0,0
3.0,0,0
3.0.0.0
3,0,0,0
3.5.0.0
2,0.0.0
3.5.0.0

v 2 ,0.50727
V2.0.50727
v 2 .0.50727
v 2 .0.50727
v 2 .0.50727
v 2 .0.50727
v ? .n .50727

c
c
C 5 li
c~

c
c
r iL
>

8.

c
c
c
c
c

0K....... l l

Compilai i rulai aplicaia cu F5. La rulare obinei:

CanCel

170

Partea a II-a. Programare Windows cu Visual C# Express Edition

Dialoguri nemodale
Dialogurile nemodale sunt ferestre care nu ntrerup execuia aplicaiei. Un
dialog nemodal nu mpiedic utilizatorul s execute aciuni n alte ferestre ale
aplicaiei. Se utilizeaz n special ca bare de instrumente. Gndii-v la toolboxurile din Paint sau Word, sau chiar Toolbox din Visual C# Express 2008.
Afiarea se face cu metoda Show(); La nchiderea unei forme cu Close (),
toi membrii clasei (de exemplu controalele de pe form) se distrug.
Ca exerciiu de creare programatic a unui dialog nemodal, reluai toi paii
aplicaiei DialogModal (redenumii ca DialogNemodal) i facei o singur modificare
n cod: nlocuii f .ShowDialog () cu f .Show ();

Aplicaia M o d a lD ia lo g E x a m p le
Descrierea aplicaiei:
>
>
>

Construiete un dialog modal care se deschide la apsarea unui buton ai


formei printe a aplicaiei.
Datele pe care utilizatorul le introduce ntr-un control al dialogului moda!
se transfer unui control al clasei printe.
Anticipeaz modul de utilizare a unui control ListBox.

Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


ModalDialogexample.

2.

Din Toolbox plasai pe form cu ajutorul mouse-ului un control de tip


ListBox i dou butoane. Setai proprietatea Text pentru celor dou
butoane astfel:

3. Adugai o nou form proiectului. n Solution Explorer, click dreapta pe


numele proiectului, alegei Add, apoi Windows Form... i validai cu OK.

Capitolul 7.
4.

Controalele Windows Forms

171

n Solution Explorer, dublu click pe numele Form2 (n cazul n care nu ai


redenumit noua form).

5. Aducei din Toolbox un control TextBox i un buton, ca n figur:

6.

n Solution Explorer, acionai click drept pe numele Form2, apoi alegei


View Code. n clasa Form2 definii membrii:
// Cmp care reine textul introdus n textBoxl
private string item;
// Proprietate care returneaz valoarea textului
public string Item
{
get { return item; }

1
7.

Tratm evenimentul Click generat la apsarea butonului OK. Acionai


dublu click pe buton. Completai codul evideniat n Bold:
private void buttonl_Click(object sender, EventArgs e)

{
// Salvm textul introdus n control,
item = textBoxl.Text.Trim();
// nchidem forma Form2.
Close();

}
8. Dorim ca Form2 s se nchid i la apsarea tastei Enter. Tratm

evenimentul KeyDown pentru controlul TextBox. Selectai controlul. n


fereastra Properties apsai butonul Events (fulgerul) i facei dublu click
pe evenimentul KeyDown. Introducei codul:
private void textBoxl_KeyDown(object sender,
KeyEventArgs e)

{
// Dac tasta apsat are codul tastei Enter
if (e.KeyCode == Keys.Enter)

{
item = textBoxl.Text.Trim(); // Memorm textul
Close ();
// nchidem forma

}
}

172 Partea a Il-a. Programare Windows cu Visual C# Express Edition


9. n scopul de a ni se permite s accesm proprietatea item a clasei Form2
din metodele clasei Forml, modelm o relaie de coninere (containment).
Definim n Forml un cmp privat, o referin la Form2. n Solution
Explorer, click drept pe Forml i alegei View Code. n fiierul Forml.cs.
n clasa Forml, scriei:
private Form2 f;

10. Tratm evenimentul Click care se genereaz la click pe butonul Adug.


aflat pe forma Forml. n Solution Explorer, facei dublu click Form2, apo
n Form Designer acionai dublu click pe butonul Adug. n corpul
handler-ului introducei codul:
private void buttonl__Click (object sender, EventArgs e)

{
f = new Form2();

// Crem forma

f .ShowDialog();
if ( f.Item != "")

// Afim dialogul modal


// Dac exist text

{
// Adugm itemul n listBoxl
listBoxl.Items.Add(f.Item);

}
}
11. Pentru ieire din aplicaie, facei dublu click pe butonul Ieire. n corpul
handler-ului evenimentului Click, scriei:
Application.Exit();

// Ieire din aplicaie

12. Compilai i lansai n execuie cu F5.


La rulare, prin apsarea butonului Adug, se deschide dialogul modal Form2.
Cnd se apas OK sau Enter, se nchide dialogul Form2, iar textul introdus
apare ca nou item n controlul ListBox de pe Forml.

Capitolul 7.

Controalele Windows Forms

173

Mo:

Metoda T rim () a clasei s t r i n g nltur caracterele albe de la nceputul


i sfritul stringului.
Metoda Add() din apelul listBoxl.items .Add(f. item) ; adaug un
item ntr-un controlul referit de listBoxl.
Metoda Close () nchide forma.

IMPORTANT!
Cnd apelai Close () pentru un dialog modal, fereastra nu se distruge ci
revine invizibil. Aceasta, deoarece dup nchiderea ferestrei, avei de regul
-evoie de membrii clasei, ca n aplicaia de fa:
f.ShowDialog();
// Afim dialogul modal
/ n acest punct fereastra este nchis!
f.Item exist i dup nchiderea dialogului, deoarece
dialogul (obiectul de tip Form2) nu este distrus,
ci numai ascuns,
if ( f.Item != "")
listBoxl.Items.Add(f.Item);

De retinut:

Dialogurile modale se afieaz cu metoda ShowDialog (), iar cele


nemodale cu metoda Show().
Afiarea unei forme cu Show() se poate face alternativ prin setarea
proprietii Visible la valoare true. Ascunderea formei se poate face
i prin setarea proprietii Hide la false.
La nchiderea formei cu Close (), dialogurile nemodale se distrug (se
distruge instana clasei).
Cnd o form este afiat ca dialog modal, apelul metodei Close () sau
un click pe butonul Close (butonul cu un x n colul dreapta sus a formei)
nu distruge forma ci o ascunde, ea putnd fi fcut vizibil ulterior.
Codul care urmeaz apelului ShowDialog () nu se execut pn cnd
forma se nchide. Dup nchiderea dialogului modal, putei utiliza n
continuare referina la clas i toi membrii clasei.

Butoane de validare

d a t e l o r

Cnd nchide un dialog modal, utilizatorul ar trebui s aib cel puin dou
opiuni: s pstreze datele pe care le-a introdus n controale sau s renune la ele.
3entru aceasta, are nevoie de dou butoane, s le spunem OK i Cancel. Evident,

174 Partea a Il-a. Programare Windows cu Visual C# Express Edition


nu este suficient s etichetai cele dou butoane astfel ca s lucreze n moc
adecvat. Ca s joace rolurile dorite, se seteaz proprietatea DialogResult a
clasei Button, astfel:
Button bl
Button b2
bl.Text =
b2.Text =

= new Button();
= new Button();
"OK";
// Poate fi i alt etichet
"Cancel";
// Poate fi i alt etichet

// Setm bl s returneze DialogResult.OK la click


bl.DialogResult = DialogResult.OK;
// Setm b2 s returneze DialogResult.Cancel la click
b2.Dialogresult = DialogResult.Cancel;

n felul acesta, bl va fi butonul OK al formei, iarb2 cel de nchidere cu Cancel.


DialogResult este o enumerare a crei membrii sunt: OK, Cancel, Abort.
Retry, None, Ignore, Yes, No.
Cum detectm n cod faptul c o form a fost nchis cu OK sau cu Cancel
? Vom analiza valoarea de retur a metodei ShowDialogO , care este tocmai una
dintre valorile membrilor enumerrii i anume, valoarea returnat de butonul
apsat. Secvena standard este:
DialogResult rez = f .ShowDialog();
switch (rez)

{
case DialogResult.OK :
// Ceea ce dorii s se execute dac s-a ieit cu OK
break;
case DialogResult.Cancel :
// Cod care se execut n caz c s-a acionat Cancel
break;

>
De ce vrem s tim dac forma a fost nchis cu OK sau cu Cancel ? Foarte
simplu: pentru c dac nchidei cu OK, forma este doar ascuns, i o putei utiliza
n continuare, ca i datele introduse, n vreme ce dac ai nchis cu Cancel, forma
se distruge mpreun cu toate controalele i datele reinute n membrii clasei.
Pentru edificare, vom realiza un mic proiect de tip Windows Forms.

Aplicaia O kC an ce!
Aplicaia are dou butoane, cu etichetele OK i Cancel. Primului buton i se
atribuie rolul de validare a datelor, iar celuilalt de renunare. Amndou nchid
forma. Se afieaz cte un message box la nchiderea formei pentru fiecare caz.

Capitolul 7.

Controalele Windows Forms

175

Creai un nou proiect de tip Windows Forms Application, cu numele


OkCancel.
I

Din Toolbox plasai pe form un buton. Atribuii proprietii Text valoarea


Deschide dialogul modal.

3. Adugai o form nou proiectului: n Solution Explorer, click dreapta pe


numele proiectului, alegei Add, apoi Windows Form. Clasa formei se va
numi Form2.
4. n Solution Explorer, facei dublu click pe Form2. Plasai pe suprafaa
acestei forme dou butoane, pentru care setai textele OK i Cancel.
5. Tratm evenimentul Load pentru Form2, pentru a putea seta proprietile
DialogResult pentru cele dou butoane. Desigur c putei face acest
lucru i din fereastra Properties. Executai dublu click pe suprafaa formei.
Scriei codul:
private void Form2_Load(object sender, EventArgs e)

{
// Seteaz buttonl s returneze OK la click
buttonl.DialogResult = DialogResult.OK;
// Seteaz button2 s returneze Cancel la click
button2.DialogResult = DialogResult.Cancel;

}
6. Tratm evenimentul Click pentru butonul formei Forml. Facei dublu click
pe buton. n metoda handler, introducei codul evideniat n Bold:
private void buttonl_Click(object sender, EventArgs e)

{
Form2 f = new Form2 () ;
DialogResult rez = .ShowDialog();
switch (rez)

{
case DialogResult.OK;
MessageBox.Show("Dialog inchis cu OK");
break;

Partea a Il-a. Programare Windows cu Visual C# Express Edition

176

case DialogResult.Cancel:
MessageBox.Show("Dialog inchis cu Cancel");
break;

}
1
La execuie, nainte de nchiderea Form2, avem:
gjj

Dup nchiderea formei cu OK:

De rein ut:

Putei desemna butoane care returneaz valori egale cu cele ale unor
membri ai enumerrii DialogResult.
Valoarea returnat la acionarea click asupra unui asemenea buton este
aceeai pe care o returneaz metoda ShowDialogO . Acest lucru
permite ca ulterior nchiderii formei s se dirijeze fluxul de execuie a,
programului n funcie de rezultatul ntors de form.

Probleme propuse
1.

Testai metoda MessageBox. Show ( t e x t ,


toate butoanele diponibile.

titlu,

butoane) cu

Capitolul 7.

Controalele Windows Forms

177

2. Testai metoda MessageBox.Show() n versiunea cu 4 parametri,


folosind pe rnd toate butoanele i toate iconurile disponibile.
3,

Realizai o aplicaie care deschide un dialog modal la acionarea unui


buton de pe forma principal. Dialogul modal conine un formular realizat
n principal cu controale text box, n care se rein date personale despre
clienii unei firme. La nchiderea dialogului modal cu OK, datele se
afieaz ntr-un format ales de dumneavoastr, ntr-un control text box
de pe forma printe. Dac dialogul modal s-a nchis cu butonul Cancel,
atunci nu se salveaz datele.

Dialoguri predefinite
.NET ofer cteva dialoguri predefinite pe care le putei invoca n aplicaii.
Dialogurile sunt forme. Cnd n Notepad sau Microsoft Word acionai File ->
Open, File -> Save As sau File -> Page Setup, invocai de fapt unul dintre
dialogurile standard Windows.
Clasele .NET care reprezint dialogurile predefinite sunt: MessageBox,
OpenFileDiaiog, SaveFileDialog, FontDialog, ColorDialog, PageSetupDialog,
PrintDialog i PrintPreviewDialog.
Toate aceste dialoguri sunt dialoguri modale.

Descrierea dialogurilor predefinite


MessageBox este cel mai comun dialog predefinit. Clasa definete metoda
static show () n mai multe versiuni. Cea mai simpl versiune, cu un singur
parametru, a fost deja folosit n aceast lucrare. n exemplu se apeleaz o
metod Show() cu patru parametri:
MessageBox.Show("Copierea nu a putut fi realizat!",
"Eroare de copiere",
MessageBoxButtons.RetryCancel,
MessageBoxIcon.Exclamation);

Efectul pe ecran este :

Icon-urile pe care le poate afia un message box sunt:

178

Partea a Il-a. Programare Windows cu Visual C# Express Edition

Asterisc, Error, Exclamation, Hand, Information, None, Question, Stop i


Warning. Acetia sunt membrii ai enumerrii MessageBoxlcon, iar semnificaiia
lor este evident.
Butoanele pe care le poate afia un message box sunt: AbortRetrylgnore
(3 butoane), OK, OKCancel (2 butoane), YesNo (2 butoane), YesNoCancel (3
butoane). Aceste entiti sunt membri ai enumerrii MessageBoxButtons.
n aplicaia pe care o vom realiza n cadrul temei MDI - Multiple Document
Interface vom arta cum dai funcionalitate butoanelor de pe form.
OpenFileDialog motenete clasa FileDialog. Dialogul (forma) este o
instan a clasei. Permite utilizatorului s selecteze un fiier pentru a fi deschis.
Atenie, dialogul nu deschide fiierul! Acest lucru cere un mic efort de programare,
aa cum vom vedea n subcapitolul urmtor. Numele fiierului selectat se atribuie
n mod automat proprietii FileName. Formatul fiierelor care trebuie deschise se
stabilesc cu ajutorul proprietii Filter.
SaveAsDialog motenete clasa FileDialog. Dialogul este folosit n scopul
alegerii unei locaii pentru salvarea unui fiier. Dialogul nu salveaz fiierul.
Numele fiierului selectat se atribuie n mod automat proprietii FileName. Clasa
poate crea un nou fiier sau poate suprascrie unul existent.
FontDialog deriv din clasa CommonDialog. Utilizatorul poate alege un
font dintre cele instalate pe calculator prin simpla selectare cu mouse-ul.
PageSetupDialog are ca i clas de baz direct CommonDialog.
Utilizatorul poate stabili setri pentru pagin, cum arfi marginile, formatul, etc.
PrintDialog deriv din clasa CommonDialog. Dialogul permite alegerea
unei imprimante, setarea formatului de imprimare, alegerea unei poriuni de
document care va fi printat i invocarea imprimantei.
PrintPreviewDialog este derivat din clasa Form. Dialogul permite
examinarea unui document nainte de imprimare.
Indicaie:
Alegei un utilitar, cum este Microsoft Word i revedei toate aceste dialoguri,
accesndu-le pe rnd din meniul File. Merit s o facei, pentru c acum le vedei
cu ochii programatorului.
r

Afiarea dialogurilor predefinite


Dialogurile standard Windows sunt forme .NET. n plus, sunt dialoguri
modale. Aadar, afiarea lor se face cu ajutorul metodei ShowDialog():
Exemplu:
lat cum afiai dialogul OpenFileDialog:

Capitolul 7.

Controalele Windows Forms

179

if (openFileDialog.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care deschide fiierul
}
openFileDialog este o referin la un obiect de tip OpenFileDialog. Referina

se creaz n mod automat n momentul n care din Toolbox alegei un control


OpenFileDialog i l plasai pe suprafaa formei.
Valoarea de retur a metodei este egal cu unul dintre membrii enumerrii
DialogResult. Acetia sunt: OK, Cancel, Abort, Retry, None, Ignore, Yes, No.
Fiecreia dintre aceste valori i corespunde un buton pe suprafaa dialogului. n
mod implicit, dialogurile predefinite afieaz butoanele OK i Cancel, ns prin
setarea proprietilor corespunztoare ale dialogului, le putei afia i pe celelalte.
Codul de mai sus se interpreteaz astfel: ShowDialog () afieaz dialogul
OpenFileDialog. Dac utilizatorul apas butonul OK, atunci se execut codul
dintre acolade. Ce anume trebuie s scriei, vom vedea la seciunea Controlul
RichTextBox.
Pentru afiarea celorlalte controale predefinite, se procedeaz similar, cu
singura diferen c vei nlocui referina openFileDialog cu una dintre
referinele: saveFileDialog, printDialog, pageSetupDialog, etc.

Observaie:
Toate cele apte dialoguri predefinite sunt dialoguri modale, deoarece
utilizeaz metoda ShowDialog (). Un dialog modal ntrerupe aplicaia, iar
utilizatorul nu poate continua pn n momentul n care dialogul a fost nchis.

Ap Iici a D ia lo g u riP re d e fin ite


Proiectul pe care l propunem este o aplicaie cu un meniu din care
utilizatorul poate selecta opiuni de deschidere a dialogurilor predefinite. Pentru
unele dialoguri, se va scrie i cod suplimentar, mai ales referitor la setarea
proprietilor. Vestea bun este c vei scrie ntotdeauna aproape la fel atunci cnd
lucrai cu dialoguri predefinite.
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


DialoguriPredefinite.

2.

Din Toolbox plasai cu ajutorul mouse-ului un control MenuStrip pe


suprafaa formei.

3.

Creai un prim meniu numit Fiier, cu opiunile Deschide, Salveaza ca,


Setare pagina, Imprimare i Previzualizare:

180 Partea a ii- a . Programare Windows cu Visual C# Express Edition

Fiier | Format
|

Deschide

Salveasa ca
Setare pagina
Imprimare
Prevteualisare
j

Type Hei e

4.

Creai un al doilea submeniu numit Format, cu opiunile Font i Culori:

5.

Din Toolbox plasai pe suprafaa formei urmtoarele controale:


OpenFileDialog, SaveFileDialog, PageSetupDialog, PrintDialog,
PrintPreviewDialog, PrintDocument, FontDialog, ColorDialog. In frayul designerului de forme vei remarca imediat referinele la aceste obiecte,
care au fost adugate n cod.

6.

n continuare vei trata evenimentul Click pentru fiecare dintre opiunile


meniului. Facei dublu click pe opiunea Deschide. n handler-ul
evenimentului, scriei codul:
private void deschideToolStripMenuItem_Click
(object sender, EventArgs e)

{
// Titlul dialogului
openFileDialogl.Title = "Deschide Fiier";
// Seteaz tipurile de fiiere care apar
// n comhobox-ul "Files of Type"
openFileDialogl.Filter =
"Fiiere Rich Text (*.rtf)|*.rtf|Fiiere Text (*.txt)|*.txt";
/ / n combobox-ul File Name nu vrem s apar la
// deschiderea dialogului nici un nume de fiier
openFileDialogl.FileName = "";

Capitolul 7.

Controalele Windows Forms

181

// Directorul care se deschide n mod implicit


openFileDialogl.InitialDirectory = "MyDocuments";
// Afieaz-o atenionare dac utilizatorul
// specific un fiier care nu exist
openFileDialogl.CheckFileExists = true;
// Deschide dialogul OpenFileDialog
if (openFileDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care deschide fiierul

}
7.

Dublu click pe opiunea Salveaz ca. n metoda de tratare, scriei:


private void salveazaCaToolStripMenuItem_Click
(object sender, EventArgs e)

{
// Titlul dialogului
saveFileDialogl.Title = "Salveaza Fiierul";
// Extensia implicit de salvare a fiierelor
saveFileDialogl.DefaultExt = ".rtf";
// Atenionare dac ncercai s suprascriei
saveFileDialogl.OverwritePrompt = true;
// Deschide dialogul SaveFileDialog
if (saveFileDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care salveaz fiierul

}
8.

Dublu click pe opiunea Setare pagina. n metoda de tratare, scriei:


private void setarePaginaToolStripMenuItem_Click
(object sender, EventArgs e)

{
// Se preiau setrile din printDocumentl
pageSetupDialogl.Document = printDocumentl;
// Setrile de pagin
pageSetupDialogl.PageSettings =
printDocumentl.DefaultPageSettings;

182

Partea a Il-a. Programare Windows cu Visual C# Express Edition


// Diverse seciuni ale dialogului devin active sau
// inactive. De fapt, valoarea implicit a acestor
// proprieti este true
pageSetupDialogl.AllowMargins = true;
pageSetupDialogl.AllowPaper = true;
pageSetupDialogl.AllowOrientation = true;
pageSetupDialogl.AllowPrinter = true;
pageSetupDialogl.ShowNetwork = true;
pageSetupDialogl.EnableMetric = false;
pageSetupDialogl.ShowHelp = false;
// Se deschide dialogul i se preiau setrile
// de pagin n obiectul de tip PrintDocument
if (pageSetupDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)
printDocumentl.DefaultPageSettings =
pageSetupDialogl.PageSettings;

9.

}
Facei dublu click pe opiunea imprimare. n handler scriei codul:
private void imprimareToolStripMenuItem_Click
(object sender, EventArgs e)
// Se preiau setrile de printare din
// obiectul de tip PrintDocument
printDialogl.Document = printDocumentl;
// Se deschide dialogul PrintDialog
if (printDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Starteaz procesul de printare
printDocumentl.Print();
// Cod care transform documentul
// n imagine i l printeaz
//

...

}
}
10. Dublu click pe opiunea Previzualizare. n handler, scriei codul:
private void previzualizareToolStripMenuItem Click
(object sender, EventArgs e)

{
if (printPreviewDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care afieaz documentul in dialog

}
}

Capitolul 7.

Controalele Windows Forms

183

11. Dublu click pe opiunea Font. n handler-ul evenimentului, scriei codul:


private void fontToolStripMenuIteml_Click
(object sender, EventArgs e)

{
// Se deschide dialogul FontDialog
if (fontDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care reafieaz documentul cu
// fontul ales de utilizator

}
}
12. Dublu click pe opiunea Culori. n handler-ul evenimentului, scriei codul:
private void culoriToolStripMenuItem_Click
(object sender, EventArgs e)
// Se deschide dialogul ColorDialog
if (colorDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Cod care actualizeaz culorile in document

}
13. Compilai i rulai cu F5.

Basic colors:

m r r m r ss r
m r m m r~ m b h
m r
m M M u m

Custom colors:

Define Custom Colors


I

OK

||

Cancel

184 Partea a Il-a. Programare Windows cu Visual C# Express Edition

Comentarii:
Proprietatea Filter este comun dialogurilor OpenFileDialog i
SaveAsDialog, ntruct este motenit de la clasa de baz comun,
FileDialog. Caracterul ' | ' (pipe) delimiteaz tipurile de fiiere pe
care le putei selecta, dar i intrrile n combobox : "Fiiere Rich
Text (*.rtf)|*.rtf|Fiiere Text (*.txt)|*.txt";
Files of type:

| Fiiere R ich Text (".rtf)

Cancel

IFiiere Text f".txti

Dialogurile predefinite se afieaz cu metoda ShowDialog (), iar tipul


de retur al acestei metodei se analizeaz pentru a vedea dac
utilizatorul dorete s pstreze setrile pe care le-a fcut sau vrea s
renune la ele.
Reinei c OpenFileDialog nu deschide un fiier (document) ci numai
v permite s-l alegei. Pentru deschidere avei nevoie de un control
suplimentar, capabil s afieze coninutul fiierului, aa cum este un
TextBox sau un RichTextBox. Aceleai consideraii sunt valabile i
pentru celelalte dialoguri predefinite.

Not:
n ce privete printarea efectiv a unui document, aceasta se face prin
apelul metodei Print () a clasei PrintDocument. Clasa PrintDocument este
definit n spaiul de nume System.Drawing.Printing. Obiectul de tip
PrintDocument preia setrile de pagin stabilite de ctre utilizator n dialogul
PageSetupDialog, i trimite documentul la imprimant. Codul necesar poate fi
gsit n documentaia clasei PrintDocument sau n articole din MSDN (Microsoft
Developer Network).

Sfat practic
S avei n permanen deschis Helpul mediului integrat. Acolo gsii
imediat clasele cu care lucrai, cu descrierea complet a cmpurilor,
proprietilor, metodelor i evenimentelor lor, dar i cu exemple de cod care v
pot ajuta. Vei descoperi foarte repede membrii ai claselor care v pot fi utili.
Reamintim locaia Bibliotecii de Clase: Help -> Contents -> .NET
Framework SDK -> .NET Framework Class Library.

MDI - Multiple Document Interface


O aplicaie MDI se lanseaz cu o singur fereastr container care reprezint
ntreaga aplicaie.

Capitolul 7.

Controalele Windows Forms

185

n interiorul ferestrei container se pot deschide multiple ferestre child.


Gndii-v la Microsoft Word. Ferestrele interioare reprezint diferite documente pe
care utilizatorul le poate edita n acelai timp sau diferite vederi ale acelorai date.
Aplicaiile MDI difer de cele de tip SD1 (Single document interface) prin
aceea c SDI au o singur fereastr copil. Notepad este un asemenea exemplu.
Dac dorii s editai dou documente, trebuie s deschidei dou instane
Notepad.
Att fereastra printe ct i ferestrele copil sunt de fapt forme .NET. O form
devine container n momentul n care proprietatea isMdiContainer este setat
true.

Aplicaia M d iE x a m p le
Aplicaia implementeaz:
>
>
>
>

Deschiderea i nchiderea ferestrelor child.


Minimizarea i maximizarea ferestrelor.
Aranjarea ferestrelor.
Tratarea mesajului de atenionare la ieirea din aplicaie.

Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


MdiExample.

2.

Setai forma ca i container MDI. Pentru aceasta, n fereastra Properties


atribuii proprietii isMdiContainer valoare true.

3.

Din Toolbox plasai cu ajutorul mouse-ului un control MenuStrip pe


suprafaa formei.

4.

Creai un prim meniu numit File, cu opiunile New, Minimize, Maximize,


Close, Close All i Exit. Creai un al doilea meniu cu numele Window,
avnd opiunile: Tile i Cascade:

186

Partea a II-a. Programare Windows cu Visual C# Express Edition

5. Adugai n clasa Forml un cmp privat care contorizeaz numrul de


ferestre copil i o metod privat care creeaz o fereastr copil. Pentru
aceasta, acionai dublu click pe numele formei n Solution Explorer. n
fiierul Forml.cs, n clasa Forml, scriei codul:
private int nr = 0;

// Numrul de ferestre child

private void CreateChild()

{
// Crem o forma child.
Form f = new Form();
nr++ ;
// Textul din bara de titlu
f.Text = "Documentul " + nr;
// Forma f devine document child
// this este referin la forma container
f.MdiParent = this;
// Afieaz forma child
f .Show();

1
6.

La pornirea aplicaiei, dorim s se deschid o fereastr copil. Tratm


evenimentul Load generat la ncrcarea formei. Dublu click pe suprafaa
formei. n metoda de tratare a evenimentului, scriei:
private void Forml_Load(object sender, EventArgs e)

Capitolul 7.

Controalele Windows Forms

187

{
CreateChild();

}
7. Acum tratm evenimentele Click pentru toate opiunile din meniuri.
Acionai dublu click pe opiunea New. n metoda de tratare, scriei:
private void newToolStripMenuItem_Click(object sender,
EventArgs e)

{
// Dac nu exist ferestre copil active
// setm contorul la 0
if (ActiveMdiChild == nuli)
nr = 0 ;
CreateChild);

8. Acionai dublu click pe opiunea Minimize. n metoda de tratare, scriei:


private void minimizeToolStripMenuItem_Click(
object sender, EventArgs e)

{
// Dac exist o fereastr copil activ,
// aceasta se minimizeaz
if (ActiveMdiChild != nuli)
ActiveMdiChild.WindowState =
FormWindowState.Minimized;

}
9. Acionai dublu click pe opiunea Maximize. n metoda de tratare, scriei:
private void minimizeToolStripMenuItem_Click(
object sender, EventArgs e)
// Dac exist o fereastr copil activ,
// aceasta se maximizeaz
if (ActiveMdiChild != nuli)
ActiveMdiChild.WindowState =
FormWindowState.Maximized;

}
10. Acionai dublu click pe opiunea Close. n metoda de tratare, scriei:
private void closeToolStripMenuItem_Click(
object sender, EventArgs e)

{
// nchide fereastra copil activ
if (ActiveMdiChild != nuli)
ActiveMdiChild.Close();

188 Partea a II-a. Programare Windows cu Visual C# Express Edition


11. Acionai dublu click pe opiunea Close AII. n metoda de tratare, scriei:
private void closeallToolStripMenuItem_Click(
object sender, EventArgs e)
{
// nchide pe rnd fiecare form copil
foreach (Form f in this.MdiChildren)
.Close();

}
12. Acionai dublu click pe opiunea Exit. n metoda de tratare, scriei:
private void exitToolStripMenuItem_Click(object sender,
EventArgs e)
{
Application.Exit (); // Ieire din aplicaie
}
13. Acionai dublu click pe opiunea Tile . n metoda de tratare, scriei:
private void tileToolStripMenuItem_Click(object sender,
EventArgs e)
{
// Aranjare T i l e pe orizontal
this.LayoutMdi(MdiLayout.TileHorizontal);

}
14. Acionai dublu click pe opiunea Cascade . n metoda de tratare, scriei:
private void tileToolStripMenuItem_Click(object sender,
EventArgs e)
{
// Aranjare n cascad
this.LayoutMdi(MdiLayout.Cascade);

}
15. La nchiderea formei, dorim s apar un message box cu butoanele Yes i
No, care s ne ntrebe dac suntem siguri c vrem s ieim. n Form
Designer selectai forma container. n fereastra Propertie apsai butonul
Events (fulgerul). Acionai dublu click pe evenimentul FormClosing. n
metoda de tratare a evenimentului, scrii codul evideniat n Bold:
private void Forml_FormClosing(object sender,
FormClosingEventArgs e)
{
DialogResult result = MessageBox.Show(
"Eti sigur ca vrei sa parasesti aplicaia?",
"Avertizare", MessageBoxButtons.YesNo,
MessageBoxIcon.Question);

Capitolul 7.

Controalele Windows Forms

// Dac s-a apsat No, atunci aplicaia


// nu se nchide
if (result == DialogResult.No)
e .Cancel = true;

}
16. Compilai i rulai aplicaia cu F5.
Cteva capturi de ecran din timpul rulrii:
a) Dup deschiderea ctorva ferestre copil:

b) Aranjare T ile :

189

Partea a Il-a. Programare Windows cu Visual C# Express Edition

190

c)

La ieirea din aplicaie:

De retinut:

O form devine container MDI dac se seteaz true valoarea propietii


IsMdiContainer.

Ferestrele child se construiesc ca oricare alt form, dup care


proprietatii MdiParent i se atribuie o referin la forma printe:
Form f = new Form();
f.MdiParent = this;
f .Show();

Proprietatea MdiChildren a formei container reine referine la toate


formele copil.
Proprietatea ActiveMdiChild returneaz o referin la fereastra child
activ.
Proprietatea WindowState a unei forme seteaz starea curent a
ferestrei. n mod implicit, valoarea ei este Normal. Se mai pot seta valorile
Maximized i Minimized. Aceste valori se obin prin accesarea membrilor
enumerrii: FormWindowState. Exemplu:
ActiveMdiChild.WindowState = FormWindowState.Maximized;

Metoda a LayoutMdi) a clasei Form, aranjeaz formele copil MDI n


forma printe.
Metoda Show() a clasei MessagBox este suprancrcat. Una dintre
versiuni, cea din aplicaie, are trei parametri: textul mesajului, textul din
bara de titlu i butoanele care trebuie s apar pe form. Reamintim c un
message box este un dialog predefinit Windows, deci o form, care

Capitolul 7.

Controalele Windows Forms

191

returneaz ntotdeuana o valoare de tip DialogResult. Aplicaia arat


cum putei exloata valoarea returnat.
La tratarea evenimentului Formclosing, unul dintre parametri este tipul
FormClosingEventArgs. Clasa are proprietatea Cancel. Dac valorea
acestei proprieti este true, atunci evenimentul nu se mai declaneaz,
deci forma nu se mai nchide (scriei e .Cancel = true);

Probleme propuse:

Implementai aplicaiei MdiExample facilitatea de aranjare a ferestrelor n


modul Tile, dar pe vertical.
Adugai aplicaiei MdiExample un control ToolStrip, cu butoane cu
aceeai funcionalitate cu cea a opiunilor meniului.
Integrai ferestrelor copil n aplicaia MdiExample un control de tip
TextBox, pentru ca aplicaia s funcioneze ca editor de text.

Controlul RichTextBox
RichTextBox deriv direct din clasa TextBoxBase, la fel ca i TextBox. n
vreme ce un TextBox se utilizeaz pentru a introduce secvene scurte de
caractere de la tastatur, un RichTextBox se utilizeaz cu precdere ca editor de
text.
Controlul are toate facilitile unui TextBox, dar ofer i altele, cum sunt
posibilitatea de formatare a fontului (Italic, Bold, Underline) i a paragrafului. Textul
se poate introduce de ctre utilizator, poate fi ncrcat din fiiere de tip RTF (Rich
Text Format) sau din fiiere text. Clasa are metode pentru deschidere i pentru
salvare de fiiere n aceste formate. Un control de tip TextBox poate fi nlocuit fr
modificri majore de cod cu un control RichTextBox.
n aplicaia care urmeaz vom utiliza pentru prima oar i o bar de
instrum ente, cu ajutorul controlului ToolStrip. nainte de a continua, cteva cuvinte
despre acest control:

Controlul ToolStrip
Este un control care v permite s creai bare de instrumente. Este de fapt
un container pentru butoane standard Windows, lat un exemplu:
:

Normal -I- Aria t Arial

* io r b i u m

_....

i...------.--------

Se pot crea bare de instrumente cu tem sau fr tem, cu aparena i


comportamentul barelor Micosoft Office, sau Internet Explorer, dar si bare cu stil i
comportament stabilit de dumneavoastr. Clasa ToolStrip abund de surpize
plcute. Merit s le explorai.

192 Partea a ii-a . Programare Windows cu Visual C# Express Edition

Aplicaia R ic h T e x tB o x E xa m p le
Vom realiza un mic editor de text, asemntor celui creat n subcapitolul
TextBox. Controlul care afieaz textul va fi de data aceasta un RichTextBox.
Aplicaia va avea un meniu, faciliti de deschidere i salvare a documentelor n
format RTF, ca i posibilitatea de a seta fontul i culoarea lui. Evident, pentru
implementarea acestor faciliti, vom utiliza dialoguri predefinite.
1.

Creai un proiect de tip Windows Forms Application, cu numele


RichtextBoxExample. Selectai forma i din fereastra Properties atribuii
proprietii Text valoarea: Editor de fiiere RTF.

2.

Din Toolbox plasai cu ajutorul mouse-ulul un control MenuStrip pe


suprafaa formei.

3.

Creai un prim meniu numit Fiier, cu opiunile Nou, Deschide, Salveaza


Ca, i Ieire. Creai un al doilea meniu cu numele Format, avnd opiunile:
Font i Culoare:

Nou
Deschide
; Salveaza Ca
"
i
Ieire

4.

__ __ ___

,1

Din Toolbox plasai pe form cu ajutorul mouse-ului un control ToolStrip.

Capitolul 7.

Controalele Windows Forms

193

5. n controlul ToolStrip adugai pe rnd 9 butoane din lista controlului, aa


ca n figura de mai sus. Rolul acestor butoane poate fi descris prin textele:
Fiier Nou", Deschide Fiierul, Salveaz Fiierul, Decupeaz",
Copiaz, Lipete, Alege un Fonf, "Alege o Culoare, Bullets. Practic
au exact funcionalitatea opiunilor din meniu.
6.

Pe fiecare buton adugat, vom prefera s lipim cte o imagine, dect s


scriem text. Cutai pe Internet cteva imagini .jpg sau .gif adecvate i
salvai-le ntr-un folder oarecare. Selectai controlul ToolStrip i din
fereastra Properties setai proprietatea ImageScalingSize la valorile 20 i
20 (implicit e 16 i 16). Aceasta, pentru a mri puin dimensiunile imaginilor
afiate pe butoane.

7.

Click drept pe fiecare buton din ToolStrip i alegei Set Image. n dialogul
Select Resource, apsai butonul Import. Vei lipi astfel pe fiecare buton
imaginea dorit:

View Code
Set Image.
Enabled

8.

Dorim s atam fiecrui buton cte un Tool Tip Text, adic un mic text
care apare cnd staionai o clip cu mouse-ul asupra butonului. Pentru
aceasta, selectai pe rnd cte un butorn i din Properties atribuii
proprietii Text un text scurt, reprezentnd rolul butonului:

Fiier

'O

Format

M m

Pi ij

tit':' U
| Alege un Font|

9.

Luai din Toolbox un control RichTextBox i plasai-l pe suprafaa formei.


Acionai click pe sageata din colul dreapta sus a controlului i alegei
Dock in parent container.

10. Vom trata evenimentul Click pentru fiecare dintre opiunile meniului, dar i
pentru butoanele din ToolStrip. Dublu click pe opiunea Nou. n corpul
handler-ului de eveniment, scriei codul:

194 Partea a II-a. Programare Windows cu Visual C# Express Edition


private void nouToolStripMenuItem_Click(object sender,
EventArgs e)

{
// terge textul controlului
richTextBoxl.Text = "";

}
Dublu click pe butonul cu textul Fiier Nou" i scriei acelai cod.
11. Facei dublu click pe opiunea Deschide. Corpul handler-ului trebuie s
conin exact acelai cod scris n aplicaia Dialoguri Predefinite din
subcapitolul precedent. Precizm doar codul suplimentar:
if (openFileDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Metoda LoadFile) deschide fiierul
richTextBoxl.LoadFile(openFileDialogl.FileName);

}
Dublu click pe butonul cu textul Deschide Fiierul. Scriei acelai cod.
12. Dublu click pe opiunea de meniu Salveaza Ca. Corpul handler-ului trebuie
s conin exact acelai cod scris n aplicaia Dialoguri Predefinite din
subcapitolul precedent. Precizm doar codul suplimentar:
if (saveFileDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
// Metoda SaveFile() salveaz pe disc textul
// controlului ntr-un fiier cu formatul RTF
richTextBoxl.SaveFile(saveFileDialogl.FileName,
RichTextBoxStreamType.RichText);

}
Dublu click pe butonul cu textul Salveaz Fiierul'. Scriei acelai cod.
13. Dublu click pe opiunea Ieire. n corpul handler-ului adugai codul:
Application.Exit();

// Ieire din aplicaie

14. Dublu click pe opiunea de meniu Font. Handler-ul evenimentului trebuie


s arate astfel:
private void fontToolStripMenuItem_Click(object sender,
EventArgs e)

{
if (fontDialogl.ShowDialog()

Capitolul 7.

Controalele Windows Forms

195

System.Windows.Forms.DialogResult.OK)

{
// Poriunea selectat din text preia
// caracteristicile alese de ctre utilizator
richTextBoxl.SelectionFont =
fontDialogl.Font;

}
}
Dublu click pe butonul cu textul Alege un Fonf. Scriei acelai cod.
15. Dublu click pe opiunea de meniu Culoare. Handler-ul evenimentului
trebuie este:
private void culoareToolStripMenuItem__Click
(objectsender, EventArgs e)

{
if (colorDialogl.ShowDialog() ==
System.Windows.Forms.DialogResult.OK)

{
richTextBoxl.SelectionColor =
colorDialogl.Color;

}
}
Dublu click pe butonul cu textul Alege o Culoare". Scriei acelai cod.
16. Selectai ultimul buton din ToolStrip, cu textul Bullets". n fereastra
Properties, setai proprietatea Name la valoarea bulletButton i
proprietatea CheckOnClick la valoarea true. Dublu click pe buton
pentru a trata evenimentul Click. n metoda handler scriei:
private
void
EventArgs e)

toolStripButton9_Click(object

{
// Dac butonul era apsat atunci textului
// selectat nu i se aplic stilul bullet
if ( bulletButton.Checked )
richTextBoxl.SelectionBullet = false;
else
richTextBoxl.SelectionBullet = true;

}
17. Compilai i lansai cu F5.

sender,

196 Partea a Il-a. Programare Windows cu Visual C# Express Edition

a
F iier

F o rm a t

...................... ....................

V-

I :=

. J..... _

jS p u n e -m i,d a c a te-as p rin d e intr-o zi


Si ti-as s ru t ta lp a piciorului
| N u - i a s a c a ai c h io p a t p u in d u p a c e e a

1D e fric a sa nu-mi striveti sarutuh

Font:

Size:

F o nt style:

Microsoft Sans Seri

i i i :
_ M ila n o LET

1T r MisterFarl RT

! Ita lic
: R egu lar
B Ita lic
i RnlH

OK
1 4
!

16
IR

C a n ce l

Observaie:

Editorul de mai sus lucreaz numai cu fiiere RTF. La ncercarea de


deschidere a unui alt tip de fiier, aceast versiune a metodei
LoadFile () arunc o excepie. Din acest motiv, ntr-o aplicaie
serioas, vei apela asemenea metode numai n interiorul blocurilor try/
catch:
try

{
richTextBoxl.LoadFile(openFileDialogl.FileName);

}
catch (System.Exception e)

{
MessageBox.Show(e.Message);

Exist o a doua versiune a acestei metode care are doi parametri i


poate fi adaptat la lucrul cu fiiere text.
Clasa RichTextBox are i alte faciliti de editare i formatare a textului,
pe care le putei explora de exemplu, mbuntind editorul de mai sus.

Controlul ToolTip
ToolTip se utilizeaz pentru afiarea unor mesaje de informare sau de
avertizare, atunci cnd utilizatorul plaseaz cursorul desupra unui control. O

Capitolul 7.

Controalele Windows Forms

197

singur instan a clasei este suficient pentru a furniza texte de informare pentru
toate controalele unei forme.

Exemplu:
ToolTip t = new ToolTip();
Button
b = new Button();
ComboBox c = new ComboBox();
t. SetToolTip(b, "Valideaza datele");
t .SetToolTip(c, "Lista elevilor din clasa a XII-a B );

Dac dorii stiluri i afiri diferite pe aceeai form, vei utiliza mai multe controale

ToolTip.

Principalii membri ai clasei ToolTip


Proprieti :
AutoPopDelay

IsBallon

ToolTipIcon
ToolTipTitle

Returneaz sau seteaz perioada de timp n care ToolTip


rmne vizibil dac cursorul e staionar deasupra
controlului.
Returnez o valoare de tip bool care indic dac mesajul
este inlclus ntr-o fereastr balon.
Seteaz un icon pentru ToolTip.
Stabilete un titlu pentru ToolTip

Ascunde fereastra ToolTip


Seteaz un text pentru ToolTip i l afieaz
nltur toate textele asociate cu un control ToolTip

Metode:
H id e ()
Show()
RemoveA l l ()

Evenimente:
Popup

Se declaneaz nainte ca ToolTip s fie afiat

Aplicaia T o o lT ip E x a m p le
n proiectul de fa se folosete acelai ToolTip pentru mai multe controale
de pe aceeai form. Se utilizeaz designer-ul pentru toate aciunile necesare.
1.

Creai un proiect de tip Windows Forms Application cu numele


ToolTipExample.

198

Partea a II-a. Programare Windows cu Visual C# Express Edition


2.

Din Toolbox plasai pe form cteva controale: dou controale de tip


TextBox, un GroupBox, dou controale de tip RadioButton, un
CheckBox i dou butoane:

Nume:

Adresa:

Studii
O

Medii

Superioare

Cstorit

OK
,--------------Cancel

3.

Din ToolBox alegei un ToolTip i plasai-l pe suprafaa formei. Acesta nu


este vizibil pe form, dar referina toolTipl apare n designer tray.

4.

Selectai primul control TextBox. n fereastra Properties selectai ToolTip


on toolTipl. Acionai click pe sgeata din dreapta i n panoul care se
deschide introducei mesajul: Introducei numele, iniiala tatlui i
prenumele". Apoi acionai Ctrl + Enter.

5.

Selectai al doilea control TextBox. Acionai de aceeai manier ca la


pasul 4, dar introducei alt mesaj, cum ar fi Introducei strada, numrul
locuinei i localitatea.

6.

Se repet pasul 4, pentru controalele de tip RadioButton, pentru


CheckBox i pentru cele dou controale de tip Button.

7. Compilai i rulai cu F5.


La rulare, cnd staionai cu mouse-ul asupra fiecrui control, apar mesajele
ToolTip:

Nume:

Adresa:

Nume:

| Introducei numele, iniiala tatlui i prenumele |


Adresa:

Studii

Studii

Medii

Superioare

OK

Medii

(*}

Superioare

/ ] C af-a frnrir-----------------

Cancel

QK

-------------------

| licen, masteral: sau doctorat

Capitolul 7.

Controalele Windows Forms

199

De retinut:
>
>

Mesajele ToolTip se pot seta att design time, ct i run time.


Se poate introduce ToolTip fr ajutorul cfes/gner-ului. Tratai de exemplu
evenimentul Load pentru forma acestei aplicaii (dublu click pe suprafaa
formei) i introducei codul:

private void Forml_Load(object sender, EventArgs e)


ToolTip t = new ToolTip();
t.SetToolTip(textBox2,
"Introducei numele, iniiala tatlui i prenumele");
t .SetToolTip(textBoxl,
"Introducei strada i numrul locuinei");
t .SetToolTip(radioButtonl,
"Studiile postliceale sunt considerate medii");
t .SetToolTip(radioButton2,
"Licen, masterat sau doctorat");
t .SetToolTip(checkBoxl,
"Nu bifai in cazul n care suntei divorat!");
t .SetToolTip(buttonl,
"Se valideaz datele introduse");
t .SetToolTip(button2,
"Se renun la datele introduse");

Controlul NotifyIcon
Formele, ca de altfel i alte controale, motenesc metoda H id e () de la
clasa control. Dac utilizatorul ascunde forma principal a aplicaiei, atunci nu
mai are posibilitatea s o reafieze.
Clasa Notifylcon ofer posibilitatea de a accesa procese care ruleaz n
background. Creeaz un icon n zona de notificare (notify area) din system tray.
Zona de notificare se gsete n dreapta task bar-ului, lng ceas. Iconul rspunde
la evenimente, cum sunt Click sau Doubleclick pe care le putei trata pentru a
reafia fereastra aplicaiei. Alternativ, se obinuiete s se ataeze un meniu
contextual care se deschide la click drept pe icon.

Principalii membri ai clasei


Proprieti :
ContextMenu
Icon
Text

Visible

Returneaz sau seteaz un meniu de context pentru icon


Returneaz sau seteaz un iconul controlului
Returneaz sau seteaz un text ToolTip, cnd cursorul
mouse-ului staioneaz deasupra iconului
Stabilete dac iconul e vizibil n zona de notificare

200 Partea a II-a. Programare Windows cu Visual C# Express Edition


Metode:
S h o w B a llo n T ip ()

Afieaz mesajul ToolTip ntr-o form asemntoare


unui balon

Evenimente:
C lic k
D o u b le c lic k

- Se declaneaz la click pe icon


- Se declaneaz la dublu click pe icon

Aplicaia N o tify lc o n E xa m p le
Pe o form plasm un buton care la click o ascunde. Folosim un Notifylcon
pentru reafiarea formei. Reafiarea se produce la dublu click pe icon sau la click
ntr-un meniu de context.
Urmai paii:
1.

Creai un proiect de tip Windows Form s A pp lica tio n cu numele


NotifylconExample.

2.

Din Toolbox plasai pe form un control de tip Button. n fereastra


Properties setai proprietea Text la valoarea Ascunde Forma":

A cunde Fotma

3.

Tragei deasupra formei un control de tip ContextMenuStrip. Selectai n


designer tray referina contextMenuStripl. Introducei itemii Acunde i
Reafiseaza:

Capitolul 7.

Controalele Windows Forms

201

4. Tragei deasupra formei un control de tip Notifylcon. Selectai in designer


tray referina notifylconl.
a. n fereastra Properties, selectai proprietatea Text i introducei
textul care dorii s apar ca tool tip cnd staionai cu mouse-ul
deasupra iconului.
b. Setai proprietatea visible la true.
c. Selectai proprietatea icon i alegei iconul care apare n zona de
notificare. Evident, trebuie s avei unul pregtit. Nu uitai s setai
un icon. n lipsa lui, nu apare la execuie nimic n notify area.
d. Selectai proprietatea ContextMenuStrip i alegei valoarea
contextMenuStrip 1.

noti fy lct j n l System,Windows.Forms,Notifylcon


'11
B

(AppIicationSettings)
(Name)

n o tify lc o n l

BalloonTipIcon

None

BalloonTipText
BalIoonTipTitle
El ContextMenuStrip
GenerateMember

contextM enuStrip 1
True
I E S I (Ic o n )

Modifiers

Private

Tag

5.

Text

Click d re a p ta pentru m eniu de conte

Visible

True

Tratm evenimentul Click pentru butonul Ascunde Forma. Executai dublu


click pe el i scriei n corpul handler-ului codul evideniat n Bold:
private void buttonl_Click(object sender, EventArgs e)

{
// Ascunde forma aplicaiei
this.Hide();

6. n designer tray selectai referina notifylconl i facei dublu click pe

opiunea Ascunde, a meniului contextual. n handler-ul de tratare a


evenimentului Click, introducei codul:
private void ascundeToolStripMenuItem_Click(
object sender, EventArgs e)

{
// Ascunde forma aplicaiei
this.Hide();

202

Partea a II-a. Programare Windows cu Visual C# Express Edition


7.

Acionai dublu click pe opiunea Reafiseaza a meniului contextual, pentru


tratarea evenimentului Click. n corpul metodei de tratare, introducei
codul:
private void reafiseazaToolStripMenuItem_Click(
object sender, EventArgs e)

{
this.Visible = true;

}
8.

Dorim ca la dublu click pe icon n notify area forma s redevin vizibil.


Pentru aceasta, tratm evenimentul Doubleclick pentru Notifylcon.
Selectai n designer tray referina notifyiconl, apoi n fereastra
Properties selectai butonul Events (fulgerul). Acionai dublu click pe
evenimentul Doubleclick. n corpul metodei de tratare scriei:
private void notifyiconl Doubleclick(object sender,
EventArgs e)
{
this.Visible = true;

}
9.

Tratm evenimentul Click pentru opiunile din meniul contextual. Selectai


n designer tray referina contextMenuStripl. Acionai dublu click pe
opiunea Ascunde. n editor, scriei codul:
private void ascundeToolStripMenuItem_Click(
object sender, EventArgs e)
{
this.Hide();

}
10. Acionai dublu click pe opiunea Reafiseaza. n editor scriei codul:
private void reafiseazaToolStripMenuItem_Click(
object sender, EventArgs e)

{
this.Visible = true;

11. Compilai i rulai cu F5.


La executare, iconul rmne n permanen vizibil n zona de notificare.

Capitolul 7.

Controalele Windows Forms

203

Iconul de
notificare

La click pe butonul Ascunde Forma, forma devine invizibil. La dublu click pe icon,
forma redevine vizibil, iar iconul rmne vizibil. Din meniul de context putei de
asemenea s controlai vizibilitatea formei:

De retinut:
*

Controlul Notifylcon plaseaz un icon n zona de notificare din system


tray. Iconul reprezint o scurttur pentru procesele care lucreaz n
background.
Controlul rspunde la evenimente (Click, Doubleclick) i admite un
meniu contextual.

Forituri
Fonturile nu sunt controale .NET. Clasa Font este definit n spaiul de
nume System.Drawing. Un obiect de tip Font ncapsuleaz un format particular

204 Partea a II-a. Programare Windows cu Visual C# Express Edition


de text, incluznd stilul, dimensiunea. Toate controalele de baz au proprietatea
Font, care v permite s specificai caracteristicile fontului care va fi afiat n
control. Setrile fontului se pot face design time, (din fereastra Properties) sau run
time.

Exemplu:
Setm fontul afiat de ctre o etichet:
Label e = new L a b e l ();

// Utilizm unul dintre constructorii clasei Font


// pentru a crea un nou font
e.Fo nt = n e w F o n t ( " A r i a l " , 10, F o n t S t y l e .I t a l i c ) ;

Stilurile Fonturilor
Enumerarea FontStyle din spaiul de nume System.Drawing are ca membri
enumeratorii: Regular, Bold, Italic, Underline i Strikeout. Acetia determin
stilul aplicat textului.
Cnd lucrai cu un editor de text, lucrurile se complic puin, pentru c mai
multe stiluri din cele de mai sus pot fi aplicate aceleai poriuni selectate de text.
Aplicarea unui nou stil nu trebuie s invalideze stilul anterior. De exemplu:
Aceast poriune de text conine stilurile Bold, Italic i Underline.

Aplicaia F o n tS ty le E x am p le
Proiectul
RichTextBox:

introduce

stilurile

Bold,

Italic,

Underline,

ntr-un

control

1.

Creai un nou proiect de tip Windows Forms Application, cu numele


FontStyleExample.

2.

Din Toolbox alegei un control TooStrip i plasai-l pe suprafaa formei.


Adugai trei butoane n acest control. Selectai pe rnd cele trei butoane
i din fereastra Properties atribuii proprietii Text valorile Bold, Italic,
Underline, iar proprietii DysplayStyle valoarea Text.

3.

Aducei pe suprafaa formei un control de tip RichTextBox. Setai din


fereastra Properties, cmpul Dock la valoarea FUI.

4.

Tratm evenimentul Click pentru fiecare buton. Dublu click pe butonul


Bold. Handler-u\ de eveniment este:
p r i vate void. t o o l S t r i p B u t t o n l _ C l i c k (object sender,
E v e ntArgs e)

Capitolul 7.

Controalele Windows Forms

205

{
Font vechiulFont, noulFont;

// Returneaz fontul folosit n textul selectet


vechiulFont = this.richTextBoxl.SelectionFont;
// Dac vechiul font era stil Bold, nlturm

// formatarea
if (vechiulFont.Bold)

{
noulFont = new Font(vechiulFont,
vechiulFont.Style & ~ FontStyle.Bold);

}
else

{
noulFont = new Font(vechiulFont,
vechiulFont.Style | FontStyle.Bold);

}
// Inserm noul font si redm focusul
// controlului RichTextBox.
this.richTextBoxl.SelectionFont = noulFont;
this.richTextBoxl.Focus() ;

5.

Dublu click pe butonul Italic. Handler-ul de eveniment va avea acelai cod


cu cel ataat evenimentului Bold, cu unica diferen c n toate locurile
cuvntul Bold se nlocuiete cu italic.

6.

Dublu click pe butonul Underline. Handler-ul de eveniment va avea


acelai cod cu cel ataat evenimentului Bold, cu unica diferen c n toate
locurile cuvntul Bold se nlocuiete cu Underline.

7.

Compilai i rulai cu F5.

IB H iilW M M I

|gMl gtlJMR
Bold

Italic

Underline

E p rie te n u l m e u a c e la
c a re m a

vorbete de bine

pe la spate.
Thomas Fuller
li-i drumul o a re ?
parc-sia aman
Se marlf-o vrjitoare ?
l ngroappe Satan ?
Aleksandr Puskin
n c o tro
Z b ia r

-i

206

Partea a II-a. Programare Windows cu Visual C# Express Edition

Observaie:

>
>

Codul prezent n metodele handler verific mai nti dac stilul dorit este
deja prezent. Dac este, l nltur.
Pentru adugarea sau nlturtarea unui stil nou, fr a afecta celelalte
stiluri prezente, se efectueaz operaii pe bii cu enumerarea FontStyle.
( Or logic pe bit!' (|) adaug un stil nou, iar And logic pe bit!', aplicat
negrii noului stil, nltur noul stilul dintre cele prezente. Exemple:
// Adaug stilul Underline:
vechiulFont.Style | FontStyle.Underline
// nltur stilul Underline
vechiulFont.Style & ~ FontStyle.Underline

Fonturile instalate
Cu ajutorul unui obiect al clasei installedFontCollection, definit n
spaiul de nume System.Drawing.Text se obin fonturile instalate n sistem, astfel:
using System.Drawing.Text;
InstalledFontCollection fnt = new InstalledFontCollection();

Proprietatea Families a clasei InstalledFontCollection returneaz un


tablou de referine la obiecte de tip FontFamily. Fiecare obiect ncapsuleaz o
familie de fonturi, iar prin proprietatea Name, returneaz numele fontului:
foreach (FontFamily fam in fnt.Families)
System.Console.WriteLine(fam.Name);

Vom vedea un exemplu dup paragraful urmtor.

Desenarea fonturilor
.NET Framework ofer posiblitatea de a desena pe suprafeele formelor sau
ale controalelor. Se pot desena linii, forme geometrice, imagini sau fonturi. n acest
paragraf ne vom ocupa numai de desenarea fonturilor. Pentru desenare, avei
nevoie de un obiect de tip Graphics. Clasa Graphics este definit n spaiul de
nume System.Drawing.
Fonturile se deseneaz cu metoda Drawstring (). Una dintre versiuni
este: Drawstring(String, Font, Brush, float, float). Deseneaz
textul specificat de obiectele string i Font, cu pensula indicat de obiectul
Brush, la locaia indicat. Ultimii doi parametrii indic coordonatele X i Y ale
colului stnga sus al textului. Dac de exemplu dorim s desenm pe suprafaa

Capitolul 7.

Controalele Windows Forms

207

unei forme, atunci cel mai bun moment pentru desenare este acela al desenrii
*'ormei i vom trata evenimentul Paint al formei.

Aplicaia F o n tD ra w in g E x a m p le
Proiectul de fa determin fonturile instalate n sistem i populeaz un
combobox cu numele acestora. La selectarea unui font din list, numele fontului se
va deseneaz pe suprafaa formei.
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


FontDrawingExample.

2.

Din Toolbox, plasai pe suprafaa formei un control de tip ComboBox.

3.

Tratm evenimentul Load generat la ncrcarea formei. Acionai dublu


click pe suprafaa formei. Scriei codul marcat n Bold, n handler-ul de
eveniment:
private void Forml_Load(object sender, EventArgs e)

{
// Determin fonturile instalate
InstalledFontCollection fnt =
new InstalledFontCollection();
// Adaug numele fiecrui font n list
foreach (FontFamily fam in fnt.Families)
comboFont.Items.Add(fam.Name);

}
4. n antetul fiierului Forml.cs, adugai directiva:
using System.Drawing.Text;

5.

Dorim ca desenarea fontului s se produc odat cu redesenarea formei.


Form redesenarea formei, la fiecare selectare a unui item n ComboBox.
Tratm evenimentul SelectedlndexChanged. n acest scop, facei dublu
click pe controlul ComboBox. Scriei codul:
private void comboBoxl_SelectedIndexChanged
(object sender, EventArgs e)

{
// Invalideaz suprafaa formei, fapt
// care cauzeaz redesenarea acesteia
this.Invalidate();

}
6.

Tratm evenimentul Paint pentru form. Selectai forma n Form Designer


i din fereastra Properties acionai dublu click pe evenimentul Faint.
Scriei codul marcat n Bold, n handler-ul de eveniment:

208

Partea a II-a. Programare Windows cu Visual C# Express Edition


private void Forml_Paint(object sender,
PaintEventArgs e)

{
try
{
// Deseneaz fontul pe suprafaa formei
e .Graphics.DrawString(comboBoxl.Text,
new Font(comboBoxl.Text, 40),
Brushes.Black, 10, 50);

}
catch (ArgumentException ex)

{
MessageBox.Show(ex.Message);

}
}
7.

Compilai i lansai n execuie cu F5.

J o k e rm a n LE T
K a r tik a
L a B am ba LET
L a lh a
L u c id a C o n s o le
L u c id a S a n s U n ic o d e
M angal

TabControl
Un TabControl conine pagini suprapuse, numite pagini tab. O pagin tab
este o instan a clasei TabPage. Pagina tab curent se schimb prin cu click cu
mouse-ul pe fab-ul dorit sau se poate face programatic. Paginile tab suport alte
controale, n mod similar formelor. Astfel, un TabControl poate constitui o
alternativ unei afiri succesive a mai multor forme.

Principalii membrii ai clasei TabControl


Proprieti :

Capitolul 7.

S e le c te d ln d e x
S e le c t e d T a b
TabCount
TabPages

Controalele Windows Forms

209

Returneaz sau seteaz indexul paginii tab selectate


Returneaz sau seteaz pagina tab selectat
Returneaz numrul de fab-uri din control
Returneaz colecia de fab-uri din TabControl

Metode:
G e t C o n t r o l()
G e tlte m s ()

Returneaz obiectul TabPage de la locaia specificat


Returneaz colecia de obiecte TabPage aparinnd
controlului TabControl.

Evenimente:

S e le c t e d
S e le c t e d ln d e x C h a n g e d

Se declaneaz cnd se selecteaz un Tab


Se declaneaz cnd proprietatea
S e l e c t e d l n d e x s-a modificat

Aplicaia T a b C o n tro lE x am p le
Aplicaia pe care o propunem utilizeaz un TabControl pentru afiarea
imaginilor. 7ab-urile controlului se adaug runtime, in momentul n care se ncarc
o imagine de pe disc. Operaiile se execut la apsarea butoanelor unui control
ToolStrip. Acestea sunt:
>
>
>
>
>

Open - ncarc o imaginede pe disc i o afieaz ntr-un tab nou.


Next - selectarea fab-ului urmtor
Prev - selectarea fab-ului anterior
Close - nchiderea fab-ului curent
Close AII - nchiderea tuturor fab-urilor

Urmai paii:
1. Creai un nou proiect de tip
TabControlExample.
2.
3.

W in d o w s F o rm s A p p lic a tio n ,

cu numele

Din Toolbox, plasai pe suprafaa formei un control de tip ToolStrip i un


TabControl.
Selectai TabControl-ul, apoi n fereastra Properties setai proprietatea
Dock la valoarea Fill. tergei cele dou tab-uri implicite din control

(acionai click dreapta pe fiecare tab i selectai) Remove Tab.


4.

Adugai cinci butoane pe ToolStrip, desprite printr-un obiect de tip


separator. Forma trebuie s arate astfel:

210

Partea a Il-a. Programare Windows cu Visual C# Express Edition

Butoanele din ToolStrip trebuie s afieze text. Ca s obinei asta,


acionai click dreapta pe fiecare buton, apoi alegei DisplayStyle i
selectai Text. Mai departe, n fereastra Properties, atribuii proprietii
Text valorile corespunztoare:

Add Iiif|a0 &JJ.jste.yt_LPm w _r lr . e

. d o s e Ai! [

"4L~ 5 ] : ViewCocle
[J }'

Set Im a ge...
Enabled
Alignment

!J l

->----

DisplayStyle

None

C onve rt To

Text

In s e rt

Image
Im ageA ndText

Select
dV

Cut
Copy

5.

Declarm un cmp privat n clasa Forml, care stabilete caracterul


separator pentru cile de director. n Solution Explorer, click dreapta pe
Forml, selectai View Code, apoi n fiierul Forml.cs, n clasa Forml,
scriei:
private char[] sep = new chart]

6.

{ '\ V

};

Din Toolbox, tragei pe suprafaa formei un control de tip OpenFiieDialog.

Capitolul 7.
7.

Controalele Windows Forms

211

Tratm evenimentul Click pentru butonul Add Image. Acionai dublu click
pe buton. n handler-ul de eveniment, scriei codul evideniat n Bold:
private void toolStripButtonl_Click(object sender,

string] aux;
string fullPath; // Calea pn la fiierul imagine
string imgName;
// Numele fiierului imagine

// Setm un filtru pentru fiiere de tip imagine


openFileDialogl.Filter = "Fiiere suportate " +
" (*.jpg;* .png;*.ico;*.gif;*.bmp;*.tiff)" +
" |*.jpg;* .png;*.ico;*.gif;*.bmp;*.tiff " +
"|A11 files (*.*)

// Dac dialogul se nchide prin apsarea OK


if (openFileDialogl.ShowDialog() ==
DialogResult.OK)

{
// Obinem calea pn la fiier
fullPath = openFileDialogl.FileName;

// Separm calea n stringuri separate prin *\ '


aux = fullPath.Split(sep);

// Numele imaginii e ultimul string


imgName = aux[aux.Length - 1];
// Crem un tab nou i un PictureBox
TabPage tP = new TabPage(imgName);
PictureBox pB = new PictureBox();
// ncrcm n picture box imaginea
p B .Image = Image.FromFile(fullPath);

// Stabilim poziia i dimensiunea imaginii pe


// tab. (x i y fa de colul stnga sus a
// tab-ului, limea i nlimea)
p B .SetBounds(
(tabControll.Width/2) - p B .Image.Width / 2),
(tabControll.Height/2)- (pB.Image.Height/2),
p B .Image.Width, p B .Image.Height);
// Adugm pb pe tab
t P .Controls.A d d (pB);
// Adugm tab-ul pe TabControl
tabControll.TabPages.Add(tP);

212 Partea a Il-a. Programare Windows cu Visual C# Express Edition


// Tab -ul adugat devine cel selectat
tabControll.Selectedlndex =
tabControll.TabPages.Count - 1 ;
}
}

8. Tratrn evenimentul Click pentru butonul Next.


buton. n metoda de tratare, scriei:

Facei dublu click pe

private void toolStripButton2_Click(object sender,


EventArgs e)
{
// Dac exist tab-ul urmtor
if (tabControll.Selectedlndex + 1 <
tabControll.TabPages.Count)
{
// l selectm
tabControll.Selectedlndex =
tabControll.Selectedlndex + 1;
}
}

9. Tratrn evenimentul Click pentru butonul Prev.


buton. n metoda de tratare, scriei:

Facei dublu click pe

private void toolStripButton3_Click(object sender,


EventArgs e)
{
// Dac exist tab-ul precedent
if (tabControll.Selectedlndex - 1 >= 0)
{
/ / l selectm
tabControll.Selectedlndex =
tabControll.Selectedlndex - 1;
}
}

10. Tratm evenimentul Click pentru butonul Close. Facei dublu click pe
buton. n metoda de tratare, scriei codul evideniat n Bold:
private void toolStripButton4__Click (object sender,
EventArgs e)

{
// Dac mai exist pagini (tab-uri)
if (tabControll.TabPages.Count > 0)

{
// O tergem pe cea selectat
tabControll.TabPages.RemoveAt(
tabControll.Selectedlndex);
}
}

Capitolul 7.

Controalele Windows Forms

213

11. Tratm evenimentul Click pentru butonul Close AII. Facei dublu click pe
buton. n metoda de tratare, scriei codul evideniat n Bold:
private void toolStripButton5_Click(object sender,
EventArgs e)

{
// Ct timp mai sunt pagini (tab-uri)
while (tabControll.TabPages.Count > 0)

{
// tergem pagina selectat
tabControll.TabPages.RemoveAt(
tabControll.Selectedlndex);

}
}
12. Compilai i rulai cu F5.
La rulare, cu Add Image se pot ncrca mai multe imagini n pagini diferite, cu
butoanele Next i Prev se parcurg tag-urile deschise, cu Close se nchide fad
ul selectat, iar cu Close AII se nchid toate paginile.

Probleme propuse
1.

Realizai o aplicaie care utilizeaz un TabControl care preia comenzile


clienilor la o pizzerie. Paginile controlului trebuie s conin controale de
tip TextBox, ComboBox, CheckBox, RadioButton i Button. La finalul
comenzii, aplicaia afieaz ntr-un dialog ntreaga comanda, mpreun cu
preul final.

2.

Realizai un proiect care un utilizeaz un TabControl cu apte pagini.


Controlul reprezint jurnalul unui elev i fiecare pagin corespunde unei
zile a sptmnii. Controlul trebuie s conin cel puin csue de editare.
Dup completarea zilei a aptea, se apas un buton care creeaz un nou
tab. n acest tab se vor afia ntr-un TextBox informaiile introduse n
timpul sptmnii (n rezumat sau integral - dumneavoastr decidei).

Controalele ListBox, ComboBox i CheckedListBox


Toate cele trei controale motenesc clasa ListControl i servesc la afiarea
unei liste de itemuri. Itemurile apar n list ca iruri de caractere i pot fi selectate
prin click cu mouse-ul.
Controlul ListBox poate oferi selecie simpl sau multipl, n funcie de
valoarea proprietii SelectionMode.
Controlul ComboBox combin un TextBox cu un ListBox, permind
utilizatorului s selecteze itemi dintr-o list, sau s introduc noi itemi.
Controlul CheckedListBox afieaz o list de itemi care pot selectai cu
ajutorul unui checkbox prezent pentru fiecare item.

214

Partea a Il-a. Programare Windows cu Visual C# Express Edition

Reinei c n aceste tipuri de liste se pot nsera obiecte, dar c ceea ce se


vede este reprezentarea ca ir de caractere a acestor obiecte.

Adugarea itemilorn liste


Itemii se pot aduga design time sau run time.

Adugarea itemilor design time


O variant simpl este s selectai controlul, facei click pe sgeata din colu
stnga sus, alegei Edit Items i introducei itemii manual, cte unul pe linie:

listBoxl

ListBox Tasks

CU Use data bound iterr


Unbound Mode
! Edit Items

Enter the strings in the collection (one per line):


Corina
Alinuta
Viorel
j Mricel
Ghiocel

ii

Cancel

Adugarea itemilor run time


Se folosesc metodele I n s e r t (), A dd () sau A ddR ange(). Cu I n s e r t ()
inserai un item la o poziie specificat. De exemplu:
// nsereaz n list la poziia 3 un item cu textul "Item 3"
l i s t B o x . I t e m s . I n s e r t (3, " Ite m 3");
Metoda A d d () adaug la sfritul listei un obiect.

Exemplu:
com boBox.Ite m s .A d d ( " Ite m N o u " ) ;
Pentru adugarea eficient a unui numr mare de itemi n list, controalele
furnizeaz metodele B e g in U p d a te () i E n d U p d a te ). Prin utilizarea acestora,
controlul nu este redesenat de fiecare dat cnd un item este introdus n list.

Exemplu:
comboBox. B e g in U p d a te ( ) ;
/ / Controlul nu se mai redeseneaz
f o r ( i n t i = 0 ; i < 200; i+ + )
com boBox.Ite m s .A d d ( " I te m u l " + i ) ;
comboBox. E n d U p d a te ( ) ;

Capitolul 7.

Controalele Windows Forms

215

Adaugarea unui interval de itemuri n liste se face cu metoda AddRange().


Aceasta primete un tablou de obiecte, apoi afieaz n list valoarea de tip
string implicit pentru fiecare obiect.
Exemplu:
listBox.Items.AddRange(new object[] { "UNU", "DOI", "TREI"});

Listele pot prelua itemi. Sursele de date pot fi tablouri, colecii, DafaSef-uri.
Exemplu:
stringf] copii = { "Ionel", "Viorel", "Alinei", "Dorel" };
checkedListBox.DataSource = copii;

Hemurile se terg cu metoda RemoveQ. Exemplu:


// terge obiectul caracterizat de irul "Alin"
listBox.Items.Remove("Alin");

// terge primul item


lisBox.Items.RemoveAt(0);

Clasele specifice acestor liste au desigur i alte metode i proprieti utile. Vom
face un mic proiect, pentru introducere n lucrul cu controalele de tip list.

Aplicaia TestListControl
Aplicaia pe care o propunem ilustreaz diferite modaliti de populare
runtime a controalelor ListBox, ComboBox i CheckedListBox.
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


TestListControl.

2.

Din Toolbox plasai pe form cu ajutorul mouse-ului un control ListBox,


un control ComboBox i un control CheckedListBox. Adugai de
asemenea trei Label-uri pe care le vei eticheta corespunztor controalelor
de tip list.

3.

Sub primele dou controale de tip list plasai cte un buton. Sub controlul
de tip CheckListBox plasai dou butoane. Stabilii valorile proprietilor
Mame
ale
butoanelor
astfel:
listButton,
comboButton,
checkListButtonl i checkListButton2, iar valorile proprietilor
Text, aa cum se vede n figur:

216 Partea a Il-a. Programare Windows cu Visual C# Express Edition


S I Forml

,,,..

ListBox

>V

ComboBox

CheckedListBox

. r ~ ......... ..... ~ 4

Inca rca ListBox

Incarca ComboBox

Incarca o lista
Inca rca alta lista

4.

Dorim ca la ncrcarea formei s ncrcm i controlul CheckListBox cu o


prim list de itemi. Pentru aceasta, tratm evenimentul Load care se
declaneaz la ncrcarea formei. Facei dublu click pe suprafaa formei.
Completai astfel corpul handler-u\u\ de eveniment:
private void Forml_Load(object sender, EventArgs e)

{
// Un tablou de referine la obiecte de tip string
string] copii = { "Ionel", "Viorel", "Alinei",
"Dorel" };
// Sursa de date este tabloul
checkedListBoxl.DataSource = copii;

}
5.

Definim clasa, Elev, n fiierul Forml.es. Avei grij, Visual C# Express


2008 cere ca definiia oricrei clase s urmeze definiiei formei:
class Elev
{
private string nume;
public Elev(string n) { nume = n; }
public string Nume
{
get { return nume; }

}
}
Vom defini de asemenea un cmp privat el n clasa Forml, de tip referin
la un tablou de obiecte de tip Elev:
private Elev[] e l ;

6.

Tratm evenimentul Click pentru butonul listButton. Acionai dublu click


pe acesta. Introducei acest cod n metoda de tratare:

Capitolul 7.

Controalele Windows Forms

217

private void listButton_Click(object sender,


EventArgs e)
// Membrul clasei Elev care va fi afiat n list
// ca ultim item
listBoxl.DisplayMember = "Nume";
// Tabloul de referine de tip object poate reine
// referinele ORICROR TIPURI de obiecte
listBoxl.Items.AddRange(new object[]{ "UNU", "DOI",
"TREI", new Elev("Nelutu") });

}
7.

Tratm evenimentul Click pentru butonul comboButton. Acionai dublu


click pe acesta. Completai astfel metoda de tratare:
private void comboButton_Click(object sender,
EventArgs e)

{
/* ncepnd de la apelul BeginUpdate() i pn la
EndUpdate() controlul nu se mai redeseneaz, ceea
ce sporete viteza de adugare n list */
comboBoxl.BeginUpdate();'
for (int i = 0; i < 20; i++)
comboBoxl.Items.Add("Itemul " + i ) ;
comboBoxl.EndUpdate();

8. Tratm evenimentul Click pentru butonul checkListButtonl. Acionai


dublu click pe acesta. Completai astfel metoda de tratare:
private void checkListButtonl_Click(object sender,
EventArgs e)

{
stringf] copii = { "Ionel", "Viorel", "Alinei",
"Dorel" };
checkedListBoxl.DataSource = copii;

}
9.

Tratm evenimentul Click pentru butonul checkListButton2. Acionai


dublu click pe acesta. Completai n acest mod metoda de tratare:
private void checkListButton2_Click(object sender,
EventArgs e)

{
// Crem obiectele care se insereaz n list
el = new Elev[] { new Elev("marius"),
new Elev("lenuta")};

218

Partea a Il-a. Programare Windows cu Visual C# Express Edition


// Sursa de date este el
checkedListBoxl.DataSource = el;
// Membrul clasei Elev care se va afia
// n list este proprietatea Nume
checkedListBoxl .Display-Member = "Nume";

10. Compilai i rulai cu F5.

ListBox

CheckedListBox

ComboBox

ii.............

Ionel

Hemul 0
Hemul 1
Hemul 2

~ 7

|| | Viorel
j| | Alinei
f~| Dorel

m m sm

Incarca ListBox

Hemul 5
Hemul 6
Hemul 7

Incarca o lista
V

Incarca alta lista

Cele trei controale se ncarc runtime, prin acionarea butoanelor corespunztoare.

Controalele TrackBar, NumericilpDown i


DomainUpDown
Aceste controale se numesc i controale de domeniu, deoarece utilizatorul
poate introduce un numr limitat de valori dintr-un domeniu prestabilit. Introducerea
datelor se face n mod vizual, acionnd de regul cu mouse-ul.

TrackBar
TrackBar:

Este un control scro//-abil, cu ajutorul crui utilizatorul poate alege o valoare a


proprietii Value, cuprins ntre o valoare maxim i minim. Limitele extreme se
impun prin atribuirea de valori proprietilor Minimum i Maximum. Implicit, aceste
valori sunt 0 i 10.

Capitolul 7.

Controalele Windows Forms

219

NumericUpDown
NumericUpDown:

!fl

Este un control care conine o singur valoare numeric, pe care utilizatorul o


poate modifica acionnd click pe butoanele Up sau Down ale controlului.
Utilizatorul poate s i introduc valori, dac proprietatea Readonly este setat
true.

DomainUpDown
D omainU pD own:

' Primul item

Este similar cu un ListBox n aceea c ofer o list de opiuni ntre care utilizatorul
poate alege. Diferena fa de ListBox este c un singur item este vizibil la un
moment dat, iar utilizatorul poate naviga n list doar acionnd sgeile Up i
Down ale controlului. Pentru crearea coleciilor de obiecte care vor alctui lista, se
utilizeaz metodele Add (), la fel ca pentru celelalte controale de tip list.

Transparena i opacitatea controalelor


opacity i Transparency sunt dou proprieti ale formelor. Au rolul de a
regla gradul de trasparen a formei, dar i a controalelor care se
gsesc
pe
suprafaa formei. Cnd proprietatea Opacity este setat la valoarea 1,00 (100%),
atunci forma este perfect vizibil. Dac valoarea este 0, atunci forma, inclusiv
bordurile, marginile i controalele de pe form sunt invizibile. Valori intermediare,
regleaz niveluri proproionale de tranparen.
n ce privete proprietatea Transparency, acesteia i este ataat o
culoare. ntreaga arie a formei care are aceeai culoare (proprietatea BackColor)
devine trasparent, iar orice aciune cu mouse-ul pe suprafaa devenit
transparent, este transferat ferestrei de sub aria devenit trasparent. Aceast
caracteristic v permite s definii controale cu forme neregulate.

Aplicaia O p a c ity
Vom utiliza controalele TrackBar, NumericUpDown i DomainUpDown
pentru a regla opacitatea unei forme. Evident, unul singur dintre cele trei controale
ar fi fost suficient, ns scopul nostru este de a nva s ie utilizm pe toate.
1. Creai un nou proiect de tip Windows Forms Application, cu numele
Opacity.
2.

Din Toolbox plasai pe form cu ajutorul mouse-ului un control


NumericUpDown, un control DomainUpDown i un control TrackBar.
Adugai de asemenea trei Label-uri pe care le vei eticheta corespunztor
controalelor i un buton cruia setai-i proprietatea Text: la Revenire:

220 Partea a II-a. Programare Windows cu Visual C# Express Edition

Revenire

NumericUpDown:

:0

DomainUpDown:

!0pacitate100%

TrackBar:

v*

3.

Selectai controlul DomainllpDown. Din fereastra Properties, atribuii


proprietii Text valoarea Opacitate 100%". Selectai proprietatea Items,
apoi apsai butonul din dreapta. n dialogul String Collection Editor,
introducei 10 itemi, cte unul pe linie, cu textul: Opacitate 100%",
Opacitate 90%, ... "Opacitate 0%.

4.

Tratm evenimentul Scroll pentru TrackBar. Dublu click pe control. Scriei


codul marcat n Bold, n handler-ul de eveniment:
private void trackBarl_Scroll(object sender,
EventArgs e)

{
// Odat cu creterea valorii Value de la 0
// 10 , opacitatea formei trebuie s scad
this.Opacity = 1 - (double)trackBarl.Value / 10;

5.

}
Tratm
evenimentul
SelectedlndexChanged
pentru
controlul
DomainUpDown, n scopul de a modifica opacitatea n raport cu indexul
itemului. Dublu click pe control. Scriei codul:
private void domain_SelectedItemChanged(object sender,
EventArgs e)

{
// Opacitatea formei scade cu creterea
// indexului itemului selectet
this.Opacity = 1 (double)domainUpDownl.Selectedlndex / 10;

}
6.

Tratatm evenimentul ValueChanged pentru controlul NumericlIpDown,


pentru a modifica opacitatea n funcie de valoarea afiat n control.
Acionai dublu click pe control. Scriei codul:

Capitolul 7.

Controalele Windows Forms

221

private void numericUpDownl_ValueChanged(object sender,


EventArgs e)

{
// Value este valoarea afiat n control
this.Opacity - 1 - (double)numericUpDownl.Value/10;

}
7.

Pentru reiniializarea valorilor controalelor, dar i pentru readucerea formei


la opacitate maxim, tratm evenimentul Click pentru butonul "Revenire.
Dublu click pe buton. Scriei codul marcat n Bold, n handler-ui de
eveniment:
private void buttonl_Click(object sender, EventArgs e)
{
this.Opacity = 1 ;
// Forma devine opac
// Reiniializarea valorilor n controale
trackBarl.Value = 0;
numericUpDownl.Value = 0;
domain.Text = "Opacitate 100%";

}
8.

Compilai aplicaia i rulai cu F5.

t.
ca|'ipiori 2003
CjImageTest

c n u t 2004
caeipion 200S

Ol ca'ipion 2006

?j magineAudoEuIulia

Revenire
a JAVA 1.3

Oi OJMPION 200?

O) ca ipiarr 2006
0 G 'te NumerieUpDown:
01 G le-STL
a Ci t i OcmainUpDown:
a cpi
a G -VORKS
a cy jwin
a di; stra TtackBat:

ea e f Life...........
a
a
a

ppr
gard

jO a v a f
3pAA_Tuteriai_5UN
PiSliavadoc
2, j JavaExampiesZ

Clpacifale 602

^Javaexe

LOlia-'axrrti

........... ,:--3BJWer
domainUpDownl.

P .... .....; P M'C'


"y
t. ldbc?
tJJSP

............. a n a ...........

Opacitatea formei se poate seta n mod independent cu ajutotorul celor trei


controale.
A p lic a ia T ra n s p a r e n c y

Atunci cnd dorii ca anumite poriuni ale formei s fie transparente i


aciunea mouse-ului pe suprafaa transparent s se transfere ferestrelor de sub
form, utilizai proprietatea Transparency a formelor.

222

Partea a II-a. Programare Windows cu Visual C# Express Edition


1.

Creai un nou proiect de tip Windows Forms Application, cu numele


Opacity.

2.

Din Toolbox plasai pe form cu ajutorul mouse-ului un control de tip


Panel i dou butoane.

3.

Selectai panoul i n fereastra Properties atribuii proprietii BackColor


valoarea Gray. Setai pentru cele dou butoane proprietatea Text la
valorile: Panou Transparent, respectiv Forma transparenta.

4.

Tratm evenimentul Click generat de butonul cu eticheta Panou


Transparent. Facei dublu click pe buton. Scriei n metoda de tratare
urmtorul cod :
private void buttonl_Click(object sender, EventArgs e)
{
// Toate zonele formei de culoare gri,
// devin transparente (suprafaa panoului)
this.TransparencyKey = System.Drawing.Color.Gray;

}
5.

Tratm evenimentul Click generat de butonul cu eticheta Forma


Transparenta. Dublu click pe buton, iar n metoda de tratare scriei:
private void button2_Click(object sender, EventArgs e)
{
// Zonele de culoarea implicit a controalelor
// devin transparente(exteriorul controlului Panel)
this.TransparencyKey =
System.Drawing.SystemColors.Control;

}
6.

Compilai i executai cu F5.

Panoul e transparent

Forma e transparent

Capitolul 7.

Controalele Windows Forms

223

Observai c numai suprafaa formei devine transparent, nu i marginile,


bara de titlu, sau celelalte controale de pe form.

Controlul ProgressBar
Controlul nu permite nici o aciune a utilizatorului. Este destinat s indice n
mod vizual progresul unei aplicaii care decurge lent, aa cum sunt printarea unor
documente, copierea unui numr mare de fiiere, scanarea unui disc.
Stilul de afiare al controlului este determinat de proprietatea s t y le . Exist
trei stiluri:
O bar continu care se umple de la stnga la dreapta
Blocuri segmentate care progreseaz de la stnga la dreapta.
Blocuri care oscileaz.
Proprietatea Value este valoarea care reprezint progresul curent al
aplicaiei. Poziia curent a barei de progres este n legtur direct cu Value.
Proprietile Minimum i Maximum sunt limitele de valori pentru Value. Minimum
este de regul setat la 0, iar Maximum este setat la o valoare care indic
terminarea operaiei.
ntreaga operaie pentru care vizualizai progresul este format dintr-un
numr de operaii pe care le considerai elementare. Dup fiecare operaie
elementar, cu ajutorul metodei PerformStep () incrementai valoarea barei de
progres cu valoarea step.
Exemplu de utilizare:
ProgressBar p = new ProgressBar();
// Maximum poate fi de exemplu numrul de fiiere
// care trebuie copiate
p.Maximum = 500;
p .Mimnimum = 500;
p.Value = 0;
p.Step = 5;
or (int i = p.Minimum; i < p.Maximum; i += p.Step)

{
// Operaie elementar (de exemplu, copierea unui fiier)
// Incrementeaz bara de progres
progress.PerformStep();

}
Aplicaia pe care o vom prezenta n cadrul temei Controlul Timer ilustreaz i
utilizarea unui progress bar.

224 Partea a II-a. Programare Windows cu Visual C# Express Edition

Controlul Timer
Contrulul funcioneaz ca i cronometru. Declaneaz un eveniment la un
interval de timp specificat de ctre programator. .NET implementeaz cteva
cronometre dintre care discutm dou:
1.

Primul, este definit de ciasa Systems.Windows.Forms.Timer. Se


utilizeaz n aplicaii de tip Windows Forms. El apare n mod implicit n
Toolbox i trebuie afiat ntr-o fereastr. Se utilizeaz numai n medii cu
un singur thread. Acurateea este de aproximativ 55 milisecunde.
2. Al doilea, definit de clasa System.Timers.Timer, este mai performant.
Poate fi folosit n medii multithread. Nu se gsete n mod implicit n
Toolbox, ns poate fi adus acolo, aa cum vom vedea.
Exist asemnri i deosebiri ntre cele dou timer-e. Ambele declaneaz
un eveniment la un interval specificat. Primul declaneaz evenimentul Tick, iar al
doilea, evenimentul Elapsed. Ambele au metodele Start () i stop(), i
proprietatea Enabled.

Aplicaia Tim er.E xam p le


Aplicaia execut sarcinile:
Utilizez timer-u\ System.Windows.Timer care declaneaz un
eveniment Tick la interval de dou secunde, timp de 20 de secunde.
Numrul de secunde se afieaz ntr-un control Labei, iar progresul se
vizualizeaz cu o bar de progres. Cronometrul poate fi pornit i oprit cu
butoanele Stop i Start.
Utilizeaz timer-ul System.Timers.Timer pentru afiarea orei, ntr-un
control Labei. Evenimentul Elapsed se declaneaz la interval de o
secund.
1.

Creai un proiect de tip Windows Forms Application, cu numele


TimerExample.
2. Aducei din Toolbox pe suprafaa formei un control de tip Timer, dou
controale de tip Button, un ProgressBar i i ase controale Labei:

Capitolul 7.

3.

Controalele Windows Forms

225

Vom seta mai nti etichetele butoanelor:


a. Selectai labell. n fereastra Properties, setai fontul la
dimensiunile (16, 50). Atribuii proprietii Text valoarea
"System.Windows.Forms.Timer." Selectai label2. Setai fontul la
dimensiunile (16, 50). tergei numele etichetei. Selectai label3.
Atribuii proprietii Text valoarea "Incrementare la 2 secunde.
b. Selectai label4. Setai fontul la dimensiunile (16, 50). Atribuii
proprietii Text valoarea System.Timers.Timer. Selectai
labels. Setai fontul la dimensiunile (16, 50). tergei numele
etichetei. Selectai label6. Atribuii proprietii Text valoarea
Afieaz ora exact.
c. Selectai buttonl. Atribuii proprietii Text valoarea Start.
Selectai button2. Atribuii proprietii Text valoarea Stop.
01 Forml

System. Windows. Forms.Timer


Ia b e l2

I n c r e m e n t a r e la 2 s e c u n d e

S ta r t

S to p

System.Timers.Timer

A fi e a z o r a e x a c t

Ia b e l5

4.

Selectai referina timerl n designer tray. n panoul Properties, setai


proprietatea Name la valoarea winTimer. Setai la 1000 (o secund)
valoarea proprietii interval. Este intervalul la care se declaneaz
evenimentul Tick.

5.

Vom aduga un timer-ul din spaiul de nume


System.Timers. n Toolbar, n partea cea
mai de jos, unde nu mai sunt controale, facei
click drept i alegei Choose Items...

6. n dialogul Choose Toolbox Items, alegei din


tab-ul .NET Framework Components, clasa
Timer din spaiul de nume System.Timers.
Un icon tip ceas apare n partea de jos n
Toolbar.

t AII Windows forms


: Common Controls
.it- Containers
* Menus 8c Toolbars
t Data

Components
t Printing
Dialogs

. - General
There are no usable controls in this group. Drag
an item onto this text to add it to the toolbox.
|| v I List View
Show AS

I
;

.....
7. Tragei noul Timer pe suprafaa formei. n
designer tray, selectai referina timerl. n
panoul Properties, schimbai numele referinei la systemTimer, setai
Choose Items..,

226

Partea a II-a. Programare Windows cu Visual C# Express Edition


valoarea proprietii Enabled la true, iar a proprietii interval la
1000. Aceasta nseamn c evenimentul Elapsed se declaneaz la
interval de o secund.
8.

Selectai bara de progres. n panoul Properties, setai proprietatea Step


la valoarea 2 i proprietatea Maximum la valoarea 20.

9. n fiierul Form1.cs, n clasa Forml, declarai un cmp privat, numit time,


care contorizeaz numrul de secunde scurse. n Solution Explorer,
facei click drept pe Forml.cs i selectai View Code. Scriei:
private int time = 0;

10. Tratm evenimentul Tick pentru winTimer. Selectai referina winTimer


n designer tray, apoi n Properties, acionai dublu click pe evenimentul
Tick. Scriei codul:
private void winTimer_Tick(object sender, EventArgs e)

{
time += 2;

// Un eveniment Tick la 2 secunde

// Afim timpul n etichet


label2.Text = string.Format("{0}", time);
// Incrementarea barei de progres
progressBarl.PerformStep();
if (time == 20)
// Dac s-au scurs 20 secunde

{
// oprim timer-ul i bara de progres
winTimer.Stop();
progressBarl.Enabled = false; // oprim

}
}

11. Tratm evenimentul Click pentru butonul Start. Facei dublu click pe buton.
Introducei codul:
private void buttonl_Click(object sender, EventArgs e)

{
winTimer.Enabled = true; // Activm timer-ul
if (time == 20)
// Dac au trecut 20 sec
{
/ / s e fac reiniializri
time = 0;
progressBarl.Value = 0;

}
}

12. Tratm evenimentul Click pentru butonul Stop. Facei dublu click pe buton.
Introducei codul:

Capitolul 7.

Controalele Windows Forms

227

private void button2_Click(object sender, EventArgs e)

{
winTimer.Stop () ;
// Oprir cronometrul
progressBarl.Enabled = false; // Oprim p r o g r e s s b a r
if (nrTick == 20)

{
nrTick = 0;
progressBarl.Value = 0;

}
13. Tratm evenimentul Elapsed pentru systemTimer. Selectai referina
systemTimer n designer tray, apoi n Properties, acionai dublu click pe
evenimentul Elapsed. Scriei codul:
private void systemTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)

{
// Proprietatea Now a clasei DateTime, returnez
// ora exact
label5.Text =System.DateTime.N o w .ToLongTimeString();

}
14. Compilai i rulai aplicaia cu F5.
Captur de ecran la execuie:
...... i?-.rJd.: ,_i

System. W indows. Forms.Timer


j

1 2

i i i i l i vi*

I n c r e m e n t a r e la 2 s e c u n d e

>' i |

System .Timers .Timer

S ta r t

S to p

A fi e a z o ra e x a c t

14:00:31

Controalele Picture Box i Imagelist


Imagini de funda! pentru controale
Multe controale suport afiarea de imagini, deoarece motenesc
proprietatea Backgroundlmage de la clasa Control. ntre aceste controale,

228

Partea a II-a. Programare Windows cu Visual C# Express Edition

menionm Button, CheckBox, RadioButton, PictureBox. i controalele de tip


container cum sunt Panel, GroupBox i Form suport imagini de fundal.

Anumite controale suport i imagini de prim plan. De exemplu, Button are


n acest scop proprietatea image, motenit de la clasa ButtonBase. n cazul n
care utilizai att o imagine de fundal ct i de prim plan, imaginea de prim plan se
afiez deasupra.
Controalele au n plus proprieti cu ajutorul crora se pot modifica
caracteristicile imaginilor afiate.
Pentru afiarea design time a unei imagini, se selectaz controlul, se apas
butonul cu etichta
din linia proprietii B ac k g r o u n d i m a g e L a y o u t sau a
proprietii image. n dialogul Select Resource, bifai Local resource", apoi
apsai butonul Import.

Capitolul 7.

Controalele Windows Forms

229

Caracteristicilor imaginilor se modific simplu din panoul Properties atribuind valori


urmtoarelor proprieti:
>

>

Backgroundl m a g e L a y o u t
Are valorile posibile: None, Tile, Center, Strech i Zoom. De exemplu,
mai sus, pentru CheckBox, i RadioButton am ales Center, iar pentru
GrupBox valoarea Tile.
ImageAllign
Label-urile nu suport Backgroundlmage deci utilizai Image pentru

afiare, iar pentru modul de afiare, alegei dintre valorile disponibile n


panoul Properties, pentru proprietatea ImageAllign.
>

A u t oSize

Pentru labei-uri, checkbox-uri i radiobutoane trebuie s setai aceast


proprietate la valoarea false, altminteri nu vei reui s redimensionai
suprafeele controalelor, astfel nct s potriveasc imaginile.
>

T e xtAllign

Aceast proprietate v permite s stabilii poziia i alinierea textului n


raport cu suprafaa controlului.

Clasa Image
.NET definete clasa Image n spaiul de nume System.Drawing, pentru
lucrul cu imagini.
Clasa este abstract, deci nu se pot crea obiecte de acest tip. n schimb, imaginile
se citesc din fiiere cu metoda static FromFile ():
Exemplu:
Image im = Image .FromFile (

Path.Combine(Application.StartupPath, "foto.gif"));
Label lbl = new lbl Labei(); // Creeaz o etichet
lbl.Image = im;
// Afieaz imaginea n control
Codul de mai sus ncarc imaginea din fiierul " f o t o . g i f " aflat n folderul n care
se gsete fiierul assembly (exe) al aplicaiei. Metoda nu recunoate dect
formatele .GIF i .BMP. Eticheta l b l afieaz imaginea ncrcat.
Clasa are proprieti i metode pentru manipularea imaginilor. Metoda
F r om St re am () ncarc imagini de diferite tipuri nu numai n formatele standard
.GIF sau .BMP. Creaz un stream din care putei descrca imaginea. Sream-ul
poate s fie de conectat la orice dispozitiv de intrare, de exemplu la o adres de
Internet:
string s = h t t p : / / ....... /foto.jpg;
// URL
// Sunt necesare obiectele w r q i wrs pentru crearea

// stream-ului
We bR eq u e s t w r q = W e b R e q u e s t .C r e a t e ( s ) ;
We bR e s p o n s e wrs = w r q . G e t R e s p o n s e ();
St ream str = w r s .G e t R e s p o n s e S t r e a m Q ; // Creaz stream-ul

230 Partea a II-a. Programare Windows cu Visual C# Express Edition


Label lbl = n e w L a b e l ();

// Afieaz imaginea ntr-un control de tip Labei


l b l . Image = I m a g e .F r o m S t r e a m (str) ;
str.c l o s e ();

Vom reveni asupra tipului Image.

Controlul PictureBox
PictureBox este un control aflat la ndemn n Toolbox. E folosit pentru
afiarea imaginilor grafice, obinute din fiiere JPEG, GIF, BMP, PNG, iconuri sau
metafiiere.
Prezentm civa membri reprezentativi ai clasei PictureBox.
Proprieti
Image
SizeMode

Se seteaz pentru afiarea design time sau run time a


imaginilor
Specific modul de afiare a imaginii. Are valorile:
Strechlmage, Centerlmage, N o r m a l , Zoom.

ClientSize
Im ageLocation

Permite modificarea dimensiunii imaginii n timpul rulrii.


Reprezint calea sau URL-ul spre imaginea care se afieaz
n PictureBox.

Metode
L o a d ()
S e t B o u n d s ()

Afieaz imaginea specificat de proprietatea


ImageLocation. Are dou versiuni.
Seteaz limitele controlului, la o anumit locaie, i la
dimensiunile specificate.

Evenimente
Click
Paint
Cl ie nt S i z e C h a n g e d

Se declaneaz la click pe control


Se declaneaz cnd controlul trebuie redesenat
Se declaneaz cnd proprietatea ClientSize se modific

Resursele unui proiect Visual C#


Ai vzut c un program C# poate accesa fiiere externe de tip imagine,
problema apare cnd asemenea resurse sunt terse sau mutate din greeal. n
aceste^condiii aplicaia nu le mai poate utiliza.
n Visual C# exist posiblitatea s incorporai resurse de care aplicaia are
nevoie: imagini, iconuri, sunete, stringuri n acelai fiier assembly(.exe) care
conine codul compilat al aplicaiei. Pentru a vedea cum se realizeaz acest lucru,
realizm un mic proiect.

Capitolul 7.

Controalele Windows Forms

231

Aplicaia Im a g e R es o u rc e E x a m p le
Proiectul va fi unul simplu: pe o form, avem un control PictureBox.
Imaginea pe care o afim n control, va fi una luat din resursele proiectului.
Pentru divertisment, implementm i facilitatea de mrire i de micorare a imaginii
(Zoom).
15. Creai un nou proiect de tip Windows Forms Application, cu numele
ImageResourceExample.
16. Aducei din Toolbox pe suprafaa formei un control de tip PictureBox i
dou butoane.
17. Selectai controlul PictureBox. n panoul Properties, setai pentru
proprietatea SizeMode valoarea Zoom. Aceasta permite controlului s se
redimensioneze odat cu imaginea.
18. Selectai pe rnd cele dou butoane i stabilii pentru proprietatea Text,
valorile Zoomln, respectiv ZoomOut:

19. Acum adugm o imagine ca resurs a proiectului. n Solution Explorer,


dublu click pe Properties. Se deschide fereastra Editorului de Resurse.
Pe coloana din stnga ferestrei, selectai Resources. Din lista primului drop
down button din stnga sus, selectai Images:

Application

. ;al Images
L?J?cj

Build Events

jH

Debug
Resources
Settings

Strings

Add Resource
Ctrl+1

Images

Ctrl+2

Icons

Ctrl+3

Audio

Ctrl-4-4

Files

Ctrl+5

Other

Ctrl+6

232

Partea a II-a. Programare Windows cu Visual C# Express Edition


20. Din lista butonului Add Ressource, selectai Add Existing File ...:
------------ ~~~r
1-13 Images -

Application

. . . . .

J Add Resource -

iT>

Add Existing File,..

Build

Add New String


Build Events

New Image

Add New Text File


........ .........t..... .
.... .........
.............

Debug
j

Resources*

21. Selectai o imagine pe care ai pregtit-o n acest scop:


Form 1. Designer.cs

Form 1. cs

i
j j Images Q Add Resource ?

Application

l! |
ij

! S

I|
i

j
i

j
: Build Events
|

1 ij
i 11
I M
1 ii

1
___ i

Debug

!
i

Resources*
f-----------------------
Settings

i
i

j i i
S j]

Solution TmageExample1(1 project)


3 3 Im ageExam ple

S) 3 $ Properties
i

{&

\S M

References
Resources
j i j actori,bmp

0 - ilF o r m l.e s
jb ] Forml.Designer.es
jfi) Forml.resx
':J3 Program.es

actori
j

22. Selectai controlul PictureBox. n panoul Properties, acionai butonul cu


eticheta (...) din dreapta proprietii Image. n dialogul Select Resource
vei selecta Project Resource File i ncrcai imaginea pe care ai adus-o
la resursele proiectului.
23. Declarai un cmp privat zoom, n clasa Forml. El reprezint cantitatea cu
care se incrementeaz dimensiunile controlului la fiecare apsare a
butoanelor:
private int zoom;

24. Tratm evenimentul Click pentru butonul cu textul Zoomln. Acionai dublu
click asupra lui. Se deschide Editorul de Cod. Scriei codul evideniat cu
Bold, n handler-ul de eveniment:
private void buttonl_Click(object sender, EventArgs e)
{
zoom = 2;

// Limea i nlimea dup o apsare de buton


int W = pictureBoxl.Size.Width + zoom;
int H = pictureBoxl.Size.Height + zoom;

Capitolul 7.

Controalele Windows Forms

233

// Are loc actualizarea dimeniunilor prin


// modificarea proprietii ClientSize
pictureBoxl.ClientSize = new Size (W, H ) ;

25. Tratm evenimentul Click pentru butonul cu textul ZoomOut. Acionai


dublu click asupra lui. n handler-ul evenimentului vei scrie acelai cod, cu
singura diferen c prima linie este: zoom = -2; (dimensiunile scad).
26. Compilai i rulai cu F5.

Prin apsarea celor dou butoane, se obine efectul de mrire, respectiv de


micorare a imaginii.

De retinut:
9

Resursele adugate proiectului se integreaz n mod automat n fiierul


assembly compilat (fiierul .exe).
Resursele sunt imagini, iconuri, sunete, sau stringuri.
Editarea resurselor se face design time cu ajutorul Editorului de
Resurse, sau runtime n mod programatic.
ntre folderele proiectului apare unul nou, numit Resources, care poate
fi vizualizat din Solution Explorer.
Se pot elimina elemente folderul Resources, fr ca aceasta s afecteze
fiierul assembly. La fiecare build, compilatorul consult acest folder i
numai dac a aprut o versiune nou a unui fiier, acesta este integrat
n assembly.

234

Partea a II-a. Programare Windows cu Visual C# Express Edition

Manipularea ru n tim e a resurselor


Resursele se acceseaz uor din cod, deoarece mediul integrat creaz o
clas Resources, aflat n spaiul de nume Properties, iar acesta din urm se
gsete n interiorul spaiului de nume al aplicaiei. n clasa Resources, toate
resursele se acceseaz simplu, ca oricare membru public.
lat de exemplu cum putei atribui runtime unui control o alt imagine din
resursele proiectului:
pictureBoxl.Image = Image.Properties.Resources.pisica;

Resursa pisica este un tip nou creat, pe baza unei imagini obinute dintr-un fiier
care se numea de exemplu pisica.bmp.

Setarea iconului aplicaiei i a iconuiui unei forme


Ca s ataai un icon fiierului assembly (.exe) al aplicaiei, n Solution
Explorer acionai dublu click pe itemul Properties. n fereastra care se deschide,
selectai Application, apoi selectai check box-ui Icon and manifest i alegei iconul
dorit.
Ca s ataai un icon unei forme, selectai forma n Form Designer, apoi n
fereastra Properties selectai proprietatea icon i alegei un icon-ul dorit.

Clasa ImageList
ImageList este un control care ncapsuleaz o colecie de imagini sau iconuri. Imaginile se folosesc de ctre alte controale, cum este Listview, TreeView,
sau ToolStrip. Principalii membrii ai clasei sunt:
Proprieti
Images
ImageSize

ColorDepth

Colecia de imagini utilizate de ctre alte controale


Dimensiunea imaginilor n colecie. Indiferent de dimensiunile
iniiale ale imaginilor, acestea se convertesc la un fomat
specificat n momentul n care se adaug la colecie
Valoare care indic adncimea de culoare. Valorile obinuite
sunt 5 bii (256 culori), 16 bii (high color), 24 bii (true color).

Metode
Draw()

Metod suprancrcat care deseneaz imaginile pe suprafaa


unui control.

Capitolul 7.

Controalele Windows Forms

235

A p lic a ia Im a g e L is tE x a m p le

Vom utiliza un control de tip ImageList ca surs de imagini pentru un control


PictureBox. Reinei c un PictureBox nu se poate conecta direct la ntreaga list
de imagini, aa cum o fac alte controale mai evoluate, ca ListView sau TreeView.
n aceast aplicaie, la fiecare acionare unui buton, se acceseaz cte o
imagine din ImageList i imaginea se afieaz n PictureBox.
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


ImageListExample.

2.

Aducei din Toolbox pe suprafaa formei un control de tip PictureBox i


un buton.

3.

Cutai opt imagini de mrime medie i salvai-le


ntr-un folder oarecare.

4.

Selectai controlul PictureBox. n panoul


Properties, setai pentru proprietatea SizeMode
valoarea strechlmage. Aceasta ntinde
imaginea pe toat suprafaa controlului. Setai ca
imagine iniial pentru proprietatea Image, una
dintre cele 8 imagini pe care le-ai pregtit pentru
acest proiect:

5.

Selectai butonul i stabilii pentru proprietatea


Text, valoarea Urmtoarea Imagine.

6. Din Toolbox, tragei pe suprafaa formei un


control de tip ImageList. n mod automat, n fray-ul Form Designer-ului
apare numele referinei: imageListl.
7.

Apsai click pe sgeata mic din colul dreapta sus al numelui


imageListl n designer tray. Stabilii ImageSize la valorile 32 i 32 i
adncimea de culoare la valoarea Depth32Bit.
j

'

I mageLi st Tasks

{ d P imageListl
.................... .......... Image Size

32; 32

j Image Bit Depth ' Depth32Bit


Error List

8.

"

Choose images.........................

Alegei Choose images. n Editorul Coleciilor de Imagini, adugai pe rnd


cte o imagine la ImageList. Cifrele din stnga reprezint poziiile
imaginilor n colecie. Poziiile se pot schimba, acionnd sgeile:

236

Partea a II-a. Programare Windows cu Visual C# Express Edition

Members:

caine.jpg properties:

0
1 E 3

g ira fa .jp g

2 F a

g o rila .jp g

3 E 3

p is ic a .jp g

i i i

B Mise
0

4 r t ' i tig r u .jp g

j; ; . HcrizoritaiRescbt
............
Name
caine.jpg

6 1 V s-l v e v e r ita .jp g

fc p ixe ro m ^ i

151 f '
'
. Formas32fcppA?gb

7 1

Iii}.1; R3ArOt'IYlr

MemaryBmp

5 O

0 :

u rs .jp g

v u ltu r .jp g

0 _.::e

..... ................. i
9 .,

Add

Remove

]
OK

9.

Cancel

Declarai n clasa Form l, n fiierul Form1.cs, cmpul privat count. Acesta


reprezint indexul imaginii din imageList, care se afieaz la un moment
dat n PictureBox:
private int count = 0;

10. Vom trata evenimentul Click pentru buton. Acionai dublu click pe
suprafaa lui. Scriei codul evideniat cu Bold, n handler-ul de eveniment:
private void buttonl_Click(object sender, EventArgs e)

{
// Atribuim proprietatii Image imaginea din
// ImageList corespunztoare indexului count % 8
pictureBoxl.Image = imageListl.Images[count % 8];
count++;

}
11. Compilai i lansai n execuie cu F5.

Capitolul 7.

Controalele Windows Forms

237

Imaginea se schimb la fiecare click.

De retinut:

Obiectele de tip ImageList rein colecii de imagini, care se utilizeaz de


ctre alte controale.
Toate imaginile se formateaz n mod automat ia aceleai dimensiuni i
adncimi de culoare precizate n momentul adugrii n ImageList,
indiferent de formatul iniial.
Imaginile se acceseaz cu ajutorul operatorului de indexare. De exemplu,
imageListl.images [3] ; reprezint a patra imagine din colecia referit
de imageListl. Atenie la acest exemplu! n colecia aceasta trebuie s
existe cel puin 4 imagini, altfel images [3] duce la aruncarea unei
excepii.

Controlul ListView
ListView este un control complex, destinat afirii unei liste de itemi.
Panoul din dreapta al aplicaiei Windows Explorer implementeaz un
ListView. Control Panel este un alt exemplu cunoscut de ctre toat lumea.
Pentru fiecare item din list controlul afieaz un text i un icon.
Itemii se pot afia n cinci moduri diferite. Cele cinci moduri sunt determinate
de valorile pe care le poate avea proprietatea view, a clasei ListView.

Modurile de afiare ntr-un ListView


Valorile posibile ale proprietatii View determin cele cinci moduri de
afiare. Aceste valori sunt:

L a r g e lc o n

Afieaz iconuri mari (32x32 pixeli), cu text dedesupt,


aliniate de la stnga la dreapta i de sus n jos__________

238

Partea a II-a. Programare Windows cu Visual C# Express Edition

Smalllcon
List
Details

Tile

Afieaz iconuri mici (16x16 pixeli), cu eticheta Tn dreapta


Afieaz iconuri mici (16x16 pixeli), cu eticheta n dreapta.
Itemii sunt aranjai n coloane, fr header de coloan.
- Fiecare item apare pe o singur linie. Informaiile
suplimentare despre item sunt date de subitemi. Subitemii
sunt aranjai pe colane diferite, pe aceeai linie. Coloana
cea mai din stnga conine un icon mic i un text.________
- Afieaz iconuri mari, cu text n dreapta acestuia,
reprezentnd informaiile din subitemi._________________

IMPORTANT!
Fiecare item ntr-un control ListView, este o instan a clasei ListViewltem.

Principalii membri ai clasei ListView


Clasa conine numeroase metode, proprieti i evenimente, graie crora
are multiple caliti, lat cteva :
S Suport selecia simpl i multipl a itemilor.
S Tratatnd corespunztor a evenimentele de la tastatur i mouse, itemii
pot deveni activi, declannd aciuni ca deschidere de fiiere, lansare de
aplicaii, etc.
S Se poate folosi pentru afiarea informaiilor dintr-o baz de date, a
informaiilor din fiiere, de pe disc, sau a informaiilor din aplicaii.
Principalii membri ai clasei sunt:
Proprieti:
- Depoziteaz colecia de obiecte de tip ListViewltem
care reprezint subitemii.
- Returneaz colecia de obiecte de tip ColumnHeader
care sunt afiate n ListViewControl.
- Permite specificarea modului de afiare a itemilor n list
- Indic obiectul imageList care conine iconurile folosite
la afiarea itemilor, atunci cnd proprietatea view are
valoarea Largelcon
- Indic obiectul ImageList care conine iconurile folosite
atunci cnd proprietatea view are oricare alt valoare n
afar de Largelcon
- Cnd este setat true, se pot selecta mai muli itemi odat

Items
Collumns
View
LargelmageList

SmallImageList

MultiSelect

Metode:
Clear ()
BeginUpdate()
EndUpdate()

nltur toi itemii din control


Prima
metod
suspend
redesenarea
controlului
ListView la fiecare adugare a unui item n situaia n
care se adaug un mare numr de itemi.
Se apeleaz a doua metod dup terminarea operaiei de
update, pentru a permite controlului s se redeseneze.

Capitolul 7.

Controalele Windows Forms

239

Evenimente:
ColumnClick
SelectedlndexChanged

Se declaneaz la click pe header-ul unei coloane


Se declaneaz cnd utilizatorul selecteaz sau
deselecteaz un item

Aplicaia L istV ie w E x a m p le
Proiectul afieaz o list titluri de cri, n toate modurile de afiare:
Largelcon, Smalllcon, List, Tile, Detail. n modul Detail, fiecare item (carte) are cte
doi itemi suplimentari, afiai n coloana a doua i a treia: numele autorului i
editura care a publicat cartea. De asemenea, tot n modul Detail este disponibil
opiunea de Grid.
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


ListViewExample.

2.

Tragei din Toolbox pe suprafaa formei un control de tip ListView un


control GroupBox, cinci controale RadioButton, un CheckBox i un
buton de apsare i aranjai-le astfel:

3.

Cutai cteva fiiere de tip imagine cu coperi de cri i salvai-ie ntr-un


folder oarecare. Notai-v pentru fiecare carte, titlul, autorul i editura.

4.

Aducei din Toolbox dou controlale de tip ImageList. n fray-ul Form


Designer-ului apar imageListl i imageList2. Ele reprezint referinele
spre colecia de icon-uri mici necesare n modurile Smalllcon, List i
Detail, respectiv spre colecia de icon-uri mari, necesare n modurile
L a r g elcon i Tile.
5. Setai pentru imageListl, dimensiunile (16, 16) i adncimea de culoare
8 bii. Setai pentru imageList2 dimensiunile (48, 48) (putei decide i
alte dimensiuni) i adncimea de culoare 32 de bii:

240 Partea a II-a. Programare Windows cu Visual C# Express Edition

SP1imageListl

......................... m Im ag e L is t Tasks
j ifjP imageList2
Image Size
i S ill
Image Bit Depth

Error List

Depth32Bit

v '

Choose images

6.

Adugai aceleai imagini n ambele obiecte de tip ImageList, acionnd


Choose images.

7.

Dorim s populm controlul ListView la ncrcarea formei. Facei dublu


click pe suprafaa formei, pentru a trata evenimentul Load. n corpul
handler-ului evenimentului, scriei codul evideniat n Bold:
private void Forml_Load(object sender, EventArgs e)

{
// Controlul listViewl preia coleciile de iconuri
// mici i de iconuri mari
listViewl.SmallImageList = imageListl;
listViewl.LargelmageList = imageList2;
// Suspendm redesenarea listei ct timp adugm
// itemi
listViewl.BeginUpdate();
// Pentru modul Detail, adugm trei coloane avnd
// n header-e textele "Crti", Autor, "Editura".
// Limile coloanelor sunt 150, 100 i 110 i
// alini erea orizontal
listViewl.Columns.Add("Crti C#", 150,
HorizontalAlignment.Left);
listViewl.Columns.Add("Autor", 100,
HorizontalAlignment.Left);
listViewl.Columns.Add("Editura", 110,
HorizontalAlignment.Left);
// Adugm primul item n list. Este un obiect de
// tip ListViewItem
ListViewItem itl = new ListViewItem();
// Indexul icon-ului din listlmagel i listlmage2.
// Putei avea mai muli itemi cu acelai index,
// deci cu acelai icon
itl.Imagelndex = 0;
// Textul itemului
itl.Text = "C# 2008 Code Book";
// Crem cei doi subitemi. Putei avea orici
// subitemi pentru un item, dar avei grij s
// creai tot attea coloane.

Capitolul 7.

Controalele Windows Forms

241

itl.Subitems.Add("Jurgen Bayer");
it l.Subitems.Add("Addison-Wesley 2007");

// Adugm itemul n controlul ListView


listViewl.Items.Add(itl);

// Se creaz al doilea item, n acelai mod


ListViewltem it2 = new ListViewItem();
it2.ImageIndex = 1;
it2.Text = "Beginning C# 2008";
it2.Subitems.A d d ("Karl Watson");
it2.Subitems.Add("WROX 2008");
listViewl.Items.Add(it2);

// Creai ceilali itemi ca mai sus


// . . .
/ / A m terminat adugarea de itemi.
// Acum permitem controlui s se redeseneze
listViewl.EndUpdate();

}
8.

Acionai dublu click pe radio butonul cu eticheta Large Icons. Tratm


evenimentul CheckedChanged. n Editorul de Cod, scriei:
private void radioButtonl_CheckedChanged(object sender,
EventArgs e)
{
// Proprietatea View primete valoarea Largelcon.
// Largelcon este un membru al enumerrii View
listViewl.View = View.Largelcon;

// Dezactivm csua de validare pentru G r i d .


// Efectul G r i d e posibil numai n modul D e t a i l
checkBoxl.Enabled = false;

}
9. Acionai dublu click pe radio butonul cu eticheta Tile. n corpul handler-ului
de eveniment, scriei codul:
listViewl.View = View.Tile;
checkBoxl.Enabled = false;

10. Acionai dublu click pe radio butonul cu eticheta Small Icons. n corpul
handler-u\u\ de eveniment, scriei codul:
listViewl.View = View.SmallIcon;
checkBoxl.Enabled = false;1

11. Acionai dublu click pe radio butonul cu eticheta List. n corpul hand/er-ului
de eveniment, scriei:

242

Partea a II-a. Programare Windows cu Visual C# Express Edition


listViewl.View = View.Tile;
checkBoxl.Enabled = false;

12. Acionai dublu click pe checkbox-ul cu eticheta Grid. Tratm evenimentul


CheckedChanged. n handler-ul de eveniment, scriei codul marcat cu
Bold:
private void checkBoxl_CheckedChanged(object sender,
EventArgs e)

{
// Dac tocmai s-a selectat checkbox-ul
if (checkBoxl.Checked)
{
// atunci punem griduri.
listViewl.GridLines = true;

}
else
{
// Dac tocmai s-a deselectat controlul
// scoatem gridurile
listViewl.GridLines = false;

}
13. Acionai dublu click pe butonul Ieire. Tratm evenimentul Click. n corpul
metodei de tratare, scriei:
Application.Exit();

// Ieire din aplicaie

14. Compilai proiectul i rulai cu F5.


La rulare, se obine:
Vedere Large Icons:

| Visual C8 2008

VisualC8.NET

Visual Studio
2008

v :

,-----
l
lesire

Capitolul 7.

Controalele Windows Forms

243

Vedere n modul 77/e:

Vedere n modul Detail cu gridurile activate:


f vv
k * m ?

Crti Ctt

v sfv

Autor

Editura

1 * * * * Ctt 2008 Code Book

Jurgen Bayer

jjjjj; Beginning Ctt 2008


|| C tt 3.0 Unleashed
j p - Essential C# 3.0

Karli Watson

Addison-Wesley...
WROX 2008

Joseph Mayo

InformIT 2007

l i . Head First Ctt

Mark Michaellis
Andrew Stellman

InformlT 2007
APRESS 2007

O Tile

PPro Ctt 2008 3.5 Platform


ii Visual Ctt 2008

Andrew T roelsen
Dirk Frischalowski

APRESS 2007
Addison-Wesley 2...

O Small Icons

James Foxall

InformlT 2008

Lars Powers
Rob Eisenberg

Addison-Wesley 2...

j B * Visual Ctt .MET


1 U f Visual Studio 2008
i f l l f WPF in 24 hours

Moduri Afiare
O Large Icons

O List
@ Detail

Addison-Wesley 2... ;
P I Grid

i
!
]

Ieire

Celelalte moduri de afiare funcioneaz de asemenea n mod corespunztor.

Observaii:

n multe situaii itemii nu se introduc n mod manual. Acetia pot fi ncrcai


din fiiere XML, sau din baze de date, aa cum vom vedea n capitolele
urmtoare.
n proiectul acesta, itemii au fost adugai programatic. Este una dintre
cele mai simple variante, dar nu unica. Mai exist i alte variante de
adugare programatic a itemilor, pe care le putei gsi n literatura de
specialitate.

244 Partea a II-a. Programare Windows cu Visual C# Express Edition

Adugarea d esig n tim e a itemilor ntr-un ListView


Selectai controlul ListView. n fereastra Properties apsai butonul cu
eticheta (...) din dreapta proprietii Items. Se deschide dialogul ListViewltem
Collection Editor. Apsai butonul Add pentru a aduga itemi.
m
Members;

ListViewltem: {} p roperties:

_0 I ListViewltem: {}
l l ListViewltem: {}

ListViewltem: {}
....2 j UstVSewItem;
{}

0 m
0

Text

... ...

ToolTipText
U seltem StyleFor True

B Behavior
Group

(none)

Im agelndex

| (none)

S tatelm ag eln d ex I

I (none)

Im ageKey

B Data
5ubltems

(none)

(Collection)

Tag

E Display
IndentC ount

Cancel

n panoul din dreapta, selectai Subitems i apsai butonul din dreapta. n dialogul
ListViewSubitem Collection Editor, adugai pe rnd subitemii necesari pentru
fiecare item:
E
Members:

ListViewSubitem: {Beginning C# 2008} pr..

o m sm m m ssm m m
iJjListViewSubItem: -{Karl Watson}
T j ListViewSubitem: <WROX 2008}

I
[~4~|

HTji .
E l Data
Tag
E Mise
BackColor
E Font
ForeColor

| Window

Microsoft Sans erif;


|

WindowText

Name

ListViewSubItem3

Text

Beginning C# 2008

Add
Cancel

De retinut:

>
>
>

Dac implementai afiarea Detail, atunci este nevoie s adugai coloane


(obiecte de tip CoiumHeader).
Itemii sunt obiecte diferite de tip ListViewltem.
Numrul subitemilor trebuie s coincid cu numrul coloanelor.

Capitolul 7.

Controalele Windows Forms

245

Probleme propuse
1. Aducei urmtoarea facilitate aplicaiei ListViewExample: la apsarea unui
buton, se activeaz opiunea de selectare a ntregului rnd, atunci cnd
utilizatorul face click pe un item n modul Detail.
2.

n aplicaia ListViewExample, introducei cte un mic icon care preced


textul n header-ul fiecrei coloane (modul Detail).
Indicaie: Utilizai constructorul adecvat al clasei ColuranHeader, astfel:
ColumnHeader c = new ColumnHeader(3);
// 3 este indexul iconului
c .Text = "C# 2008"
listViewl.Columns.Add(c);
// etc

3.

* Creai o aplicaie care preia ntr-un ListView informaiile despre fiierele


i folderele care se gsesc ntr-un folder dat. Folderu se alege cu ajutorul
controlului predefinit FolderBrowserOialog.

4.

Creai o aplicaie care permite editarea etichetelor itemilor unui ListView.

Controlul TreeView
Controlul afieaz o colecie ierarhic de elemente care se numesc noduri.
Fiecare nod este o instan a clasei TreeNode. Proprietatea Nodes a controlului
memoreaz aceast colecie de noduri.
Nodurile se creaz programatic relativ simplu. Creai un proiect de tip
Windows Forms i tratai evenimentul Load generat de form (dubiu click pe
suprafaa ei), apoi scriei codul:
private void Forml_Load(object sender, EventArgs e)

{
// Instaniem un TreeView
TreeView tw = new TreeView();
// Crem un prim nod cu eticheta "Biei"

TreeNode t n l - new TreeNode( ) ;


tnl.Text = "Biei";
// Adugm nodul n control
t w .Node s .A d d (tnl) ;
// Crem al doilea nod cu eticheta "Fete"
TreeNode tn2 = new TreeNode();
tn2.Text = "Fete";
// Adugm nodul n control
t w .Nodes.A d d (tn2);

246

Partea a II-a. Programare Windows cu Visual C# Express Edition


// Adugm controlul pe form
this.Controls.A d d (tw);

Crearea ierarhiilor
Fiecare nod ntr-un TreeView poate fi printe pentru alte noduri.
Se pot crea ierarhii arborescente cu oricte niveluri. Modificm exemplul anterior,
prin adugarea de noduri child nodurilor Baieti' i Fete:
// Instaniem un TreeView
TreeView tw = new TreeView();
// Stabilim poziia pe form i dimensiunea controlului:
tw.Location = new System.Drawing.Point(12, 12);
tw.Size = new System.Drawing.Size(153, 133);
// Crem un prim nod cu eticheta Baieti
TreeNode tnl = new TreeNode();
tnl.Text = "Baieti";
// Crem un nod child pentru Baieti:
TreeNode tnll;
II Referina tnnl indic nodul nou creat (cu eticheta Marius)
tnll = tnl.Nodes.Add("Marius");
// Nodul M a r i u s va fi printe pentru alte dou noduri:
tnll.Nodes.Add("Profesie");
tnll.Nodes.Add("Hobby");
II Al doilea nod child pentru Baieti:
tnl.Nodes.A d d ("Valentin");
// Adugm nodul Baieti n control:
tw.Nodes.Add(tnl);

Capitolul 7.
//

Crem

al

doilea

Controalele Windows Forms


nod

rdcin

cu

eticheta

247

Fete :

TreeNode tn2 = new TreeNode();


tn2.Text = "Fete";
tn2.Nodes.Add("Alina");
tn2.Nodes.Add("Teodora") ;
// A d u g m n o d u l Fete
tw .Nodes.Add(tn2 );
//

Adugm

controlul

n
pe

control
form

this.Controls.Add(tw);

B Marius
Profesie
H obby
Valentin
S- Fete
Alina
T eodora

Imaginea anterioar reprezint ceea ce se obine la rulare.

Important:
Metoda A dd() returneaz ntotdeauna o referin la nodul nou creat.
Aceasta nlesnete adugarea de noduri child.

Accesarea indexat a nodurilor


Subnodurile care fac parte din colecia Nodes a nodului curent se pot
accesa cu ajutorul operatorului de indexare. Relum exemplul anterior. Prezentm
o alternativ de construire programatic a controlui, bazat pe accesarea indexat:
// Instaniem un TreeView
TreeView tw = new TreeView();
//

Stabilim

poziia

pe

form

dimensiunea

controlului:

tw.Location = new System.Drawing.Point(12, 12);


tw.Size = new System.Drawing.Size(153, 133);
//

Adugm

control

un

prim

nod:

tw.Nodes.Add("Biei");
// A d u g m s u b n o d u r i l e Marius si Valentin
tw.Nodes[0].Nodes.Add("Marius");
tw.Nodes[0].Nodes.Add("Valentin");

pentru

Biei

// A d u g m s u b n o d u r i l e Ocupaie si Hobby p e n t r u Marius:


tw.Nodes[0].Nodes[0].Nodes.Add("Ocupaie");
tw.Nodes[0].Nodes[0].Nodes.Add("Hobby");

248

Partea a II-a. Programare Windows cu Visual C# Express Edition

// Adugm subnodurile Varsta i coala pentru Valentin:


tw.Nodes[0].Nodes[1].Nodes.Add("Varsta");
tw.Nodes[ 0 ] .Nodes[1].Nodes.Add("coala");
// Adugm controlul pe form:
this.Controls.Add(tw);

La execuie se obine :

Principalii membri ai clasei TreeView


Controlul TreeView are multiple capabiliti. Descriem cteva dintre acestea:
>
>
>
>
>

Poate afia imagini asociate fiecrui nod.


Poate afia opional checkbox-uri asociate nodurilor.
i poate schimba aparena setnd corespunztor proprieti de stil.
Poate rspunde la diverse evenimente, cum ar fi click sau dublu
click pe eticheta unui nod.
Se poate folosi pentru afiarea informaiilor dintr-o baz de date, a
informaiilor din fiiere, de pe disc, sau a informaiilor din aplicaii.

Aceste caliti se datoreaz mulimii de metode, proprieti i evenimente ale


clasei. Dintre acestea menionm:
Proprieti:
Nodes

LabelEdit
ChectcBoxes

SelectedNode
PathSeparator

Depoziteaz colecia de obiecte de tip TreeNode a


controlului. Fiecare nod are la rndului lui proprietatea
Nodes, care gzduiete propriile noduri child.
Stabilete dac eticheta text a unui nod poate fi editat
Stabilete dac se afieaz un checkbox lng etichetele
nodurilor
Returneaz sau modific nodul selectat.
Returneaz sau seteaz stringul separator folosit n calea
spre noduri. Calea spre un nod este un set de etichete de
noduri separate prin delimitatorul PathSeparator.

Capitolul 7.

Controalele Windows Forms

249

Metode:
CollapseAll ()
BeginUpdate()
EndUpdate()

Colapseaz ramurile arborelui (Inversul expandrii)


Suspend redesenarea controlului TreeView la fiecare
adugare a unui item n situaia n care se adaug un
mare numr de itemi.
Se apeleaz a doua metod dup terminarea operaiei de
update, pentru a permite controlului s se redeseneze.
Returneaz nodul care se gsete la locaia specificat

GetNodeAt()

Evenimente:
BeforeCollapse
Af terCollapse
BeforeExpand
AfterExpand

Se declaneaz nainte, respectiv dup colapsul unui


nod
Se declaneaz nainte, respectiv dup expandarea
unui nod

Parcurgerea i prelucrarea nodurilor


Uneori trebuie s vizitai toate nodurile unui TreeView pentru o prelucrare
oarecare. Amintii-v c un TreeView este o structur de date arborescent. Vei
nelege din ce cauz parcurgerea unei asemenea structuri se face cu o metod
algoritmic. Propunem o parcurgere n adncime:
private void ParcurgTreeView(TreeNodeCollection noduri)

{
foreach (TreeNode nod in noduri)

{
PrelucrezNod(nod);
ParcurgTreeView(nod.Nodes);

}
}
private void PrelucrezNod(TreeNode nod)

1
// Prelucrarea dorit pentru nod
// Aici, pentru verificare afim doar eticheta
MessageBox.Show(node.Text + "\n");

}
private void buttonl_Click(object sender, EventArgs e)

{
//
ParcurgTreeView(treeViewl.Nodes);

Partea a II-a. Programare Windows cu Visual C# Express Edition

250

De retinut:

reprezint colecia de noduri rdcin n arbore.


Fiecare nod din aceast colecie are la rndul lui proprietatea N o d e s , care
refer nodurile de pe al doilea nivel, etc.
TreeNodeCollection este un tip de date care reprezint o colecie de
obiecte TreeNode.
treviewl.Nodes

Aplicaia T reeV iew E xam p le


Proiectul pe care l propunem utilizeaz un combobox pentru selectarea
dr/Ve-urilor sistemului. n funcie de discul selectat, ntr-un control TreeView se
afieaz structura arborescent de directoare discului.
Elemente de noutate:
Obinerea informaiilor despre discuri cu metoda:
D r i v e l n f o .G e t D r i v e s ()

Obinerea numelor subdirectorilor unui director specificat, cu metoda:


D i r e c t o r y .G e t D i r e c t o r i e s ()

Parcurgerea recursiv a structurii de directoare a unui disc, n scopul


populrii controlului TreeView.
Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


Tree ViewExample.

2.

Aducei din Toolbox pe suprafaa formei controalele: un Labei, un


ComboBox, un Button i un TreeView i aranjai-le astfel:

3.

Modificai culorile controlulului T r e e V i e w dup preferin: culoarea


fundalului (proprietatea B a c k C o l o r ) , culoarea etichetelor ( F o r e C o l o r ) i
culoarea liniilor punctate ( L i n e C o l o r ) .

Capitolul 7.
4.

Controalele Windows Forms

251

Adugai directiva using System. IO;

5. n fiierul Form1.cs, n corpul clasei Forml, scriei secvenele de cod


urmtoare:
public Forml()

// Constructoul clasei

{
InitializeComponent();
// Populeaz comboBoxl cu toate drive-urile
DriveInfo[] drives = Drivelnfo.GetDrives();
comboBoxl.Iterns.AddRange(drives);

}
// Cmpuri private. Reprezint caracterul de separare
// a cii de director, respectiv litera discului
private char[] sep = new char[] { '\ \ ' };
private string drvLetter = nuli;
// Deep First n structura de directoare
private void PopulateTreeView(string path,
TreeNode node)

{
stringf] dirs = Directory.GetDirectories(path);
string[] auxs;
foreach (string dir in dirs)

{
auxs = dir.Split(sep);
TreeNode tn =
new TreeNode(auxs[auxs.Length - 1]);
node.Nodes.Add(tn); // Adaug subdirectorul
PopulateTreeView(dir, tn) ;

}
}
6.

Aplicaia trebuie s reacioneze la alegerea unui item n combobox. Tratm


evenimentul SelectedlndexChanged pentru comboBoxl. Pentru aceasta,
acionai dublu click pe acest control. n corpul hand/er-ului de eveniment,
scriei codul evideniat n bold:
private void comboBoxl_SelectedIndexChanged(
object sender, EventArgs e)

{
// Obinem textul itemului selectat n combobox
drvLetter =
comboBoxl.Items[comboBoxl.Selectedlndex].ToString();
// Suspendm redesenarea controlului
treeViewl.BeginUpdate();
// tergem toat colecia de noduri
treeViewl.Nodes.Clear() ;

wm

252

Partea a II-a. Programare Windows cu Visual C# Express Edition

// Adugm eticheta drive-ului ca nod rdcin


treeViewl.Nodes.Add(drvLetter);
drvLetter +=
// Concatenez caracterul '\ '
// Explorarea ncepe de la rdcina drive-ului
PopulateTreeView(drvLetter, treeViewl.Nodes[0]);
treeViewl.EndUpdate();

7. Acionai dublu click pe butonul Ieire. n handler-ul evenimentului Click,


scriei:
Application.Exit();

8.

Compilai i rulai cu F5.

La rulare obinei:

Observaie:

Cu metoda recursiv se parcurge ntreaga structur de director a drive-ului


curent. Din aceast cauz, actualizarea controlului TreeView este lent pentru un
disc ncrcat.

De retinut:

Clasa Directory din spaiul de nume System.IO furnizeaz metode


statice pentru creare, copiere, mutarea, redenumire de directori.
Clasa Driveinfo din spaiul de nume System.IO conine metode i
proprieti pentru determinarea informaiilor referitoare la drive-uri.
Metoda treeViewl .Nodes .Clear () ; terge toate nodurile din
colecie.

Capitolul 7.

Controalele Windows Forms

253

Probleme propuse
1.

Creai o aplicaie de tip WindowsForms. Forma conine un control


TreeView. Populai design time controlul cu noduri.
Indicaie: n fereastra Properties, acionai butonul cu eticheta (...) aflat
n dreapta proprietii Nodes. n dialogul TreeNode Editor, adugai noduri
apsnd butoanele Add Root i Add Child.

2.

Implementai aplicaiei TreeViewExample urmtoarea facilitate: fiecare nod


are lng etichet un checkbox.

3.

* Modificai aplicaia TreeViewExample de aa manier nct nici un nod


s nu se adauge n TreeView dect n momentul cnd se expandeaz
printele su n control. Un nod se expandeaz prin click pe cruciulia din
dreptul su. n felul acesta aplicaia va lucra mai rapid.

4.

Implementai un file browser cu funcionalitate asemntoare Windows


Explorer. Aplicaia trebuie s afieze n panoul din dreapta fiierele aflate
n directorul care este selectat n panoul din stnga. De asemenea, la
dublu click pe un fiier executabil n panoul din dreapta, acesta s se
lanseze n execuie.
Indicaie: Utilizai un SplitContainer. n panoul din stnga aducei un
control TreeView, iar n cel din dreapta un ListView. Pentru obinerea
fiierelor
dintr-un
director
oarecare,
apelai
metoda
D ir e c t o r y . G e tF ile s (). Pentru lansare n execuie, utilizai metoda
S y s te m .D ia g n o s tic s . P ro ce ss. S t a r t ( ) .

Controalele Web Browser i StatusStrip


Dac v-ai gndit s integrai un browser Web n aplicaia dumneavoastr,
atunci cu Visual C# Express Edition 2008 aceasta este o sarcin simpl, deoarece
mediul include un control de tip WebBrowser.

Aplicaia W eb B ro w serE xam p le


n acest proiect utilizm un control de tip WebBrowser, un control
StatusStrip pentru vizualizarea ncrcrii paginiii curente i un ToolStrip pentru
butoane i bara de navigare. Urmai paii:
1.
2.

Creai un nou proiect de tip Windows Forms cu numele


WebBrowserExample.
Pe forma aplicaiei aducei din Toolbox un control de tip ToolStrip, un
control de tip StatusStrip i un control de tip WebBrowser.

254

Partea a II-a. Programare Windows cu Visual C# Express Edition

3.

Selectai controlul ToolStrip. Adugai pe el un Labei, un TextBox i patru


butoane. Pentru fiecare buton, acionai click drept i alegei DisplayStyle,
apoi Text, pentru a afia text n loc de imagine.

4.

Selectai controlul StatusStrip. Acionai click drept i alegei un


ProgressBar.

5.

Selectai controlul WebBrowser. n fereastra Properties atribuii


proprietii
Dock
valoarea
FUI i
proprietii
URL
adresa:
http://www.google.com. Setai textele pentru butoane i aranjai totul astfel:

6,

Tratm evenimentul Click pentru butonul Search. Acionai dublu click pe


buton. n corpul metodei handler, scriei:
private void toolStripButtonl_Click(object sender,
EventArgs e)

{
// ncarc pagina de la adresa specificat
webBrowserl.Navigate(toolStripTextBoxl.Text);

}
7.

Tratm evenimentul Click pentru butonul Stop. Acionai dublu click pe


buton. n corpul metodei handler, scriei:
private void toolStripButton2 Click(object sender,
EventArgs e)

{
// Oprete ncrcarea paginii
webBrowserl.Stop();

Capitolul 7.
8.

Controalele Windows Forms

255

Tratm evenimentul Click pentru butonul Back. Dublu click pe buton. n


corpul metodei de tratare, scriei:
private void toolStripButton3_Click(object sender,
EventArgs e)

{
// Revenire la pagin aanterioar
webBrowserl.GoBack();

}
9.

Tratm evenimentul Click pentru butonul Refresh. Dublu click pe buton. n


corpul metodei de tratare, scriei:
private void toolStripButton4_Click(object sender,
EventArgs e)

{
// Rencrcarea paginii de la URL-ul curent
webBrowserl.Refresh();

}
10. n progress bar-ul integrat n StatusStrip dorim s vizualizm progresul
ncrcrii paginii. n acest scop, tratm evenimentul ProgressChanged
pentru controlul WebBrowser. Selectai controlul i acionai dublu click pe
acest eveniment n fereastra Properties. Introducei codul:
private void webBrowserl_ProgressChanged(object sender,
WebBrowserProgressChangedEventArgs e)

{
// Seteaz Maximum la numrul total de b y t e s pe
// care l ocup documentul care se descarc
toolStripProgressBarl.Maximum =
(int)e.MaximumProgress;
// Seteaz Value la numrul de b y t e s care au fost
// downloadai pn n prezent
toolStripProgressBarl.Value =
(int)e.CurrentProgress;

}
11. n momentul n care documentul este descrcat, dorim s ne asigurm c
progress bar- ul este la valoarea maxim. Tratm evenimentul
DocumentCompleted declanat de WebBrowser cnd documentul este
complet descrcat. Dublu click pe acest eveniment n Properties. n
metoda de tratare, introducei codul:
private void webBrowserl_DocumentCompleted(
object sender, WebBrowserDocumentCompletedEventArgs e)

{
toolStripProgressBarl.Value =
toolStripProgressBarl.Maximum;

Partea a II-a. Programare Windows cu Visual C# Express Edition

256

12. Compilai i rulai cu F5.


La rulare, aplicaia ncarc n mod automat pagina stabilit design time prin
proprietatea URL. n fereastra de navigare putei introduce oricarea alt adres:

Observaii:

Dac lucrai n Visual C# Express Edition 2005, atunci controlul


WebBrowser nu se gsete n mod implicit n Toolbar. Aceasta nu este o
problem, pentru c el exist ca i component .NET i l putei aduce n
Toolbar cu un click dreapta pe suprafaa liber de jos, apoi selectai
Chose Items... iar n tab-ul .NET Framework Components, alegei Web
Browser.

Clasa WebBrowser are metode prin care implementai aciunile specifice


ale unui browser: navigare, rencrcare, ntoarcere la URL-u\ anterior i
aa mai departe.

Capitolul 7.

Controalele Windows Forms

257

Integrarea WindowsMediaPlayer n aplicaii


Suntem siguri c v-ati ntrebat dac este greu s implementai player-e video
sau audio. Nu este uor. ns exist exist o cale mai simpl de a avea toate
acestea, prin integrarea componentei COM, WindowsMediaPlayer n aplicaia
dumneavoastr.
Ca s vedei cum se procedeaz, vom face urmtorul proiect:

Aplicaia W in d o w s M e d ia P la y erE x a m p le
Aplicaia utilizeaz componenta Windows Media Player i un control de tip

ToolStrip cu 5 butoane. Rolul butoanelor este acela de a efectua aceleai operaii


ca i butoanele implicite ale controlului. Ne vom servi i de dialogul predefinit
OpenFileDialog pentru alegerea unui fiier audio sau video de pe disc.
Urmai paii:
1.

Creeai un nou proiect de tip Windows Forms.

2.

Pe suprafaa designerului plasai un control de tip ToolStrip, pe care


adugai apoi cinci butoane care afieaz text. Etichetai cele cinci butoane
astfel: Open, Start, Stop, Pause, Resume.

3.

Plasai pe suprafaa formei un control de tip OpenFileDialog.

4.

W indows Media Player nu este disponibil n Toolbox n mod implicit, dar


poate fi adus acolo manual. l aducei cu un click dreapta pe suprafaa
liber de jos, apoi selectai Chose Items... iar n fab-ul COM Components,
alegei W indows Media Player. n continuare, plasai componenta pe
suprafaa des/gner-ului i setai-i proprietatea Dock la valoarea FUI i
proprietatea Name la valoarea wmp.

258

Partea a II-a. Programare Windows cu Visual C# Express Edition


5. Tratm evenimentul Click pentru butonul Open. Acionai dublu click pe
buton i scriei n metoda handler.
private void toolStripButtonl_Click(object sender,

EventArgs e)
{

// Dac s-a ales un fiier media i s-a apsat OK


if (openFileDialogl.ShowDialog() =
DialogResult.OK)
{
// Playerul nu va executa p l a y n mod automat
// la ncrcarea fiierului
w m p .settings.autoStart = false;
// Se ncarc fiierul ales de utilizator
wmp.URL = openFileDialogl.FileName;
}
}

6. Tratm evenimentul Click pentru butonul Start. Acionai dublu click pe


buton i introducei codul:
private void toolStripButton2_Click(object sender,
EventArgs e)
{
// Player-ul ruleaz fiierul ncrcat
wmp.Ctlcontrols.p lay();
}
7.

Tratm evenimentul Click pentru butonul Stop. Dublu click pe buton i


introducei codul:
private void toolStripButton3_Click(object sender,
EventArgs e)
{
// Oprete rularea
wmp.Ctlcontrols.stop();

8.

Tratm evenimentul Click pentru butonul Pause. Dublu click pe buton. n


metoda de tratare introducei codul:
private void toolStripButton4_Click(object sender,
EventArgs e)
{
// Pauz. La un nou apel play(), redarea continu
// din aceast poziie n fiier
w m p .Ctlcontrols.pause();
}

Capitolul 7.
9.

Controalele Windows Forms

259

Tratm evenimentul Click pentru butonul Resume. Dublu click pe buton. n


metoda de tratare introducei codul:
private void toolStripButton5_Click(object sender,

EventArgs e)
{
// Redarea se reia din poziia n care s-a ajuns
// la ultimul apel pause()
w m p .Ctlcontrols.play();

10. Compilai i rulai cu F5.


Putei rula att fiiere audio ct i video.

Observaie:
Controalele adugate manual au aceleai funcii cu cele ale butoanelor
implicite. A fost un exerciiu pentru cazul n care vrei s mascai bara standard i
s utilizai propriile controale pentru manevrarea player-ului.

260 Partea a II-a. Programare Windows cu Visual C# Express Edition

C a p ito lu l 8

Desenare n .NET cu Visual C#


GDI+ (Graphics Device Interface) este o interfa de programare a
aplicaiilor integrat sistemelor de operare Microsoft Windows XP i Windows
Server 2003.
Aplicaiile de tip Windows deseneaz elemente grafice cu ajutorul bibliotecii
de clase GDI+. O interfa pentru dispozitive grafice, aa cum este GDI+, permite
programatorilor s deseneze pe dispozitive grafice: ecran, scanner, imprimant, cu
ajutorul acelorai funcii, fr s trebuiasc s in seama de detaliile unui
dispozitiv de afiare particular.
Se pot desena linii, curbe, figuri geometrice, text, imagini. Clasele GDI+ se
gsesc n marea lor majoritate n spaiul de nume System.Drawing. Dintre
acestea, clasa System.Drawing.Graphics este cea mai utilizat.

Clasa Graphics
Clasa definete o suprafa de desenare GDI+. Metodele sale deseneaz pe
aceast suprafa, iar biblioteca GDI+ tie s trimit imaginea pe dispozitivul grafic
(monitor, imprimant, sau altceva).

Principalele metode ale clasei Graphics


Clear ()

DrawArc()
Drawlmage()
DrawLine()
DrawEllipse()

DrawRectangle()
Drawstring()
FillEllipse()

FillRectangle()

Cur suprafaa de desenare i o umple cu o culoare


de fundal specificat
Deseneaz un arc de elips
Deseneaz o imagine la o locaie dat
Deseneaz un segment specificat prin capetele sale
Deseneaz o elips specificat printr-un dreptunghi
care o mrginete
Deseneaz un dreptunghi
Deseneaz un text la o locaie specificat
Umple interiorul unei elipse cu ajutorul unei pensule
(obiect de tip Brush)
Umple interiorul unui dreptunghi cu ajutorul unei
pensule

Clasa nu rspunde la evenimente findc nu are membri de tip event. Dar folosete
evenimentul Paint al controalelor pentru a desena pe suprafaa lor.

Penie pentru desenarea formelor


Desenm cu ajutorul unui obiect de tip Graphics. Obiectul se obine n dou
moduri:

Capitolul 8. Desenare n.NET cu Visual C#


1.
2.

261

Prin intermediul parametrului de tip PaintEventsArgs al handler-ului


evenimentului Paint.
Cu ajutorul metodei CreateGraphi.es (), motenit de ctre toate
controalele de la clasa de baz Control.

Detaliem cele dou cazuri:

Cazul 1.
Creai un proiect nou de tip Windows Forms. Tratm evenimentul Paint al
formei. Selectai forma i n fereastra Properties acionai dublu click pe
evenimentul Paint. Scriei codul:

private void Forml__Paint (object sender, PaintEventArgs e)


{
// Peni de culoare roie i grosime 20
Pen p = new P e n(Color.Blue, 20);
Rectangle r = new Rectangle(new Point(50, 50),
new Size(200, 100));
e .Graphics.DrawRectangle(p, r);
p.Dispose ();
}
Compilai i rulai cu F5. Pe form s-a desenat un dreptunghi.

Hand/er-ului evenimentului Paint are un parametru e de tip PaintEventArgs.


Acesta returneaz un obiect de tip Graphics prin proprietatea Graphics:
e .Graphics.
IM P O R T A N T !
Pentru desenarea liniilor i a curbelor, avei nevoie de un obiect de tip
Graphics i un obiect de tip Pen (peni). Obiectul Graphics furnizeaz metodele
care deseneaz, iar obiectele de tip Pen depoziteaz atribute ale liniei, cum ar fi
culoarea, grosimea i stilul.

262

Partea a II-a. Programare Windows cu Visual C# Express Edition

Reinei c este o practic bun aceea de a elibera resursele deinute de


obiectul Pen, cu metoda Dispose(), n momentul n care nu mai avei nevoie
de el.

Cazul 2.
Metoda CreateGraphics (), se regsete n toate clasele derivate din

Control. Returneaz un obiect de tip Graphics. Este nevoie de aceast metod


cnd nu dorii s foloii un eveniment Paint pentru a desena.
Realizai un nou proiect de tip Windows Forms. Pe form plasai un buton.
Acionai dublu click pe buton pentru tratarea evenimentului Click,
n handler-ul evenimentului introducei secvena de cod evideniat cu Bold:
private void buttonl_Click(object sender, EventArgs e)
{
// Obinem un obiect Graphics
Graphics g = this.CreateGraphics ();
// Fabricm o peni
Pen p = new Pen(Color.Red, 3) ;
// Desenm o linie
g .DrawLine(p, new Point(20, 30), new Point(280, 30));
// Desenm un arc definit de dreptunghiul (50, 50, 200,
// 100). Unghiul de nceput e 0, iar cel de sfrit 360.
// Aceasta nsemn elips
g.DrawArc(p, 50, 50, 200, 100, 0, 360);
// Schimbm stilul peniei (linie punctat) i desenm
// un dreptunghi
p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
Rectangle r = new Rectangle(new Point(50, 50),
new Size (200, 100));
g.DrawRectangle(p, r);
p.Dispose();
}
La click pe butonul Deseneaz, pe suprafaa formei se deseneaz figurile:

Capitolul 8. Desenare n.NET cu Visual C#

263

Observaii

Un arc este o poriune a unei elipse. Ca s desenai o elips, apelai


metoda DrawEllipse (). Parametrii metodei DrawArc()
sunt
aceeiai cu cei ai metodei DrawEllipse (), cu diferena c
DrawArc () necesit un unghi de start i unul de baleiere, lat cum
desenai o elips:
Graphics g = this.CreateGraphics();
Pen p = new Pen(Color.Red, 3);
Rectangle r = new Rectangle(new Point(50, 50),
new Size(200, 100));
g.DrawEllipse(p, r);
p.Dispose();

Metodele de desenare ale arcelor i elipselor primesc ca parametri


coordonatele dreptunghiului care le ncadreaz.
Metodele sunt
suprancrcate. De exemplu, putei nlocui apelul:
g.DrawArc (p, 50, 50, 200, 100, 0, 360); CU apelul
g .DrawArc ( p , r, 0, 360); unde r este dreptunghiul definit

anterior.

Poligoane
Desenarea unui poligon se face foarte simplu, prin apelul metodei
DrawPolygon (). Metoda are ca parametri un obiect de tip Pen i un tablou de
puncte:
Graphics g = this.CreateGraphics();
Pen p = new P en (Color.Red, 3);
Point[] pt = { new Point(190, 90), new Point(140, 130),
new Point(150, 200), new Point(60, 100) };
// Deseneaz un poligon cu patru vrfuri
g .DrawPolygon(p, pt);
p.Dispose();

264 Partea a II-a. Programare Windows cu Visual C# Express Edition


Dac ne folosim de evenimentul Click al butonului n aplicaia anterioar, atunci la
click pe Deseneaz, avem:

Pensule pentru umplerea formelor


Figurile nchise se deseneaz cu penie. Interiorul lor se umple cu pensule.
Pensulele sunt obiecte de tip Brush.
Biblioteca GDI+ ofer cteva clase care definesc pensule: SolidBrush,
HatchBrush, TextureBrush, LinearGradientBrush, i PathGradientBrush.
Clasa SolidBrush este definit n spaiul de nume System.Drawing.
Celelalte pensule sunt n spaiul de nume System.Drawing.Drawing2D.
Cel mai simplu mod de a nva, este de a lucra cu aceste pensule. Vom realiza o
aplicaie ca modei.

Aplicaia B ru s h e s E x a m p le
Aplicaia umple trei elipse cu pensule diferite: o pensul solid, una de
haurare i una gradient liniar. n dreapta formei se va umple un dreptunghi cu o
pensul de tip TextureBrush, care utilizeaz ca element de umplere o imagine.
Urmai paii:
1.

Creai un nou proiect de tip Windows Forms A pplication, cu numele

BrushesExample.
2. n fiierul Form1.cs, n clasa Form l, introducei la seciunea directivelor
using, secvena:
using System.Drawing.Drawing2D;

Capitolul 8. Desenare n.NET cu Visual C#


3.

265

Tratm evenimentul Paint pentru form. Selectai forma. n fereastra


Properties, acionai dublu click pe evenimentul Paint. n corpul handlerului introducei codul:
private void Forml_Paint(object sender,
PaintEventArgs e)
{
Pen p = new Pen(Color.Red, 3);
// Crem un dreptunghi pentru elipse
int x = 10, y = 10, width = 200, height = 100;
Rectangle r = new Rectangle(x, y, width, height);
// Crem o pensul solid
SolidBrush s = new SolidBrush(Color.Aquamarine);
// Umplem elipsa cu pensula solid
e .Graphics.FillEllipse(s, r);
y = 120;
r = new Rectangle(x, y, width, height);
// Crem o pensul de haurare
HatchBrush h =
new HatchBrush(HatchStyle.DiagonalCross,
Color.Azure, Color.Black);
// Umplem elipsa cu pensula de haurare
e .Graphics.FillEllipse(h, r ) ;
y = 230;
r = new Rectangle(x, y, width, height);
// Crem o pensul gradient liniar
LinearGradientBrush lg = new LinearGradientBrush(r,
Color.Aqua, Color.BlueViolet,
LinearGradientMode.Horizontal);
// Umplem elipsa cu pensula gradient liniar
e.Graphics.FillEllipse(lg, r ) ;
x = 230; y = 15; width = 250; height = 310;
r = new Rectangle(x, y, width, height);
// Crem o pensul de textur
TextureBrush t =
new TextureBrush(Image.FromFile("pisica.jpg"));
// Umplem dreptunghiul cu pensula de textur
e.Graphics.FillRectangle(t, r);
p.Dispose();

Partea a II-a. Programare Windows cu Visual C# Express Edition

266

4.

Compilai, rulai cu F5.

La rulare, avem:

Observaii:
i

Constructorii claselor de tip brush primesc ca argumente culori, stiluri, etc,


prin intermediul membrilor anumitor enumerri. Ai remarcat enumerrile

Color, LinearGradientMode, HatchStyle.


0

Constructorul TextureBrush ( (Image .FromFile ("pisica .jpg" ) ) ;


ncarc o imagine. Dac se specific doar numele fiierului imagine,
atunci acesta este cutat n folderul n care se gsete fiierul assembly,
adic /bin/Debug sau /bin/Release.

Desenarea textului
GDI+ furnizeaz cteva clase care se ocup cu desenarea textului. Clasa
Graphics are n acest scop mai multe metode Drawstring (). V vei acomoda
cu utilizarea acestora, urmrind exemplul de mai jos:

Aplicaia D ra w S trin g E x a m p le
Ca s desenai cu metodele Drawstring () trebuie s pregtii un font i o
pensul. Aplicaia testeaz dou dintre metodele Drawstring (). Prima scrie un
text la o locaie specificat de un punct, iar a doua scrie un text ncadrat ntr-un
dreptunghi.

Capitolul 8. Desenare n.NET cu Visual C#

267

Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


Dra wStringExample.

2.

Tratm evenimentul Paint pentru form. Selectai forma. n fereastra


Properties, acionai dublu click pe evenimentul Paint. n corpul handlerului introducei codul:
private void Forml_Paint(object sender,
PaintEventArgs e)
{
String s = "Dau un regat pentru un cal";
// Crem un font preciznd familia, dimensiunea
// i stilul, apoi o pensul solid
Font f = new Font("Arial", 22, FontStyle.Bold);
SolidBrush b = new SolidBrush(Color.Red);
// Punctul colului stnga sus al stringului
PointF pt = new PointF(20.OF, 30.OF);
// De seneaz stringul
e.Graphics.DrawString(s, f, b, pt);
float x = 100.OF, y = 100.OF, width = 200.OF,
height = 80.OF;
RectangleF r = new RectangleF(x, y, width, height);
// Deseneaz dreptunghiul pe ecran
Pen p = new Pen(Color.Black);
e .Graphics.DrawRectangle(p, x, y, width, height);
// Formatm stringul. Aliniere centru
// (in dreptunghi)
StringFormat stF = new StringFormat();
stF.Alignment = StringAlignment.Center;
f = new Font("Times New roman", 24,
FontStyle.Italic);
// Desenez textul in dreptunghiul r
e.Graphics.DrawString(s, f, b, r, stF);
p.Dispose();
}

3.

Compilai i rulai cu F5.

La rulare, obinei:

Partea a II-a. Programare Windows cu Visual C# Express Edition

268

Dau un regat pentru un cal

Dau un regat
pentru un cal
O

Observaii:
Clasa StringFomat are proprietatea Alignment, care permite s setai
alinierea textului n dreptunghiul specificat.
PointF i RectangleF sunt structuri similare Point i Rectangle, cu
diferena c admit coordonate reale.
A doua metod Drawstring () constrnge stringul s se ncadreze n
dreptunghiul specificat i l trunchiaz n aa fel nct cuvintele individuale
nu se frng.

De retinut:

s
s
s

Cu ajutorul bibliotecii GDI+ se scriu aplicaii care deseneaz pe


dispozitive grafice (ecran, imprimante).
Clasa System.Drawing.Graphics este nucleul metodelor de desenare.
Pentru a desena o curb, avei nevoie de o peni (obiect de tip Pen), iar
pentru a umple sau haura o curb nchis, avei nevoie de o pensul
(obiect de tip Brush).
Obiectele de tip Graphics, cu care apelai metodele Draw, se obin n
dou moduri:
1. Din parametrul de tip PaintEventArgs al metodei de tratare a
evenimentului Paint.
2. Prin apelul metodei CreateGraphics ( ) .
Textul se deseneaz cu metodele DrawStringQ ale clasei Graphics.

Capitolul 8. Desenare n.NET cu Visual C#

269

Probleme propuse
1.

S presupunem c n handler-ul evenimentului Paint desenai pe


form un text. Stringul care trebuie desenat este itemul pe care s-a
fcut click ntr-un Listbox. Cum forai redesenarea formei (declaarea
evenimentului Paint) la click pe acel item ? Realizai o aplicaie care
implementeaz aceast cerin.
Indicaie: n handler-ul eveniementului SelectedlndexChanged al
controlului ListBox, preluai textul necesar i foai evenimentul Paint
cu metoda this. invalidate (). Aceasta invalideaz toat
suprafaa formei i oblig redesenarea.

2. Exist patru versiuni ale metodei DrawEllipse (). Testai-le pe toate


ntr-un mic proiect.
3.

Realizai un proiect n care vei desena icon-uri cu ajutorul celor dou


metode Drawicon() i vei afia imagini, utiliznd cteva versiuni
diferite ale metodei Draw image ().

4.

Utilizai metoda Graphics .RotateTransform(), pentru a roti un


string-uri i figuri geometrice care au fost desenate cu metodele
D r aw ().

5.

Realizai un mic proiect care utilizeaz metodele DrawPieQ,


DrawPolygon( ) ,FillPie() i FillPolygon( ) .

270

Partea a II-a. Programare Windows cu Visual C# Express Edition

Capitolul 9

XML cu C#
XML (extensible Markup Language) este un limbaj folosit pentru
descrierea datelor. Menirea XML este de a oferi un format standard, cu ajutorul
cruia aplicaii diferite, rulnd pe calculatoare diferite, pot s citeasc datele, s le
procese i s le scrie. Sistemele de calculatore i bazele de date conin date n
formate incompatibile. Datele XML se depoziteaz n format text. Aceasta a oferit
o cale de a depozita i de a transmite datele n mod independent de software-ul i
hardware-ul folosit.
XML specific date, dar i forma n care datele sunt organizate. Formatul
XML este folosit pentru depozitarea informaiilor din documente care conin
cuvinte, pentru meninerea listelor de preuri pe site-urile Web, detaliiile post-urilor
de pe bloguri. XML este vehiculul prin care se trimit cantiti mari de informaie prin
Internet. Datele schimbate ntre serviciile Web i aplicaiile clienilor sunt XML.

Sintaxa XML
Spre deosebire de HTML, XML este destinat depozitrii i transportului
datelor i nu afirii datelor. Tag-urile XML nu sunt predefinite. Trebuie s definii
dumneavoastr aceste tag-uri. Un fiier XML este un fiier cu text.
<?xml version="l.0" encoding="utf-8" ?>
<biblioteca>
<carte nrvol ="12">
<titlu>Oameni si soareci</titlu>
<autor>John Steinbeck</autor>
</carte>
<carte nrvol ="7">
<titlu>Darul lui Humboldt</titlu>
<autor>Saul Bellow</autor>
</carte>
</biblioteca>

Elementele sunt ceea ce scriei ntre parantezele unghiulare. Exemplu:


biblioteca, carte, titlu, autor, sunt elemente. Primul element, <?xml
version="l.0" encoding="utf-8" ?> indic versiunea XML cu care este
conform acest document i c e conform cu standardul de codificare Unicode
UTF-8.
Atributele descriu elementele.
Sintaxa pentru un element este:
<nume_elexnent nume_atribut ="valoare_atribut">
Coninutul elementului
</nume element>

Capitolul 9. XML cu C#

271

De exemplu, 12 i 7 sunt atributele elementelor carte. Atributele pot s lipseasc.


Comentariile n document se scriu astfel: <! Comentariu >

Criteriile pe care trebuie s le ndeplineasc un document valid XML sunt:


Documentul are exact un singur element root. n cazul de fa, elementul
root este biblioteca. Acesta ndeplinete rolul de container pentru restul
datelor.
Pentru fiecare element start trebuie s existe un element corespunztor
final. Exemplu: <carte> i </carte>.
Elementele nu se pot suprapune. Documentul urmtor este invalid:
<biblioteca>
<carte>
<titlu>Iarna vrajbei noastre</carte>
</titlu>
</biblioteca>

Clase .NET pentru Xml


Clasele .NET care lucreaz cu XML se gsec n spaiul de nume

System.Xml. Documentele XML au o structur arborescent. Trebuie s conin


ntotdeauna un unic element root. Acesta la rndul lui, conine atribute, valori, alte
elemente, i aa mai departe. Clasa XmIDocument se bazeaz pe aceeai idee.
Un document se obine prin instanierea clasei XmIDocument. Obiectul are
proprietatea ChildNodes, care este o colecie referine la nodurile child. Fiecare
element al coleciei este un obiect de tip XmINode. Fiecare obiect de tip XmINode,
are la rndul lui proprietatea ChildNode. Astfel, deoarece n fiecare nod se menin
referine spre nodurile child, se poate explora ntregul document.

Citirea informaiilor dintr-un document XML


f

Un document XML poate ndeplini rolul unei baze de date pentru aplicaia
dumneavoastr. Aplicaiile citesc deseori informaii din asemenea fiiere XML. Este
important, pentru c dac dorii s modificai acele informaii, schimbai coninutul
fiierului XML i nu e nevoie de refacei aplicaia.
Aplicaiile .NET pot s i scrie n fiiere .xml. De exemplu, dac setrile pe
care le face utilizatorul n aplicaie trebuie fie persistente, atunci e o idee bun s le
salvai ntr-un document XML.
Vom lucra n continuare cu clasa XmIDocument, pentru citirea datelor dintr-un
document (fiier) XML.

272

Partea a II-a. Programare Windows cu Visual C# Express Edition

Aplicaia X m lE x a m p le
Aplicaia citete date din fiierul Elevi, xml i le afieaz n mai multe
controale. ntr-un control de tip ListBox se afieaz numele elevilor, iar n alte trei
controale de tip TextBox, se afieaz coala, clasa i profilul clasei pentru elevul
care a fost selectat n list box.
Urmai paii:
1.

Creai un nou proiect de tip Windows Forms Application, cu numele


XmlExample.

2.

Aducei pe forma aplicaiei un control de tip ListBox, trei controale de tip


TextBox, dou butoane, un GroupBox, patru controale Labei i aranjai-le
astfel:

3.

Vom edita fiierul XML. Mediul integrat include un editor de fiiere XML.
Acesta se invoc acionnd click drept n Solution Explorer pe titlul
proiectului, apoi Add, i New Item... n dialogul care apare, alegei din
panoul Template, iconul XML File. Completai cmpul Name cu Elevi.xml.
n editor scriei urmtorul document:
<?xml version="l.0" encoding="utf-8" ?>
<absolventi>
<elev>
<nume>Ardelean Eugen</nume>
<scoala>C.N. Liviu Rebreanu</scoala>
<clasa>a Xll-a A</clasa>
<profil>matematica-informatica</profil>
</elev>
<elev>
<nume>Costea Andrei</nume>
<scoala>C.N. Andrei Muresanu</scoala>
<clasa>a IX-a C</clasa>
<profil>stintele naturii</profil>
</elev>

Capitolul 9. XML cu C#

273

<elev>
<nume>Nicoara Alina</nume>
<scoala>Gr. Sc. Industrial nr l</scoala>
<clasa>a Xl-a B</clasa>
<profil>telecomunicatii</profil>
</elev>
</absolventi>
Dup ce ai editat i ai salvat, copiai fiierul Elevi.xml din folderul
proiectului, n folderul /bin/Debug.
4.

n seciunea se directive a fiierului fiierul Form1.cs, introducei:


using System.Xml;

5.

Declarai dou cmpuri private n clasa Formf.


// d reine ntregul document XML
private XmlDocument d = nuli;
// elevi reine colecia de noduri child a
// nodului curent.
private XmlNodeList elevi = nuli;

6.

Tratm evenimentul Click pentru butonul "Incarna Xm l. n fereastra


Properties acionai dublu click pe buton. n corpul handler-ului introducei
codul:
private void buttonl_Click(object sender, EventArgs e)
{
d = new XmlDocument(); // Creeaz un document XML
d.Load("Elevi.xml");
// ncarc fiierul
// Returneaz colecia de elemente (noduri)
elevi = d.SelectNodes("absolventi/elev");

"elev"

// Parcurge elementele "elev"


for (int i = 0; i < elevi.Count; i++)
{
// n colecia elevi, nodurile se acceseaz
// indexat. Pentru fiecare elev, se selecteaz
// nodul "nume"
XmlNode elev =
elevi.Item(i).SelectSingleNode("nume");
// Numele elevului se adaug n list
listBoxl.Items.Add(elev.InnerText);
}
}
7.

La selectarea unui nume n list, dorim s afim n controalele TextBox


informaiile referitoare la acel nume.

274

Partea a II-a. Programare Windows cu Visual C# Express Edition


Tratm evenimentul SelectedlndexChanged pentru ListBox. Selectai
controlul i n fereastra Properties, facei dublu click pe eveniment. n
metoda de tratare, introducei codul evideniat:
private void listBoxl_SelectedIndexChanged(
object sender, EventArgs e)
{
// Se obine indexul numelui selctat
int index = listBoxl.Selectedlndex;
// Se selecteaz lista de elemente "elev"
elevi = d.SelectNodes("absolveni/elev");
// n colecia elevi se acceseaz cel cu indexul
// index. Apoi se selecteaz subelementul "coala"
XmlNode nume =
elevi.Item(index).SelectSingleNode("coala");
// Textul aferent elementului "coala"
textBoxl.Text = nume.InnerText;
// Operaiile se repet pentru "clasa" i "profil"
XmlNode clasa =
elevi.Item(index).SelectSingleNode("clasa");
textBox2.Text = clasa.InnerText;
XmlNode profil =
elevi.Item(index).SelectSingleNode("profil");
textBox3.Text = profil.InnerText;
}
8.

Compilai i rulai cu F5.

La rulare, dup acionarea butonului Incarca XML:

Elevi
A rdelean Eu

Costea Andrei
I Nicoara Alina

Informaii

coala: iC.N. Liviu Rebreanu


Clasa: fa XII-a A
Profil: I matematica-informatica j

Incarca XML______ ]

Ieire

Capitolul 9. XML cu C#

275

Important!

Clasele XmlDocument i XmlNodeList motenesc clasa XmlNode.


Astfel ne explicm faptul c proprietile childNodes i nnerText se
regsesc printre membrii ambelor clase.
nnerText este valoarea nodului concatenat cu valorile tuturor
copiilor si.
XmlNodeList reprezint o colecie ordonat de noduri.
Metoda XmlNode Item(int i) a clasei XmlNodeList retumeaz
nodul aflat la indexul i.

Descrcarea fiierelor XML de pe Internet


n ultimii ani, multe site-uri i bloguri expun clienilor un format XML cunoscut
sub numele RSS ( Really Simple Syndication), n scopul distribuirii de coninut care
se schimb frecvent (tiri, sumarul coninutului unui site sau ntregul coninut,
posturi pe blog, etc).
Un furnizor de coninut (site, blog) public de regul un link (feed link) ia care
utilizatorii subscriu cu ajutorul unor programe specializate (feed reader).
Subscrierea se face simplu, copiind link-ul din Web browser n feed reader. Mai
departe, coninuturile noi se descarc n mod automat, iar utilizatorul este ntiinat
cnd acest lucru se petrece. Practic, se descarc fiiere XML.
Cu .NET putei crea propriul feed reader (agregator). Nu vom face acest
lucru aici, ci vom arta ct de simplu putei descrca un fiier XML de pe Internet
sau un feed RSS.

Aplicaia D o w n lo a d X m l
Aplicaia utilizeaz clasa WebClient din spaiul de nume System.Net
pentru a descrca un fiier de tip XML.
Urmai paii:
1.

Creeai o aplicaie de tip Windows Forms n Visual C# Express 2008.

2.

Pe forma aplicaiei, aducei din Toolbox un buton.

3.

La seciunea directivelor, n fiierul Form1.cs, adugai directivele:


using System.Xml;
using System.Net;

4.

Tratm evenimentul Click generat la click pe buton. Acionai dublu click


pe buton. n metoda de tratare scriei:

276

Partea a II-a. Programare Windows cu Visual C# Express Edition


private void buttonl_Click(object sender, EventArgs e)
{
// Descrcm n stringul xml coninutul XML (R S S
// feed) de la un anumit URL
string xml = new
WebClient().Downloadstring("http://news.google.com/"
+ "?output=rss");
// Crem o instan de tip XmlDocument
XmlDocument doc = new XmlDocument();
// ncrcm stringul
d o c .LoadXml(xml);

(cu coninut XML) n document

// Salvm pe disc coninutul XML descrcat


d o c .Save("coninut.xml");
}
5.

Compilai i rulai cu F5.

Dup executare, vei gsi n folderul /Bin/Debug fiierul coninut.xml,

Observaie:
>
Pe numeroase site-uri i blog-uri vei gsi feed link-uri pentru subscriere, lat
cteva link-uri alese aleatoriu:
http://www.preferredjobs.com/rss/rss2.asp
http://sourceforge.net/export/rss2_sfnews.php?feed
http://newsrss.bbc.c o .uk/rss/newsonline_uk_edition/world/rss.
xml

Citirea i analiza unui document XML cu


XmITextReader
Transportul datelor ia distan se face n mod frecvent cu ajutorul streamurilor.
Clasa XmITextReader este un instrument foarte rapid de accesare streamurilor de date XML. Clasa reprezint un cititor (reader), care se deplaseaz n
stream doar nainte (forward only), citete documentul nod dup nod i nu modific
stream-u\. Reader-ul v permite s v deplasai progresiv n documentul XML i s
examinai fiecare nod, cu elementul, atributele i valoarea sa.
Propunem o aplicaie care ilustreaz o parte dinte capabilitile acestei
clase.

Capitolul 9. XML cu C#

277

Aplicaia XmlTextReaderExample
Programul C# de mai jos folosete clasa XmITextReader pentru a citi un
document XML aflat pe disc. Documentul este citit nod cu nod, apoi este
reconstituit i se afieaz pe ecran.
Urmai paii:
1.

n Visual C# creeai
XmlTextReaderExample.

un

proiect

de

2.

Editai fiierul crti.xml cu urmtorul coninut:

tip

consol

cu

numele

<!--Citire fiier XML-->


<biblioteca>
Ccarte ISBN="186-383-537">
<Titlu>Amintiri din copilarie</Titlu>
<Pret>13.20</Pret>
<Autor>Ion Creanga</Autor>
</carte>
</biblioteca>
3.

n fiierul Program.es introducei codul:

using System;
using System.Xml;
class Program
{

static void Main(string[] args)


{

// Crem un reader (instan a clasei) i


// ncrcm fiierul

XmITextReader reader =
new XmITextReader ("crti.xml");
// Citim pe rnd toate nodurile din document

while (reader.Read())
{
// n funcie de tipul nodului curent

switch (reader.NodeType)
{
// Dac nodul este un element

case XmlNodeType.Element:
Console.Write("<" + reader.Name);
Console.WriteLine(">");
break;
// Afim textul din fiecare element

case XmlNodeType.Text:

278

Partea a II-a. Programare Windows cu Visual C# Express Edition


Console.WriteLine

("
" +
reader.Value);

break;
// Afim "sfritul" elementului
case XmlNodeType.EndElement:
Console.Write(</" + reader.Name);
Console.WriteLine(">");
break;
}
}
} // Main()
}
4.

Compilai i rulai cu F5.

La rulare, pe ecran se va afia:


h ia t

Mani

kbiblioteca>
Kcarte>
K T i t l u >

finintiri din copilrie


H/T itlu>
KPret>
1 3 .2 0

k/Pret>
Kftutor>
Ion Creanga
[</ftutor>
|</carte >
k/biblioteca>

111....
De retinut:
>
Metoda Read() a clasei XmlTextReader citete i returneaz
urmtorul nod din stream.
Proprietatea NodeType a clasei XmlNode este o enumerare ai crei
membri reprezint tipurile de noduri din document. Studiai aceast
enumerare pentru a vedea c exist mai multe tipuri de noduri dect n
acest exemplu.
Cu ajutorul clasei XmlTextReader obinei coninutul XML dintr-un fiier
sau dintr-un stream. n plus, are calitatea c v permite s analizai i s
prelucrai acest coninut.

Capitolul 9. XML cu C#

279

Crearea coninutului
XML cu XmITextWriter
t
Clasa XmITextWriter ofer o cale rapid cu care putei genera fiiere sau
sfream-uri cu coninut XML. Clasa conine un numr de metode i proprieti cu
care se genereaz coninut XML. Pentru a le folosi creai un obiect de tip
XmITextWriter, apoi adugai pe rnd entiti XML obiectului. Exist metode cu
care putei aduga orice tip de coninut XML. Aplicaia pe care urmeaz utilizeaz
cteva dintre aceste metode.

Aplicaia X m IT e x tW rite rE x a m p le
Vom crea un fiier cu coninut XML. Urmai paii:
1.

Creeai o aplicaie de tip consol n Visual C# Express Edition.

2.

n fiierul Program.es, introducei codul:


using System;
using System.IO;
using System.Xml;
public class Program
{
// Fiierul n care se scrie coninutul XML
private string filename = "coninut.xml";
public static void Main()
{
// Crem obiectul de tip XmITextWriter
XmITextWriter writer =
new XmITextWriter(filename, null);
// Folosim indentarea tag-urilor
writer.Formatting = Formatting.Indented;
// Scriem un comentariu XML
writer.WriteComment("Creeare fiier XML");
// Scriem primul element (root).
writer.WriteStartElement("librrie");
// Scriem elementul carte (child pentru
// librrie)
writer.WriteStartElement("carte");
// Scriem un atribut pentru carte
writer.WriteAttributeString("ISBN",
"186-383-523") ;

280

Partea a II-a. Programare Windows cu Visual C# Express Edition


// Titlul crii
writer.WriteStartElement("Titlu");
writer.WriteString("Amintiri din copilrie");
writer.WriteEndElement();
// Preul si autorul crii
writer.WriteElementString("Pre", "13.20") ;
writer.WriteStartElement("Autor");
writer.WriteString("Ion Creanga");
// Scrie tag-ul de sfrit pentru elementul
// carte
writer.WriteEndElement();
// Scrie tag-ul de sfrit pentru elementul
// librrie
writer.WriteEndElement();
// Scrie XML n fiier si nchide writer
writer.Flush();
writer.Close();
// Afim coninutul XML si pe ecran
XmlDocument doc = new XmlDocument();
// Pstrm spaiile albe pentru lizibilitate
d o c .PreserveWhitespace = true;
// ncrcm fiierul
doc.Load(filename);
//Scriem coninutul XML pe ecran
Console.Write(doc.InnerXml);
Console.ReadLine();
} // Main ()
}
3.

Compilai i rulai cu F5.

n folderul /bin/Debug vei gsi fiierul continut.xml. Acelai coninut se afieaz i


pe ecran:

Capitolul 9. XML cu C#

281

lib r r ie >
C c a rte ISBN ="186-383-S23">
< T itlu > A m in tiri d in c o p ila r ie < / T itlu >
<P r e t > 13.2 0</Pre t >
<Autor>Ion Creanga</Autor>
< /carte>
/ lib r r ie >

De retinut:

Clasa XmlTextWriter ofer o cale programatic de a crea coninut XML


Metodele clasei au nume intuitive.
De exemplu, writer.WriteStartElement("titlu") ; scrie
n
obiectul writer <titlu>.
Cu WriteString () scriei textul asociat elementului curent.
Exist i alte metode i proprieti corespunztoare altor entiti XML.
Acestea se utilizeaz n mod similar. Merit efortul s le explorai.

Probleme propuse
1.

Realizai o aplicaie care utilizeaz controale text box pentru a introduce


datele personale ale clienilor unei bnci. Datele clienilor se vor salva ntrun fiier n format XML.

2.

Realizai o aplicaie care deschide un fiier XML i afieaz ntr-un textbox


concatenarea tuturor textelor asociate elementelor child ale elementului
root.

3.

Realizai o aplicaie de tip consol care descarc un feed RSS de pe


Internet i listeaz numele tuturor elementelor din coninutul XML.

4.

Realizai o aplicaie care citete coninutul XML dintr-un fiier i cu ajutorul


clasei XmlTextReader i afieaz ntr-un ListBox toate elementele XML.

5.

Realizai o aplicaie care salveaz ntr-un fiier cu coninut XML informaii


despre produsele unui magazin. La repornirea aplicaiei, aceste informaii
se pot ncrca de ctre aplicaie pentru a fi afiate n controale.

Partea a II-a. Programare Windows cu Visual C# Express Edition

282

Partea a III - a

Baze de date
Scopul acestei pri a lucrrii este acela de a v ajuta s accesai bazele de date
relaionale cu C#.

C apitolul 10

Baze de date i ADO.NET. Noiuni introductive


Capitolul are urmtoarele obiective:
O scurt prezentare a sistemului de gestiune pentru baze de date
reaionale MS SQL Server.
Generaliti despre sistemele de gestiune a bazelor de date relaionale.
Primele noiuni despre tehnologia A D O .N ET.
Crearea unei baze de date n Visual C# 2008 Express Edition.
Interogarea bazei de date cu ajutorul Query Designer.

Instrumente de lucru
Instrumentele software pe care le vom utiliza n lucrul cu bazele de date sunt:

Visual C# Express Edition 2008 (VCSE).


Microsoft SQL Server Express Edition 2005 (SSE).

Ambele instrumente funcioneaz pe platforma Microsoft .NET versiunea 3.5.


Sunt versiuni free, puternice, destinate s lucreze mpreun. n momentul cnd
instalai VC S E, avei opiune de instalare i pentru SSE.
SSE, este un subset al serverului de baze de date Microsoft SQL Server
2005. Acesta din urm este unul dintre cele mai avansate sisteme de gestiune a
bazelor de date (SGDB) existente. Dei SSE nu include toate capabilitile SQL
Server 2005, este perfect funcional i utilizabil n aplicaii industriale. Suport
procesarea online a tranzaciilor (OLAP), poate s gestioneze baze de date mai
mari de 4 Gb i admite sute de conexiuni concurente.
Cnd instalai SSE, vei avea de fapt dou versiuni ale serverului: SQL
Server Express Edition i SQL Server Express Compact Edition 2005. Acesta
din urm, este o versiune cu mai puine faciliti, fiind destinat s gestioneze baze
de date locale. n momentul n care construiie o baz de date n VCSE, avei
opiunea de a alege unul dintre cee dou servere.

Capitolul 10. Baze de date i ADO.NET. Noiuni introductive

283

SGDB-uri - noiuni generale


Sistemele de gestiune ale bazelor de date, aa cum numele indic, se
ocup cu crearea i ntreinerea bazelor de date. O baz de date este o colecie de
informaii structurate. Bazele de date poate nmagazina mari cantiti de informaie
care poate apoi s fie accesat i modificat n mod eficient de ctre utilizatori prin
intermediul SGDB-urilor.
Un SGDB admite multiple baze de date. Utilizatorii obin informaii din bazele
de date scriind interogri (query) care se adreseaz serverului de baze de date.
Acesta le execut, efectund operaii specifice asupra bazei de date i ntoarce
utilizatorului un set de rezultate. Operaiile obinuite sunt: de modificare a datelor,
de introducere de noi date, de tergere.
SQL ( Structured Query Language) este limbajul cu care trebuie s ne
adresm unui SGDB care opereaz cu baze de date relaionale. n aceast lucrare
vom presupune c cititorii au cunotine elementare referitoare la acest limbaj.
Un Sistem de Gestiune a Bazelor de Date Relaionale (SGDBR) este un
SGDB bazat pe m odelul relaional. Datele sunt depozitate n tabele. ntre tabele
exist relaii, iar relaiile se memoreaz de asemenea n baza de date.

Calitile SGDBR-urilor
Sistemele de gestiune a bazelor de date asigur depozitarea i regsirea
datelor. n raport cu alte forme de pstrare a datelor, au afu-uri care le fac
inegalabile:

Viteza mare a operaiilor.


Operaiile asupra datelor (cutare, sortare, modificare) sunt foarte
rapide.

Compacteaz informaia.
Bazele de date lucreaz cu cantiti uriae de date. Acestea se
memoreaz pe spaii relativ reduse.

Asigur securitatea datelor.


Datele sunt foarte bine protejate mpotriva oricrui acces neautorizat.

ntreine
j datele.
Un SGDB ine evidena fiecrui fragment de informaie. Utilizatorii nu
trebuie s se preocupe acest aspect.

Controleaz redundana datelor.


Previn crearea de duplicate multiple ale acelorai date, care ar duce la
ocuparea unui volum mare pe disc.

Previne inconsistenta
i datelor.

Partea a III - a. Baze de date

284

Nu permite utilizatorului operaii care distruge logica bazei de date. n


acelai timp, cnd un SGDB elimin date redundante, aceast
operaie se face cu pstrarea consistenei datelor.

Asigur atomicitatea operaiilor.


Operaiile elementare, dar i grupurile de operaii (tranzaciile) se
garanteaz fie c vor fi complet executate, fie c nu vor avea nici un
efect. n oricare dintre situaii, baza de date rmne ntr-o stare
consistent.

Furnizori de baze de date relaionale


i
Pe pia exist multe SGDB-uri. O s amintim doar cteva firme
productoare importante:
Oracle, cu SGDB-ul Oracle. Deine recordul de vnzri n acest moment.
IBM cu produsele DB2 i Informix.
Microsoft cu SQL Server 2005.
Sybase, cu SGDB-ul Sybase.
Exist i alte firme ale cror sisteme de gestiune a bazelor de date au un segment
de pia bine delimitat, dar mult mai restrns dect a celor menionate.
n acest punct trebuie s adugm rolul tot mai important pe care l are n
acest moment SGDB-ul MySQL. Se utilizeaz ca free software, sub GNU General
Public Licence (GPL). Este foarte popular ndeosebi pentru aplicaii Web, fiind
disponibil pentru mai multe sisteme de operare.

Tehnologia ADO.NET - introducere


Aproape toate aplicaiile software interacioneaz cu baze de date. Este
nevoie de un mecanism prin care aplicaiile se conecteaz i utilizeaz bazele de
date. Pentru aplicaiile .NET, acest mecanism se numete ADO.NET.

Caracteristicile tehnologiei ADO.NET


ADO.NET este format dintr-un subset al B ib lio te cii de Clase .NET, folosite
n programare pentru accesarea surselor de date, n special a bazelor de date
relaionale.
nainte ca platforma .NET s existe, n programarea aplicaiilor pentru
sistemele Windows se utilizau urmtoarele tehnologii de accesare a bazelor de
date: ODBC (Open Database Connectivity), OLE DB (Object Unking and
Embedding, Database) i ADO (ActiveX Data Objects). ADO este o colecie de
obiecte pentru accesarea surselor de date.

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

285

Pentru compatibilitate cu SGDB-uri mai vechi, ADO.NET include n


continuare ODBC i OLE DB, ns ADO.NET nu este ADO.
ADO.NET este o tehnologie complet nou de acces la date. Este parte
integrant a platformei .NET i nu este format din obiecte ActiveX. Raiunile
pentru care Microsoft a pstrat cuvntul ADO n numele ADO.NET in de ideea c
interfaa de utilizare a celor dou tehnologii este oarecum asemntoare.
ADO.NET faciliteaz dezvoltarea de aplicaii mai performante cu baze din
urmtoarele considerente :
1. A c c e s u l d e c o n e c ta t la b a z e le d e d a te
ADO.NET este conceput s permit att accesul conectat ct i
deconectat la bazele de date. Imaginai-v c v-ai conectat prin intermediul unei
aplicaii la un server de baze de date, aflat undeva la distan n reea. Deschidei
o conexiune, citii datele, modificai datele i la sfrit v deconectai. Acesta este
modelul conectat. Dezavantajul este c n tot acest timp comunicai prin reea
direct cu serverul care trebuie s menin conexiunea i s execute interogrile.
Dac ne gndim c poate fi vorba de sute sau mii de utilizatori care transfer
cantiti mari de date, atunci nelegem c n modelul conectat, utilizat cu vechile
tehnologii, pot s survin suprancrcri ale serverului i ale traficului n reea, un
consum mare de resurse i ncetinirea sau blocarea aplicaiilor.
n modelul deconectat datele sunt trimise de la server i sunt stocate local
la client ntr-o structur de date numit dataset. Clientul opereaz doar asupra
datelor din acest dataset, iar cnd a terminat, datele schimbate se trimit la server,
acolo unde se gsete adevrata baz de date. Astfel, serverul este eliberat de
sarcina de a menine conexiunile n mod permanent i poate servi mai muli cu
clieni. Pe partea clientului de asemenea, toate operaiile se desfoar mai rapid.
2.

In te g ra re a X M L .

ADO.NET este strns legat de XML. XML este folosit intern de ADO.NET ca
s menin datele n cfafasef-uri i s rein relaiile i constrngerile ntre tabele.
Mai mult, suportul pentru XML este integrat in ADO.NET. Se pot produce scheme
XML, se pot transmite date cu ajutorul documentelor XML.

Arhitectura ADO.NET
ADO.NET are dou componente centrale:

1.
2.
1.

Furnizorii de date {data provider)


Seturile de date (datasets)

F u rn iz o rii d e d a te

Un furnizor de date (data provider) asigur conectarea la o surs de date


(data source). Sursa de date poate fi un fiier text, un document XML, o baz de
date, etc. Totodat un furnizor de date suport accesul la date i manipularea

286

Partea a III - a. Baze de date

datelor. Este legtura ntre aplicaia dumneavoastr i sursa de date. De regul


sursa de date este o baz de date i atunci un furnizor de date asigur legtura
ntre aplicaie i sistemul de gestiune a bazei de date respective.
Un furnizor de date se compune dintr-un numr de obiecte ale unor clase
specializate. Aceste clase sunt definite n interiorul unor spaii de nume speciale.
Tabelul prezint cteva dintre spatiile de nume n care sunt grupate componentele

.NET:
Spaiu! de nume
System.Data
System.Data.Odbc
System.Data.OleDb
System.Data.Sql
System.Data.OracleClient
System.Data.SqlClient

Descriere
Clase, interfee, delegri care definesc arhitectura
.NET. Aici sunt clasele care definesc dataset-urile
Data provider .NET pentru ODBC
Data provider .NET pentru OLE DB
Clase care suport funcionalitate specific SQL
Server
Data provider .NET pentru Oracle
Data provider .NET pentru SQL Server

Figura 10.1. Schema prilor componente ale arhitecturii .NET.

Interfaa cu utilizatorul
ADO.NET
Data Set
Data
Table

Data Provider
Data Reader
Data Adapter
Command
Connection

XML
Baza de date

Sarcinile pe care le ndeplinete un data provider.

Furnizeaz accesul la date printr-o conexiune activ cu sursa de date.


Asigur transmisia datelor la i dinspre ctefasef-uri (n modelul
deconectat).
Asigur transmisia datelor la i dinspre aplicaie (n modelul conectat)

Capitolul 10. Baze de date i ADO.NET. Noiuni introductive

287

Clasele unui data provider sunt:


Connection
Command
Parameter
DataAdapter
DataReader

Creeaz conexiunea cu sursa de date.


Este utilizat pentru operaii asupra sursei de date: citire,
modificare, tergere de date.
Descrie un singur parametru al unei comenzi. De pild,
parametrul unei proceduri stocate.
Este un adaptor pentru transferul datelor ntre sursa de date
i dataset.
Este folosit pentru accesarea i citirea rapid a a datelor ntro surs de date.

Pentru a nelege cum sunt definite n .NET aceste clase, vom lista numele acestor
clase pentru doi furnizori de date: Sql Server i OLE DB .NET. Reamintim c n
spaiul de nume System.Data.SqlClient sunt clasele furnizorului de date Sql
Server, iar n spaiul de nume System.Data.OleDb sunt cele ale furnizorului de
date, OLE DB.
Clasele specifice celor doi data provider-i sunt:
Furnizorul OLE DB .NET
OleDbConnection
OleDbCommand
OleDbDataReader
OleDbDataAdapter

Furnizorul SQL Server


SqlConnection
SqlCommand
SqlDataReader
SqlDataAdapter

Corespunde clasei
Connection
Command
DataReader
DataAdapter

Pentru ca lucrurile s se lmureasc pe deplin, enumerm clasele DataReader


specifice tuturor furnizorilor .NET:

System.Data.SqlClient.SqlDataReader
System.Data.OleDb.OleDbDataReader
System.Data.Odbc.OdbcDataReader
Oracle.OracleClient.OracleDataReader

2. Seturile de date
Dataset-ul este o component major a arhitecturii .NET. DataSet este
clasa care definete un dataset. Un dataset este o colecie de obiecte DataTable
care pot fi legate ntre ele cu obiecte de tip DataRelation. Dataset-urile preiau
de la data providers informaiile necesare din sursa de date sub forma unei copii
reduse a bazei de date. Prin urmare, un dataset poate include o baz de date
relaional cu tabele, relaii, vederi. Utilizatorul opereaz asupra tabelelor din
dataset, care sunt practic o copie a tabelelor reale din baza de date. Deoarece un
dataset este un obiect, cahe-ul pentru datele sale este n memorie.
Dafasef-urile implementeaz modelul de lucru deconectat de baza de date.
Cnd este necesar, dafasef-urile transmit bazei de date modificrile operate
asupra datelor.
Clasa DataSet, ca i celelalte clase care lucreaz cu un dataset se gsesc n
spaiul de nume System.Data. Tabelul urmtor descrie aceste clase:

Partea a III - a. Baze de date

288

DataSet

O b ie c te le s a le d e s c r iu s c h e m a n tre g ii b a z e d e d a te s a u a u n e i
s u b m u lim i a sa. C o n in e ta b e le i re la iile n tr e e le .

DataTable

O b ie c te le re p r e z in t o s in g u r ta b e l d in b a z a d e d a te . C o n in e
r n d u r i i c o lo a n e .

DataRow
DataColumn
DataView
DataRowView
DataRelation

R e p re z in t u n s in g u r r n d n tr-o ta b e l .
R e p r e z in t o c o lo a n n tr-o ta b e l .

DataTable
DataView.

O b ie c te le s o r te a z d a te le . N u s u n t in c lu s e n tr - u n
O b ie c te le r e p r e z in t u n s in g u r r n d n t r - u n

R e p r e z in t o re la ie n tre ta b e le . D e e x e m p lu , o re la ie d e

cheie

p r i m a r - c h e ie s tr in

Constraint

D e s c r ie o c o n s tr n g e r e n ta b e l , c u m a r fi u n ic i ta t e a v a lo r il o r n tr-o
c o lo a n c h e ie p rim a r .

Crearea unei baze de date n VCSE


Construim o baz de date n cadrul unui proiect de tip consol. Pentru
aceasta, deschidei Visual C# Express 2008 i urmai urmtoarele indicaii:
1.

Creai un nou proiect de tip consol cu numele DatabaseExample.

2.

n meniul View, selectai Other Windows, apoi Database Explorer. Aceasta


este o fereastr important, n care vizualizai i manipulai elementele bazei
de date pe care o vei crea.

3.

n Solution Explorer, acionai click drept pe numele proiectului, alegei Add,


apoi New Item... n dialogul Add New Item, selectai iconul Service-based
Database, apoi numii baza de date coala.

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

289

Remarcai c exist i alternativa de a alege Local Database. n aceast


situaie, baza de date este creat de ctre SQL Server Compact Edition. Are
extensia .sdf, i este destinat s fie utilizat local. Testai i aceast variant.
4. n panoul Add New Item, acionai butonul Add. Dialogul Data Source
Configuration Wizard v anun c va construi un dataset vid, pe care l putei
configura ulterior. Acceptai numele ScoalaDataSet pentru acesta:

Apsai butonul Finish.


5. n panoul Database Explorer, expandai nodul coala.mdf, care reprezint
baza de date. Click dreapta pe Tables, i selectai Add New Table:

li

. j j Data Connections
ii* coala.mdf
*

Database Diagrams

.~i

_1 Views

.................._ _ _

Stored,

t:

Funcii

_S Synoni ;j?j

_ i Types

l_j Assemf

Add New Table

New Query
Refresh
Properties

290
6.

Partea a III - a. Baze de date


Panoul care se deschide este Table Designer. Acesta v permite s definii
schema tabelei, adic numele, tipul i constrngerile pentru fiecare coloan.
Completai prima linie ca n figur. n fereastra Column Properties, setai
pentru cmpul IdElev, proprietatea i s i d e n t i t y la valoarea Yes i Identity
Increment la valoarea 1. Aceasta nseamn c tipul coloanei trebuie s fie int,
iar valorile pe coloan se incrementeaz n mod automat ncepnd de la
valoarea 1, pentru fiecare rnd nou introdus. n acest fel, IdElev poate
identifica n mod unic un rnd n tabel:
Database Explorer
H

A X

d b o .T ab lel: T...E\SCO A LA .M D F )*
Column Name

Data Connections

Si

L J Tables

ffi

3 Views

ffi

~
Allow Nulls

int

[j]

Database Diagrams
u
| Column Properties

- l 3 Stored Procedures
D 3 Functions

A I

1 i , v>; /.. i ..^ -:'.t

ffi~
: IC i Synonyms
r (--

..

f f i- C i Types

03 - C l Assemblies

l( j j 'E l Full-text Specification

No

'l
B

;
1,

..

.. . ..:
a i

C~l l!J '*-t J ' iu

Identity Specification

Yes

(Is Identity)

Yes

Identity Seed

y ;j

Vom stabili pentru coloana IdElev, o constrngere de cheie primar (primary


key). Facem acest lucru pentru a vedea cum se procedeaz i nu pentru c ar
fi necesar, deoarece IDEIev este deja o coloan Identity. Deselectai check
box-ul Allow Nulls, deoarece o coloan Identity sau o cheie primar nu admite
valori nule. Selectai n Table Designer primul rnd, facei click dreapta i
alegei Set Primary Key:
Column Name

Data Type

IdElev
|

uu

8.

Data Type

IdElev

ij,. coala,mdf
Si

7.

Program.es

Set Primary Key


Insert Column

Delete Column

Relationships,,,

Definii celelalte coloane astfel:

Allow Nulls

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive


Column Name

Data Type

Allow Nulls

IdElev

int

Nume

nvarchar(30)

Prenume

nvarchar(30)

S3

Varsta

291

0
0

money
n c h a r(ld )

9.

Salvai proiectul i tabela apsnd butonul Save AII. n dialogul Choose Name
introducei numele tabelei: Elevi.

10. Pentru a nsera (design time) cteva rnduri cu date n tabel, expandai
nodul Tables n Database Explorer. Click dreapta pe tabela Elevi i
selectai Show Table Data.
Database

d
b
o
.E
lev
i:T
a
,..L
E
\5
C
0
A
L
A
.M
D
F
) sta
rtP
a
g
e

fi

'ii

C
o
lu
m
nN
a
m
e
Id
E
le
v

D
a
taC
o
n
n
ectio
n
s
3 Q
|.
co
a
la
,m
d
f
ffi 23D
a
ta
b
a
seD
ia
g
r
a
m
s
l_i T
a
b
les

fib

D
a
taT
y
p
e
|m
t

N
u
m
e

rw
a
rch
a
r(3
0
)

Prenume

n
v
a
tch
a
r(3
0
)
n
t

HUS ' A
d
dN
ew
T
a
b
le
1 1*:
A
d
dN
ew
T
r
ig
g
e
r
m iv
HR
N
ew
Q
u
e
ry
a v
O
p
enT
a
b
leD
efin
it

__f Views

:* ii S
to
redP
ij j* S
h
ew
T
a
b
leD
a
ta

SC r*51 Ft trwifWurM

11. S-a deschis Query Designer. Aici putei introduce manual date n tabel i
putei efectua interogri. Completai cteva rnduri, ca mai jos. Observai c pe
coloana idElev serverul nu v permite s introducei valori, deoarece este
coloan Identity i aceasta nseamn c SQ L S e rver ii atribuie valori n mod
automat:

Si

J-J

.....

f,

Elevi: Query(...LE\SCOALA.MDF)
ti------------1 IdElev
if|

1 .
2

0= t 3 d l 5

dbo,Elevi; Ta.,.LESCOALA,MDF) j St;

Nume

Prenume

Varsta

Pascu

lo a n

18

Nedelcu

Valentin

17

|3

Pop

Andrei

19

!4

Ilie

lo a n

18

[ MAL

MAL

MAL

MAL

292

Partea a III - a. Baze de date

12. Dac dorii s adugai i alte tabele bazei de date coala, de pild tabelele
Clase, Profesori, Materii, e foarte simplu: facei click dreapta pe Tables
n Database Explorer i alegei New Table., apoi repetai paii 6...11.
Nu vei face build acestui proiect, pentru c aplicaia nu execut nimic. Vom vedea
n seciunile urmtoare cum ne conectm la baza de date i cum o interogm
programatic.

De retinut:
9

O cheie primar (primary key) identific n mod unic fiecare rnd ntr-o
tabel. Cheia primar include o coloan sau o combinaie de coloane. Nu
pot exista dou rnduri distincte ntr-o tabel care s aib aceeai valoare
(sau combinaie de valori) n aceste coloane.
O coloan identitate (Identity column) identific n mod unic fiecare rnd
ntr-o tabel, iar valorile sale sunt generate de ctre baza de date. Deseori
o coloan identitate e desemnat i cheie primar.
varchar (n) este un tip de dat specific SGDB-urilor, care reine un set
de caractere de lungime variabil, dar care nu depete n. Pentru SQL
Server 2005, n poate fi maxim 8000 bytes.

Interogri cu Query Designer


n aceast seciune vom face cteva exerciii de manipulare a datelor, n
scopul mprosptrii cunotinelor referitoare la comenzile limbajului SQL. Utilizm
baza de date coala, construit anterior.
Deschidei proiectul DatabaseExample. n Database Explorer, acionai
click dreapta pe Tables i alegei New Query. n dialogul Add Table selectai tabela
Elevi i acionai butonul Add. Se deschide Query Designer-u\ mediului integrat,
care vizual consist din patru panouri: Panoul Diagramelor (Diagram Pane),
Panoul Criteriilor (Criteria Pane), Panoul SQL (SQL Pane), Panoul de Vizualizare
a Rezulatelor ( Show Results Pane).
n Panoul SQL vom introduce interogri, iar rezultatele interogrii, adic
setul de rezultate, este vizualizat n Panoul Rezultatelor. Panoul diagramelor
permite selectarea coloanelor iar cel al criteriilor servete la stabilirea criteriilor de
sortare. Toate seleciile fcute n cele dou panouri genereaz cod n Panoul SQL.
Reamintim faptul c limbaljul SQL (Structured Query Language) include
dou seciuni importante:
1.

Data Manipulation Language (DML).


DML const din interogri i comenzi pentru modificarea datelor.
Acestea sunt: s e l e c t ,u p d a t e ,d e l e t e i i n s e r t i n t o .

2.

Data Definition Language (DDL).


Comenzile DDL permit crearea i tergerea tabelelor ntr-o baz de
date. Cele mai importante comenzi de acest tip sunt: c r e a t e t a b l e ,
ALTER TABLE, DROP TABLE.

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

293

Butoanele
panourilor

w) s i

iU ? 0

i m 6=

Query4: Query...E\SCOALA.MDF)

Iii

s ta r t P age

X
A-

LJ* (All Columns)


|L

Diagram Pane

IdElev

jV iN u m e
li v ] P re n u m e

jivj V a rs ta
v

>

<
C olum n

:<
.... ^
SELECT

Alias

Table

O u tp u t

N um e

Elevi

P re n u m e

Elevi

V a rs ta

Elevi

j
v

Criteria Pane

4l

>

SQL Pane

N um e, P re n u m e j V a rs ta
E levi

FROM

|
Show Result
Pane

Figura 10.2 Query Designer


Executarea interogrii
Pentru executare acionai click pe butonul Execute SQL (butonul cu semnul
exclamrii) sau de la tastatur Ctrl + R.
n panoul de rezultate, se afieaz:

Num e

P re n u m e

V a rs ta

P ascu

lo a n

18

N e d e lc u

V a le n tin

17

P op

A n d re i

19

Ilie

lo a n

18

Partea a III - a. Baze de date

294

Comanda SELECT
SELECT este utilizat pentru selecatrea datelor dintr-o tabel. Rezultatul
este returnat ntr-o form tabelar, numit result set.

Sintax:
SELECT nume_coloane FROM tabela

Exemplu:
Introducei n SQL Pane comanda urmtoare, dup care o executai cu un
click pe butonul Execute SQL:
SELECT Nume, Prenume, Varsta FROM Elevi

Putei face acest lucru manual, sau bifai n Diagram Pane coloanele
corespunztoare.

Sortare
Ca s introducei criterii de sortare n comanda s e l e c t , utilizai Panoul
Criteriilor (selectai o opiune din coloana Sort Type) sau le introducei manual.
Exemplu:
Introducei n SQL Pane comanda:
SELECT Nume, Prenume FROM Elevi
ORDER BY Nume

Rezultat:
1
-

ii '

Nume

Prenume

Ilie

loan

Nedelcu

Valentin

Pascu

loan

' i Pop

Andrei

Clauza WHERE
where

permite selecia condiionat. Cu * selectai toate coloanele tabelei.

Exemplu:
Introducei n SQL Pane comanda:
SELECT * FROM Elevi
WHERE Varsta > = 1 8

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

295

Rezultat:
IdElev

Nume

Prenume

Varsta

Pascu

loan

18

Pop

Andrei

19

Ilie

loan

18

Comanda INSERT INTO


Comanda insereaz un rnd nou n tabel.

Sintax:
INSERT INTO nume_tabel
VALUES valoarel, valoare2, ...

Putei de asemenea s specificai coloanele n care se nsereaz date:


INSERT INTO nume_tabel (coloanal, coloana2,
VALUES valoarel, valoare2, ...

...)

Exemplu:
Introducei n SQL Pane:
INSERT INTO Elevi (Nume, Prenume, Varsta)
VALUES ('Florea', 'Constantin', 99)

Rezultat:
Pentru a vedea rezultatul, avem nevoie de un result set ntors de o
instruciune s e l e c t .Introducei interogarea:
SELECT * FROM Elevi
IdElev

Nume

Prenume

Varsta

11
[2

Pascu

loan

18

Nedelcu

Valentin

17

13

Pop

Andrei

19

<

......i I4

Ilie

loan

18

;7

Florea

Constantin

99

Comanda UPDATE
Comanda este utilizat pentru modificarea datelor ntr-o tabel.

Partea a III - a. Baze de date

296

S in ta x :
UPDATE nume_tabel
SET coloanl = valoarel, coloan2 = valoare2, ...
WHERE coloan = valoare

Cu u p d a t e putei modifica valorile pe una sau mai multe coloane, n rndurile


selectate cu clauza w h e r e .
Exemplu:

Introducei n SQL Pane:


UPDATE Elevi
SET Vrsta = 104
WHERE Prenume = 'loan'
Rezultat:

Pentru a vizualiza rezultatul introducei n SQL Pane interogarea:


SELECT * FROM Elevi
Id E le v

N um e

P renum e

V a rsta

Pascu

lo a n

104

N ede lcu

V alentin

17

Pop

A n drei

19

Ilie

lo a n

104

F lo re a

C o n s ta n tin

99

*}

Com anda DELETE

Comanda este utilizat pentru tergerea rndurilor dintr-o tabel.


S in ta x :
DELETE FROM nume tabel
WHERE coloan = valoare
Exemplu:

Introducei n SQL Pane comanda urmtoare, dup care executai-o cu click


pe butonul Execute SQL:
DELETE FROM Elevi
WHERE Vrsta > 1 9
Rezultat:

Pentru a vizualiza rezultatul introducei n SQL Pane interogarea:

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

297

SELECT * FROM Elevi


jId E le v
)]

l.

N um e

P ren um e

V a rs ta

N e d e lcu

V a le n tin

1?

Pop

A n d re i

19

Comanda CREATE TABLE


Comanda creeaz o tabel ntr-o baz de date.

Sintax:
CREATE TABLE nume_tabel
(
coloanal tip_dat,
coloana2 tip_dat,

)
Exemplu:
Lucrm cu aceeai baz de date, coala. Introducei n SQL Pane
comanda urmtoare, dup care executai cu un click pe butonul Execute SQL:
CREATE TABLE Clase (IDClasa varchar(5), Profil varchar(20),
NrElevi int)

Rezultat:
n Database Explorer a aprut tabela Clase. Acionai click drept asupra
numelui clasei i selectai Open Table Definition:
C o lu m n N a m e
ID C la s a

D a ta T y p e
1 v a rc h a r(5 )

A llo w Nulls
i

P ro fil

v a r c h a r( 2 0 )

N rE le vi

in t

Comanda ALTER TABLE


Comanda este utilizat pentru a aduga sau a terge coloane ntr-o tabel.

Sintax:
ALTER TABLE tabel
ADD coloan tip
ALTER TABLE tabel
DROP COLUMN coloan

298

Partea a III - a. Baze de date

Exemplu:
Introducei n SQL Pane comanda urmtoare, dup care o executai cu un
click pe butonul Execute SQL:
A L T E R TABLE Clase
ADD D i r i ginte varchar(20)

Rezultat:
n Database Explorer acionai click drept asupra numelui clasei i selectai
Open Table Definition:
Column Name

D ata Type

Allow Nulls

IDCIasa

v a rc h a r(5 )

Profil

v a rc h a r(2 0 )

NrElevi

int

| D iriginte

| v a rc h a r(2 0 )

Exemplu:
Introducei n SQL Pane comanda pentru tergerea coloanei Diriginte:
A L T E R TABLE Clase
DROP C OLUMN Diriginte

Rezultat:
C olum n N am e

D a ta T y p e

ID C Ia sa

v a r c h a r(5 )

P ro fil

v a rc h a r(2 0 )

N rE levi

in t

A llo w Nulls

Comanda DROP TABLE


Comanda este utilizat pentru a terge o tabel ntr-o baz de date.

Sintax:
DR OP TABLE

ta b e l

Exemplu:
Vom terge tabela Clase. Introducei n SQL Pane comanda urmtoare,
dup care o executai cu un click pe butonul Execute SQL:
DROP TABLE Clase

Rezultat:

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

299

n Database Explorer, click dreapta pe Tables i selectai Refresh. Se


observ c tabela Clase a fost tears.

Controlul DataGridView
Acest control este vedeta controalelor pentru afiarea datelor. Clasa
DataGridView permite construirea unei tabele adaptabile. Celulele, rndurile,
coloanele se seteaz prin intermediul proprietilor Rows i Columns.

Controlul se poate popula manual sau programatic. Ca alternativ, controlul


se poate lega la o surs de date prin intermediu) proprietilor DataSource i
DataMember. Astfel popularea se face n mod automat.
Prezentm un exemplu de manipulare simpl a acestui control.

Aplicaia DataGridView Example


Realizm un proiect de tip consol, care conine o baz de date cu o singur
tabel. Informaiile din tabel se vor afia ntr-un control DataGridView n
momentul pornirii aplicaiei. Urmai paii:
1.
2.

Creai un proiect de tip Windows Forms cu numele DataGridViewExample.


Construii o baz de date cu numele Sport. Adugai n baza de date tabela
Sportivi. Tabela are urmtoarea structur:
Colum n Name
Id S p o rtiv

D ata T yp e
j int

Allow Nulls

Nume

n va reha r(1 5)

Prenum e

n va rc h a r(1 5 )

D ata N a sterii

d a tetim e

S p o rtu lP ra ctica t

n va rc h a r(3 0 )

Pentru construirea bazei de date i a tabelei, urmai indicaiile temei: Crearea


unei baze de date n VCSE.
3.

Introducei cteva nregistrri n tabel. Pentru aceasta, selectai tabela


Sportivi n Database Explorer, acionai click dreapta i alegei Show

Table Data.
4.

Din Toolbox, tragei pe suprafaa formei un control de tip DataGridView i


setai proprietatea Dock la valoarea Fill.5

5. Selectai controlul. n fereastra Properties, atribuii proprietii DataSource


valoarea Sportivi. Se face acest lucru, expandnd n panoul din dreapta

n mod succesiv nodurile: Other Data Sources, Project Data Sources i


SportDataSet:

Partea a III - a. Baze de date

300

A 1I
L

'5=1
d ll

C ursor

D efault

DataM em ber
1

(n one)

D e fa u 1 : M
Dock
Q - Q J O th er D ata Sources
EditMc

Enable

J j]
S3

P roject D ata Sources


2 1 S portD ataS et
71 Soortivi

Enable
Gener

F o rm l List Instances

GridCc

Astfel, n mod vizual, ai legat controlul la sursa de date.


6.

Facei B u ild i rulai cu F5.

La rulare obinei:

IdSportiv

1
2
..........
,j 3

....

Nume

Prenume

DataNasterii

SportulPracticat A

Dita Tomescu

Constantina

23.01.1970

Atletism

Izbasa

Sandra

28.05.1998

Gimnastica

Alina

30.08.1982

Judo

| Dumitru

Andrunache

1Georgeta

14.04.1976

Canotaj

r5

Susanu

1Viorica

29.10.1975

Canotaj

7>

L
Exist i alte variante vizuale pentru popularea controlului.
Varianta a 2-a
Procedai dup cum urmeaz:
Paii 1, 2, 3, 4 sunt identici cu cei specificai anterior. Continuai astfel:5

5. n meniul Data, selectai Show Data Sources. n fereastra Data Sources,


acionai click dreapta pe elementul Sp ortD ataSet, apoi selectai Configure
DataSet with Wizard...
Startl
SportDataSet
Jt

A dd N ew D a ta S o urce..,
E dit D a ta S e t w ith D esigner

F j

C o n fig u re D ata S e t w ith W iz a rd ...

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

301

6. n dialogul Data Source Configuration Wizard, selectai tabela Sportivi, apoi


apsai butonul Finish:
Data Source Configuration Wizard

Sfi/fgNH

Choose Your Database Objects

W hich d a ta b a s e o b je cts do yo u w a n t in y o u r dataset?

0-

Tables

+ 0 Z3 S portivi
i
;

Views
-Q t#

S tore d P rocedures

7. n fereastra Data Source, selectai tabela Sportivi i tragei-o pur i simplu

cu mouse-ul deasupra controlului DataGridView, n Form Designer.


Dt Sources

9 X

SportDataSet.w d

^Start Page

FormUS F o rm l.e s [D e s ig n ]*

Sportivi; Que

,;J L'J |
' r, SpctDat-aSet
S i- i Sportivi v
bl IdSportiv

bi Nume

,'.T~

bi Prenume
DataNauterii
abi SportijPracticai

8.

Facei Build i rulai cu F5. Vei obine popularea controlului cu datele din
tabel.

Varianta a 3-a
Procedai astfel:
Paii 1,2, 3, 4 sunt identici cu cei ai aplicaiei anterioare. Continuai astfel:
5.

Deschidei DataSet Designer. Pentru aceasta, avei dou posibiliti: n


Solution Explorer facei dublu click pe itemul SportDataSet.xsd sau n
panoul Data Source, click dreapta pe itemul SportDataSet i selectai Edit
DataSet with Designer.i
Start Page

situ U
SportData m
Add New Data Source. ..
Edit DataSet with Designer

Partea a III - a. Baze de date

302

6. n Database Explorer, selectai tabela Sportivi i o tragei cu mouse-ul pe

suprafaa DataSet Designer-ului:


Database Explorer

J
j B

-* 9 X

Sport.DataSet.xsd*

Start Page

Forml.cs*

p Data Corrections

Sportivi

Ufc Spwtrodf
H8 0 1 Database Diagrams
S3 t i l Tables
0 3 Sportivi
33 IdSportiv
13 Nume
j O Prenume
3 ] DataNasterii
23 SportulPracticat

IdSportiv
Mume
Prenume
DataNasterii
SportulPracticat

..r ^ 7 ..;

IP >

% F i,6et0ata()

C3 Views

7. Deschidei Form Designer-ul cu dublu click pe Forml.cs n Solution


Explorer. n panoul Data Source, selectai cu click tabela Sportivi i

plasai-o pe suprafaa controlului D ataG ridView .


8.

Facei build i rulai cu F5.

Observaii:

>
>

Toate cele trei variante de populare a controlului D ataG rid V iew realizeaz o
legare a controlului la sursa de date printr-un obiect de tip BindingSource.
Despre clasele DataSet, BindingSource, Table Adapter, dar i despre
modul n care populai programatic un control D ataG ridV iew , vom discuta n
seciunile urmtoare.

Configurarea d esig n tim e a coloanelor unui DataGridView


Coloanele se adaug i se configureaz astfel:
1. n Form Desiger acionai click pe sgeata din colul dreapta sus al controlului
D ataG ridView , apoi alegei Edit Columns.
2. n dialogul Edit Columns adugai coloane. Pentru fiecare coloan avei n
panoul Unbound Column Properties, diverse proprieti care pot fi setate, ntre
care i textele header-elor.

Capitolul 10.

Baze de date i ADO.NET. Noiuni introductive

IDSportiv

Prenume

Data Naterii

303

DataGridView Tasks

Sport P racticat...........- .............................

Choose Data Source ; (none)


Edit Columns...
Add Column...

fiabil Nume

<
0r

j [abi; Prenume
i {abi; Data Naterii
j ;abl Sport Practicat

Unbound Column Properties

if'!41 _

Enable Editing

Enable Deleting

Enable Column Reordering

MaxInputLength

32767

Readonly

False

Resizable

True

SortMode

Automatic

Ajj

Dock in parent container

B Data
DataPropertyName

(none)

B Design
(Name)
ColumnType
~ ..... .... "
[

Add...

........ ..j[

Remove

Enable Adding

Column 1
DataGridViewTextBoxColu:v j

(Name)
Indicates the name used in code to identify the
object.
Cancel

Partea a III - a. Baze de date

304

C a p ito lu l 11

Aplicaii cu baze de date n modelul conectat


ADO.NET permite aplicaiilor s lucreze att n modelul conectat la baza
de date, ct i n modelul deconectat.
n modelul conectat se utilizeaz provider-ii specifici diferitor surse de date.
De exemplu, pentru comunicarea cu SQL Server 2005, folosim clasele specifice
acestui provider: SqlConnection i SqlReader. Aplicaia se conecteaz,
execut interogrile, apoi se deconecteaz.
n modelul deconectat se creaz un dataset care preia din baza de date
tablele necesare. Aplicaia se deconecteaz de la baza de date, execut interogri
asupra acestui dataset, apoi face update-ul necesar n baza de date.
n continuare propunem cteva modele de lucru cu bazele de date, att n modelul
conectat ct i deconectat. Vor fi aplicaii de tip consol, dar i de tip Windows
Forms.
Vom realiza cteva aplicaii care folosesc provider-ul pentru SQL Server 2005,
pentru OLE DB i pentru ODBC. Reamintii-v c ADO.NET include data provided
pentru diferite surse de date.

Utilizarea provider-ului pentru SQL Server 2005


Realizm o aplicaie este de tip consol. Relum aplicaia DatabaseExample
din capitolul anterior. Aceasta conine baza de date coala, cu o singur tabel:
Elevi. S presupunem c tabela are doar dou rnduri:
IdE lev
l
{ . ____ |2

Nume

Prenume

V ersta

Nedelcu

Valentin

17

Pop

Andrei

19

Executm dou operaii asupra tabelei Elev: inserarea unui rnd nou i selectarea
rndurilor.
Urmai paii:
1.

Deschidei aplicaia de tip consol, DatabaseExample. n Solution Explorer,


redenumii Program.es astfel: SQLDataProvider.es (click dreapta i
Rename).

2.

Deschidei fiierul SQLDataProvider.es (click dreapta i View Code) apoi


nlocuii codul existent cu urmtorul:
using System;
using System.Data.SqlClient;

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

305

namespace ConsoleApplicationl

{
class SQLDataProvider

{
static void Main(string[] args)

{
// Construim stringul de conectare
(connection string)
string connString =
0"server = .\sqlexpress;
Database=Scoala.mdf;
trusted_connection=True;
AttachDbFileName =
C:\DatabaseExample\DatabaseExample\bin\Debug\Scoala.mdf";
/ /

// Pregtim interogrile
string sqll = 0"SELECT * FROM Elevi";
string sql2 = 0"INSERT INTO Elevi
(Nume, Prenume, Varsta)
VALUES
('Axente', 'Mihai', 20)";

// Declarm variabilele conexiune


/ /i c i t i t o r u l d e d a t e
SqlConnection conn = null;
SqlDataReader reader = null;
try
{

// Deschidem conexiunea
conn = new SqlConnection(connString);
conn.Open();

// Executm prima interogare


SqlCommand cmd = new SqlCommand(sqll, conn);
reader = cmd.ExecuteReader();

// nchidem reader-ul
// pentru a putea fi refolosit
reader.Close();

// Executm a doua interogare - inserarea


// unui rand
cmd = new SqlCommand(sql2, conn);
reader = cmd.ExecuteReader();
reader.Close();
// Din nou un SELECT pentru a avea

// un r e s u l t s e t
cmd = new SqlCommand(sqll, conn);

Partea a III - a. Baze de date

306

reader = crad.ExecuteReader();
Console.WriteLine("Baza de date " +
conn.Database + " se interogheaz cu "
+ cmd.CommandText);
// Afim informaiile din result set
while (reader.Read())
Console.WriteLine("{0}
{1}
{2}",
reader[l], reader["Prenume"] ,
reader[3]);
Console.WriteLine();

}
catch (Exception e)

{
Console.WriteLine("Eroare: " + e ) ;

}
finally

{
// Conexiunea se nchide indiferent dac se
// arunc sau nu excepii
reader.Close();
conn.Close();
conn.Dispose();

}
} //Main()

}
}
3.

Facei Build i rulai cu Ctrl + F5 (Modul depanare)


C:\WINDOWS\system32\cmd.exe

aza de date coala.mdf se interogheaz cu SELECT * FROM Elevi


edelcu Ualentin
17
op Andrei 19
Ixente
Mihai 20
ress any key to continue

. . . _

hi

Reinei etapele comunicrii cu baza de date:


Paii urmtori sunt aceeai indiferent de providerul cu care lucrai:

Se include spaiul de nume System.Data.SqlClient.


Clasele acestuia definesc providerul pentru MS SQL Server. Pentru ali
provided, se nlocuiete prefixul Sql cu cel corespunztor.

Se deschide o conexiune cu baza de date

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

307

>

Clasa SqlConnection permite obinerea unei conexiuni la server


i deschiderea conexiunii cu metoda Open ( ) .
^ Constructorul acestei clase, SqlConnection (connString),
primete stringul de conectare.
A Proprietile
Databasei
CommandText
ale
clasei
SqlConnection returneaz baza de date, respectiv interogarea
curent.

Executarea interogrii
>
>

>

>

Ca s executai o interogare, trebuie mai nti s construii un


obiect de tip SqlCommand.
Constructorul SqlCommand(sql,conn) primete ca argumente
interogarea care trebuie executat i conexiunea prin care va
lucra.
Executararea propriuzis a interogrii, se face cu metoda
ExecuteReader (). Aceasta face dou lucruri: construiete un
obiect (reader) de tip SqlDataReader i apoi execut
interogarea.
Metoda ExecuteReader () returneaz un result set care poate fi
vid pentru comenzi non-query, cum este i n s e r t i n t o ,dar nevid
pentru s e l e c t . Acest result set se poate imagina ca o tabel n
care se regsesc rezultatele interogrii.

Accesarea rezultatelor interogrii


>

>

Ca s analizai setul de rezultate, parcurgei setul n bucl cu


metoda Read(), care la fiecare apel, avanseaz reader-ul la
urmtoarea linie.
Datele de pe linie se acceseaz indexat, reader [0] este
valoarea
corespunztoare
primei
coloane,
reader [1]
corespunde celei de a doua coloane, etc. Un alt mod de accesare
este prin numele coloanei respective, aa cum am artat n
aplicaie: reader ["Prenume"] este valoarea aflat pe linia
curent i coloana Prenume. Se prefer accesarea prin indeci
pentru c este mai rapid.

Protecia mpotriva excepiilor


>

Deschiderea conexiunii (new SqlConnection (connString))


trebuie protejat ntr-un bloc try ...catch, pentru tratarea
excepiilor. Astfel ne asigurm c blocul finally, n care
eliberm resursele va fi executat. Se face acest lucru, deoarece
ADO.NET arunc excepii la erorile de baze de date. Este foarte
simplu s avei erori. De exemplu, greii ceva n stringul de
conectare, sau baza de date este blocat de cte o alt aplicaie.

308

Partea a III - a. Baze de date

Blocul u s i n g - o tehnic sigur


Clasele Connection, aa cum este SqlConnection motenesc interfaa
IDisposable. Aceasta nseamn c un obiect de acest tip poate referi resurse
negestionate n mod automat de .NET (unmanaged resources). Poate fi vorba de
surse de date, fiiere pe disc i altele. Toate clasele care motenesc aceast
interfa au metoda Dispose (), care trebuie invocat de ctre programator
pentru eliberarea acestor resurse. n mod obinuit, se apeleaz n blocul finally.
O metod mai elegant pentru tratarea excepiilor este utilizarea blocului
using. Nu confundai cu directiva using. Obiectele iDispozable se declar i
se instaniaz n declaraia using. n acest fel, v asigurai c metoda Dispose ()
este apelat chiar n cazul n care se arunc excepii.
lat cum se poate scrie codul cuprins n blocul try ... catch n programul
de mai sus:
using (conn = new SqlConnection(connString) )

{
conn.Open();
SqlCommand cmd = new SqlCommand(sqll, conn) ;
reader = cmd.ExecuteReader();
// cod ...
while (reader.Read())
Console.WriteLine("{0}
{1} {2}",
reader[1], reader["Prenume"],
reader[3]) ;
reader.Close();

}
Observai c nu mai este nevoie nici mcar s nchidei conexiunea,
deoarece de acest lucru se ocup acum C#.

Ce reprezint c o n n ec tio n s trin g ?


Stringul de conectare este un string care specific informaii despre o surs
de date, precum i mijloacele de conectare la aceasta. Se transmite data providerului pentru iniierea conexiunii. Conine atribute cum sunt: numele driverului,
numele serverului de baze de date, numele bazei de date, informaii de securitate
cum ar fi user i parol i altele.
n aplicaia anterioar, server = .\sqlexpress ; specific faptul c se
utilizeaz o instan a SQL Server 2005 Express Edition, aflat pe maina local
(prin . \ se precizeaz c e vorba de localhost).
Se indic deasemenea numele bazei de date prin Database=Scoala.mdf ; Mai
departe, trusted_connection=True; permite userului curent autentificat s
fac o conexiune.

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

309

Atributul AttachDbFileName specific calea de director pe discul local pn la


baza de date. Procesul prin care aducei la cunotin serverului SQL Server de
existena unei baze de date se numete ataarea bazei de date.
Ajuni n acest punct, precizm c baza de date se compune din dou
fiiere strns legate : fiierul cu extensia (,mdf) i cel cu extensia (.Idf). Primul
depoziteaz datele, iar ai doilea este fiier de log, care conine informaii despre
tranzacii.
Exist mai multe atribute care pot fi incluse n stringul de conectare. De
multe ori, alegerea lor corect este o problem. Din fericire, exist destul
documentaie i chiar site-uri dedicate. Recomandm unul dintre acestea:
www.connectionstrings.com.

Utilizarea provider-ului pentru OLE DB


Cu ajutorul furnizorului de date OLE DB, se pot accesa date depozitate n
diverse tipuri de baze de date, de la MS Access pn la Oracle. V putei conecta
inclusiv la SQL Server 2005, ns acesta are propriul lui provider, aa cum ai
vzut, care este mai rapid. Acest data provider este definit n spaiul de nume
System.Data.OleDb. Cele mai importante clase ale sale sunt:
OleDbCommand
OleDbConnection
OleDbDataReader

E x e c u t in te ro g ri s a u p ro c e d u r i s to c a te
R e p r e z in t o c o n e x iu n e la o s u r s d e d a te
P e rm ite c itir e a n u m a i n a in te , a u n u i s tre a m d e r n d u ri
d in tr-o s u r s d e d a te

OleDbDataAdaptor

R e p re z in t

le g tu r

n tre

su rsa

de

d a te

i d a ta s e t,

f o lo s it p e n tr u o b in e re a i s a lv a r e a d a te lo r.

Este uor de remarcat similitudinea ntre clasele furnizorului OLE DB i cele ale
SQL Server 2005. Metodele acestor clase sunt de asemenea similare.

Aplicaia OleDbProviderWinApp
Vom accesa o baz de date Microsoft Access 2003 cu ajutorul providerului
Microsoft. Jet.OLEDB. 4.0. Acest furnizor este specific pentru bazele de date

Access.
Urmai procedura:
1. Deschidei Micosoft Access i creai baza de date Access Persoane.mdb, cu
urmtoarea schem:

Partea a III - a. Baze de date

310

} f^ ie r

Ic te re

Vtzuateare

Interare

Instrumente

li Persoane: Tabel

I4un*e cmp

S* ID
Nume
Prenume

Dafc^testar*

Tip de date
AutoNumerdtare
Text
Text
Dat/Ora

Completai cteva rnduri cu date n tabel. Salvai baza de date


Persoane.mdb n folderul C:\teste.
2.

Creai n VCSE un nou proiect de tip Windows Forms, cu numele


OleDbProviderWinApp.

3.

Pe suprafaa formei plasai un control de tip DataGridView.

4. n fiierul Forml.cs introducei directiva: using System.Data.OleDb;

5.

Intenionm s populm controlul la ncrcarea formei. Prin urmare, tratm


evenimentul Load pentru form. Acionai dublu click pe suprafaa formei. n
corpul band/er-ului, introducei codul marcat cu Bold:
private void Forml_Load(object sender, EventArgs e)

{
// Setm numrul coloanelor i textul
dataGridViewl.ColumnCount = 4;
dataGridViewl.Columns[0].HeaderText =
dataGridViewl.Columns[1].HeaderText =
dataGridViewl.Columns[2].HeaderText =
dataGridViewl.Columns[3].HeaderText =

h e a d e r - e lor

"ID-ul";
"Numele";
"Prenumele";
"Data Naterii";

// Stringul de conectare
string connString =
0"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=
C :\teste\Persoane.mdb;";
// Stringul de interogare
string sql = @"select * from Persoane";
// Declarm variabilele conexiune i data read e r
OleDbConnection conn = null;
OleDbDataReader reader = null;
// Crem conexiunea
using (conn = new OleDbConnection(connString))

Capitolul 11.

Aplicaii cu baze de date n modelul conectat


conn.Open ();

311

// Deschidem conexiunea

// Se execut interogarea
OleDbCommand cmd = new OleDbCommand(sql, conn);
reader = cmd.ExecuteReader();

// Tablou de stringuri. Reine valorile unui rnd


// din tabel
string[] r = nuli;
// Metoda Read() avanseaz reader la un rnd nou
while ( reader.Read() )

{
r = new string[4]{ reader[0].ToString(),
reader[l] .ToStringO ,
reader [2] .ToStringO ,
reader [3] .ToStringO };

// Adugm rndul n control


dataGridViewl.Rows.Add(r);

}
reader.Close();

> // using
}
6.

Compilai i executai cu F5.

Vei avea ceva asemntor:

ID-ul

Numele

Prenumele

Data Naterii

Voicu

Ionel

16.01.1988 00:0...

Grapini

Grigore

10.11.1987 00:0...

Pop

loan

21.02.1990 00:0...

U liniei

Sorin

114.07.1991 00:0...

y& em

&mhhs

ivi. N

De retinut:
>
>

Coloanele, mpreun cu textul header-elor se pot aduga design time, ns


am dorit s artm cum le setai programatic.
Stringul de conectare are dou atribute: Provider i Data Source.
Primul indic providerul OLE DB pentru bazele de date Access, iar al
doilea indic sursa de date i locaia sa.

Partea a III - a. Baze de date

312

>

Rndurile
se
adaug
n
control
cu
metoda
Add():
dataGridViewl.Rows.Add(r) ; , unde r este un ir de stringuri care
reine valorile reac/er-ului.
Declaraia using asigur eliberarea resurselor alocate att pentru o ieire
normal din bloc, ct i la aruncarea unei excepii. Observai c nu este
nevoie s mai nchidei conexiunea, ci doar reader-ul.
Remarcm similitudinea codului i a tipurilor utilizate pentru provider-ii
SQLServer i OLE DB.

>

>

Utilizarea provider-ului pentru ODBC


ADO.NET include furnizorul de date ODBC n spaiul de nume
System.Data.Odbc. Este prima tehnologie Microsoft de accesare a surselor de
date, fiind nc folosit pentru surse de date care nu au provider OLE DB. Poate fi
folosit cu aproape oricare tip de surs de date. ODBC comunic cu sursa de date
prin intermediul driver-ului sursei de date, deci apare un nivel intermediar i
aceasta face ca viteza de lucru s fie mai mic n raport cu ali provided.
Cele mai importante clase asociate provider-ului ODBC sunt uor de
recunoscut,
dup
prefixul
Odbc:
OdbcCommand,
OdbcConnection,
odbcDataAdaptor, OdbcDataReader. Semnificaia acestora este aceeai cu a
claselor similare ale celorlali provided.
Vom realiza dou aplicaii. Prima aplicaie se conecteaz la un fiier Excel
iar a doua la un server MySql.
Folosim n mod intenionat metode diferite de conectare ODBC pentru cele
dou aplicaii: n caul primei aplicaii includem n stringul de conectare informaii
despre driver-ul Excel, iar pentru a doua aplicaie realizm o surs de date cu un
utilitar integrat sistemului de operare. Precizm c ambele metode pot fi folosite i
lucreaz la fel de bine pentru aplicaiile cu provider ODBC.

Aplicaia O d b c E x ce lE xa m p le
Vom reliza o aplicaie de tip Windows Forms care se conecteaz prin
providerul ODBC la un fiier Excel 2003, n care pe prima foaie este un tabel.
Datele se citesc din sursa de date i se afieaz ntr-un control DataGridView.
Urmai indicaiile:
1.

Deschidei Micosoft Excel i scriei tabelul:

A
J. . . B _ | _ ..... C .
Id P ro d u s
D e n u m ire P re

C a n tita te

1 P a in e

2 L a p te

23

3 Ia u rt

45

4 C o la

21

200

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

313

Salvai fiierul cu numele Produse.xls n folder-ul C:\teste.


2.

Creai n VCSE un nou proiect de tip Windows Forms, cu numele


Odb cExcelExample.

3.

Pe suprafaa formei plasai un control de tip DataGridView.

4. n fiierul Form1.cs introducei directiva: using System.Data.Odbc;


5.

Dorim s populm controlul la ncrcarea formei. Deci tratm evenimentul


Load pentru form. Acionai dublu click pe suprafaa formei. n corpul
handler-ului, introducei codul marcat cu Bold:
private void Forml_Load(object sender, EventArgs e)
{
// Setm numrul coloanelor i textul header-elor
dataGridViewl.ColumnCount = 4;
dataGridViewl.Columns[0].HeaderText
dataGridViewl.Columns[1].HeaderText
dataGridViewl.Columns[2].HeaderText
dataGridViewl.Columns[3].HeaderText

=
=
=
=

"ID-ul";
"Nume";
"Pre";
"Nr Produse";

// Stringul de conectare
string connString =
@"Driver={Microsoft Excel Driver (*.xls)};
Driverld=790;
Dbq=C:\teste\Produse.xls;
DefaultDir=C:\OdbcExcelExample\OdbcExcelExample\bin\Debug";

// Stringul de interogare
// [Foaiel$] poate fi [sheetl$] dup caz
string sql = @"select * from [Foaiel$]";

// Declarm variabilele conexiune i d a t a r e a d e r


OdbcConnection conn = null;
OdbcDataReader reader = null;

// Crem conexiunea
using (conn = new OdbcConnection(connString))

{
conn.Open();

// Deschidem conexiunea

// Se execut interogarea
OdbcCommand cmd = new OdbcCommand(sql, conn);
reader = cmd.ExecuteReader();

// Tablou de stringuri. Reine valorile unui rnd


// din tabel
string[] r = nuli;

Partea a III - a. Baze de date

314

// Metoda Read() avanseaz reader la un rnd nou


while (reader.Read())

{
r = new string[4]{ reader[0].ToString(),
reader[1].ToString(),
reader[2].ToString(),
reader[3].ToString() };
dataGridViewl.Rows.Add(r);

}
reader.Close();
} // using

}
6.

Compilai i rulai cu F5.

La rulare obinei:

ID-ul

Nume

Pre

Nr Produse

Paine

200

Lapte

23

Iaurt

Cola

....f l H

,,

45
21
v

Observaii:
j
>
>

Stringul de conectare precizeaz driver-ul Excel i ID-ul su. Dbq indic


sursa de date i calea de director, iar DefaultDir este directorul implicit.
Codul C# este similar cu cel pentru provider-ii OLE DB sau SQL Server.

Aplicaia O d b cM yS Q L
Scopul acestei aplicaii este acela de a arta modul n care v putei conecta
la o baz de date MySQL cu C#, utiliznd provider-ul ODBC.
Diferena estenial fa de modul de conectare al aplicaiei anterioare
const n faptul c vom construi un Data Source Name {DSN) cu ajutorul unui
utilitar windows. Acest DSN se utilizeaz apoi n stringul de conectare.
Separm tema n trei seciuni:

A) Instalarea serverului MySQL 5.0 i crearea unei baze de date


MySQL
Presupunnd c nu avei MySQL instalat i c nu ai mai lucrat cu aceast
baz de date, procedai dup cum urmeaz:

Capitolul 11.
>
>

Aplicaii cu baze de date n modelul conectat

315

Intrai pe site-ul www.mysql.com. La seciunea download, descrcai


fiierul mysql-essential-5.0.45-win32.msi.
Wizard-ul de instalare v cere anumite informaii, pe care le completai
selectnd urmtoarele opiuni (bifai check box-urile):
S Configure the MySQL Server now.
s Install as Windows Service.
S Launch the MySQL Server Automatically".
A Include Bin Directory in Windows PA TH".
s Modify Security Settings". Introducei parola de root n cele dou
text box-uri.
S Enable root access from remote machines".
'A Create An Anonymous Account.

n felul acesta, ai instalat MySQL Server 5.0 ca serviciu Windows care


starteaz n mod automat la pornirea calculatorului. Avei un cont de administrator
(root) i un cont Anonymous. Acesta din urm v permite s v conectai fr s
introducei user sau parol. Este bine s avei un asemenea user numai n
perioada de nvare, deoarece n practic creeaz probleme de securitate.
Acum serverul e lansat. l putem folosi. Ne conectm cu clientul mysql.exe
la serverul MySQL pentru a crea o baz de date cu o tabel. Urmai indicaiile :
1. n taskbar-ul sistemului de operare, click Start->Run. introducei cmd i
apsai OK.
2. Tastai la promptul sistemului: mysql. n acest fel v-ai conectat ca user
Anonymous, deoarece nu ai specificat user i parol.
3. Tastai create database clasa;
Ai construit astfel o baz de date cu numele clasa.
4. Tastai show databases;
Vizualizai astfel bazele de date preinstalete i noua baz de date creat.
5. Introducei comanda use clasa; pentru a utiliza aceast baz de date.
C' C:\WINDOWS\syslem32tand.exe - mysql
C:\>mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Kour MySQL connection id is 4 to seruer version: 5.0.45-community-ntj
Type 'help;' or *\h' for help. Type \c' to clear the buffer.
mysql> create database clasa;
Query OK, 1 row affected <0.00 sec)
mysql> show databases;

------------------------- +
Database

inf ornat ion_schema


clasa
mysql
test

+------------

4 rows in set <0.00 sec)


mysql> use clasa;
Database changed
mysql>

Partea a III - a. Baze de date

316

6.

Crem o tabel. Introducei comanda:


create table Elevi
(Nume varchar(15), Prenume varchar(15), Varsta int);

7.

Inserm cteva rnduri n tabel:


insert into Elevi values ('Blaga', 'Ionel', 25);
insert into Elevi values ('Horga', 'Lucian', 25);
insert into Elevi values ('Chifa', 'Ionel', 19);

8.

Acum avem baza de date Clase cu o tabel numit Elevi. Tabela


conine trei rnduri. V deconectai de la server cu comanda quit.

B) Crearea unui D ata S ou rce N am e (DSN)


Informaiile necesare conectrii la o surs de date cu provider ODBC se pot
centraliza cu utilitarul ODBC Data Source Administrator. Ceea ce se obine se
numete Data Source Name (DSN).
Procedai astfel:
1. n bara de task-uri a sistemului de operare, accesai Start->AII Programs>Control Panel. Dublu click pe iconul Administrative Tools, apoi lansai
Data Sources(ODBC). Se deschide dialogul ODBC Data Source
Administrator.
2. n pagina User DSN, apsai butonul Add. Se deschide dialogul Create
New Data Source. Selectai din list driver-ul MySQL, apoi click pe butonul
Finish:

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

317

ser DSN ; System DSN j File DSN | Drivers | Tracing ; Connection Pooling ] About
User Data Sources:
Add...

Select a driver for which you want to set up a data source.


Name...........
........ ......... ....
Microsoft Paradox Driver (x.db)
Microsoft Paradox-T reiber (x.db)
Microsoft Text Driver (X.txt; x.csv)
Microsoft Text-Treiber (X.txt; x.csv)
Microsoft Visual FoxPro Driver
Microsoft Visual FoxPro-Treiber
SQL Native Client
SQL Server

)V
4
4
4
4
6
6

Finish

3.

jnnect to
to you.

2
2v

'

Cancel

Completai formularul de mai jos. n cmpul Data Source Name, introducei


ConexiuneMySQL. Dac dorii s v conectai ca user Anonymous, nu
este necesar s completai cmpurile User i Password.

Partea a III - a. Baze de date

318

Dac serverul MySQL nu este pe maina local, atunci n cmpul Server


trecei IF-ul host-ului respectiv. De exemplu: 80.97.66.192
4.

C)

Apsai butonul OK pe dialogul de mai sus. Ai creat deja un DSN cu


numele ConexiuneMySQL, pe care l pasm stringului de conectare n
aplicaia C# care urmeaz.

Crearea aplicaiei C#

Aplicaia de tip Windows Forms se conecteaz la serverul MySQL de pe


maina local i acceseaz baza de date clasa, creat la paii anteriori. Apoi
afieaz ntr-un control DataGridView datele din tabela Elevi. Procedai astfel:
1.

Creai n VCSE un nou proiect de tip Windows Forms, cu numele


OdbcMySQL.

2.

Pe suprafaa formei plasai un control de tip DataGridView.

3. n fiierul Form1.cs introducei directiva: using System.Data.Odbc;

4.

Controlul se va popula la ncrcarea formei. Prin urmare, tratm evenimentul


Load pentru form. Acionai dublu click pe suprafaa formei. n corpul
handler-ului, introducei codul marcat cu Bold:
private void Forml_Load(object sender, EventArgs e)

{
dataGridViewl.ColumnCount = 3;
dataGridViewl.Columns[0].HeaderText = "Numele";
dataGridViewl.Columns[1].HeaderText = "Prenumele";
dataGridViewl.Columns[2].HeaderText = "Varsta";
string connString =
"dsn=ConexiuneMySQL;User=root;Password=iuliuta";
string sql = @"select * from elevi";
OdbcConnection conn = null;
OdbcDataReader reader = null;
using (conn = new OdbcConnection(connString))

{
conn.Open();
// Se execut interogarea
OdbcCommand cmd = new OdbcCommand(sql, conn);
using (reader = cmd.ExecuteReader())

{
string[] r = null;
while (reader.Read())

Capitolul 11.

Aplicaii cu baze de date n modelul conectat

319

r = new s t r i n g [ 3 ] { r e a d e r [0] .T o S tr in g O ,
reader [1] .ToStringO ,
reader [2] .ToStringO };
dataGridViewl.Rows.Add(r);

}
5.

Compilai i executai cu F5.

La rulare, controlul DataGridView afieaz datele din tabela Elevi, obinute n


urma interogrii SELECT:

N um ele

Blaga

V ersta

Prenum ele
|

Ionel

\ 25

H orga

Lu cia n

25

Chifa

Ionel

19
j

Precizri:

MySQL ofer propriul provider ODBC, numit MyODBC. Este driver-ul pe


care l-am utilizat la crearea DSN.
ADO.NET are un provider dedicat pentru MySQL, definit n spaiul de
nume MySql.Data.MySqlClient.
Nu am comentat codul, deoarece este similar cu cel al aplicaiilor
anterioare cu provider ODBC.

320

Partea a III - a. Baze de date

C a p ito lu l 12

Aplicaii cu baze de date n modelul deconectat


Dac ceea ce dorii este doar s citii i s afiai mari cantiti de date,
atunci un obiect de tip DataReader este foarte potrivit. n cazul n care trebuie s
efectuai mai multe operaii asupra acestor date i la final s actualizai baza de
date, atunci un reader nu este cea mai potrivit alegere, deoarece el parcurge
datele o singur dat, doar nainte i pentru fiecare operaie este nevoie s
construii un alt obiect de tip DataReader. Ceea ce trebuie s facei n aceste
situaii, este s folosii un dataset.
Un dataset este un obiect de tip System.Data.DataSet. Dafasef-urile
sunt capabile s depoziteze mari cantiti de date n memoria intern a
calculatorului. Un dataset v permite s preluai date din sursa de date, s nchidei
conexiunea cu baza de date, apoi s prelucrai datele offline, adic n modul
deconectat de la sursa de date. La final, cnd prelucrarea datelor s-a ncheiat,
baza de date se actualizeaz.
Un dataset memoreaz datele ntr-o colecie de tabele (obiecte de tip
DataTable) i de relaii ntre tabele.
n momentul n care construii un obiect de tip DataSet, acesta nu conine
date. Ca s primeasc date este nevoie de un obiect de tip DataAdapter. Un
DataAdapter este parte a furnizorului de date, n vreme ce un dataset este
exterior provider-ului. Fiecare provider are propriul su adaptor de date. Spre
exemplu, adaptorul provider-ului pentru SQL Servereste SqlDataAdaptor.

Construirea i utilizarea dataset-urilor


Ca s creai
constructorii clasei:

instan

clasei

DataSet,

utilizai

unul

dintre

DataSet ds = new DataSet();


DataSet ds = new DataSet("numeDataSet");

Al doilea constructor precizeaz numele dataset-ului. Primul constructor, atribuie


dafasef-ului numele NewDataSet.
n dataset, datele sunt organizate ntr-un set de tabele. Fiecare tabel se
memoreaz ntr-un obiect de tip DataTable. Fiecare obiect DataTable consist
din obiecte de tip DataRow i DataColumn, care pstreaz datele.
S presupunem c un dataset primete datele de la un SqlDataAdaptor.
Secvena standard de cod care construiete i umple dataset-ul este :
// Creeaz adaptorul de date
SqlDataAdapter da = new SqlDataAdapter(sql, conn);

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

321

// Creeaz dataset-ul
DataSet ds = new DataSet ();
// ncarc dataset- ul cu tabela elevi. Dac exist i alte
// tabele n sursa de date, acelea nu se ncarc
da.Fill(ds, "elevi");
Aadar, constructorul clasei SqlDataAdaptor primete stringul de conectare i
conexiunea (referina la un obiect de tip SqlConnection), iar metoda Fill a
adaptorului umple d a ta s e t -ul cu tabela elevi.
Exist nc dou versiuni ale constructoului clasei SqlDataAdaptor. Primul nu are
parametri, iar al doilea primete un obiect de tip SqlCommand:
SqlDataAdapter da = new SqlDataAdapter();
SqlDataAdapter da = new SqlDataAdapter(cmd);
Pentru a ncrca n d a ta s e t toate tabelele din baza de date, utilizai alt versiune a
metodei Fill:
d a .Fill(ds);

Accesarea tabelelor ntr-un dataset


Un d a ta s e t poate s conin mai multe tabele. Acestea sunt obiecte de tip
DataTable care se pot accesa indexat, ncepnd cu indexul 0. de exemplu :
// Obine tabela a treia din dataset.
DataTable dt = ds.Tables[2] ;
Alt variant este accesarea prin numele tabelei:
// Obine tabela produse
DataTable

dt

d s .T a b l e s [" p r o d u s e " ];

Accesarea rndurilor i coloanelor ntr-o tabel


Rndurile unui unui obiect DataTable se obin din proprietatea Rows, care
suport indexarea :
// Obine al patrulea rnd al tablelei
DataRow r = dt.Rows[3];
Colecia de coloane a unui obiect DataTable se poate obine din
proprietatea Columns. Proprietatea suport operatorul de indexare, cu pornire de
la 0 :

322

Partea a III - a. Baze de date

// Obine coloana a 4-a


DataColumn col = d t .Columns[3];
// Obine coloana "Nume"
DataColumn col = d t .Columns["Nume"];

Accesarea valorilor dintr-o tabel a unui dataset


Se utilizeaz proprietile Rows i Columns ale clasei DataTable:
// Obinem tabela dorit
DataTable dt = d s .Tables["produse"] ;
// Pentru fiecare rnd din colecie (din tabela produse)
foreach (DataRow row in dt.Rows)

{
// Pentru fiecare coloan
foreach (DataColumn col in dt.Columns)
Console.Write(row[col]); // Accesare indexat a
// valorii unei celule
Console.WriteLine();
}

Propagarea schimbrilor din dataset spre baza de date


Am vzut c metoda Fill () a clasei TableAdaptor umple un d a ta s e t cu
datele preluate din baza de date. Dac metoda este apelat dup ce s-a nchis
conexiunea, atunci Fill() deschide conexiunea, transfer datele n dataset i
apoi nchide conexiunea. Dac conexiunea era deschis nainte de apelul Fill (),
atunci metoda las conexiunea deschis.
Modificrile operate asupra datelor unui d a ta s e t, se propag napoi n baza
de date la apelul metodei Update () a clasei TableAdaptor. Prezentm dou
versiuni ale acestei metode. Ambele returneaz numrul de rnduri updatate cu
succes.
Prima versiune actualizeaz baza de date opernd toate modificrile care s-au
fcut n d a ta s e t:
int Update(DataSet ds);
A doua versiune actualizeaz baza de date opernd toate modificrile care s-au
fcut n tabela transmis ca argument:
int Update(DataTable dt)

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

323

Actualizarea bazei de date se produce conform scenariului de mai jos:


// Creeaz adaptorul de date
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
// Creeaz dataset-ul
DataSet ds = new DataSet();
// Umple dataset-ul cu date din baza de date
da.Fill(ds);
// Se modific datele n dataset
I I ...
// Se propag modificrile n baza de date
ta.Update(ds);

Aplicaia U p d a te D a ta b a s e
Aplicaia de tip Windows Forms acceseaz o baz de date S Q L S e r v e r
2 0 0 5 i afieaz ntr-un control DataGridView datele dintr-o tabel. La apsarea
unui buton, modificrile operate de utilizator n celulele gridului se propag n baza
de date.
1.

Creai n VCSE un nou proiect de tip

Windows Forms, cu numele

UpdateDatabase.
2.

Pe suprafaa formei plasai un control de tip DataGridView i un buton cu


textul Salveaza i o etichet cu textul 0 rnduri afectate.

3.

Adugai proiectului o baz de date cu numele L ib r r ie . n acest scop, urmai


indicaiile subcapitolului Crearea unei baze de date in VCSE. Wizardul
propune numele LibrarieDataset pentru clasa pe care o genereaz.
Aceast clas motenete DataSet, aadar Este Un dataset.

4.

Adugai bazei de date L ib r r ie tabela Crti, cu urmtoarea structur:


Column Name
w

5.

Data Type

Allow Nulls

int

Titlu

nvarchar(50)

Autor

nvarchar(20)

Pre

int

n fereastra D a ta S o u r c e , acionai click dreapta pe tabela Crti i selectai


Edit DataSet with Designer. Dup ce designer-ul se deschide, tragei tabela
Crti cu mouse-ul, din fereastra D a ta S o u r c e pe suprafaa designerului:

Partea a III - a. Baze de date

324
Data Source;;

, S'

LibrarieDataSet

a S3 cwti
ai Cod
lattfi Titlu
iafel Autor

Start Page

'j
(fi

dbo.Carth Ta.,.\UERAP

m Carti

'9 cot)
iu
Autor
Pre

i|SjPre

...

F*,GetOata ()

Prin aceast aciune am cerut ajutorul mediului integrat, care a generat pentru
noi o clas CartiTableAdapter. Aceast clas conine un obiect de tip
SqlDataAdapter, un obiect de tip SqlConnection i un obiect de tip
SqlCommand, astfel nct nu mai trebuie s ne procupm de deschiderea
manual a unei conexiuni la server.
6.

Deschidei n E d ito ru l de C o d fiierul F o rm 1 .c s . n clasa F o rm l declarai


cmpurile:
// Declarm o referin la dataset
private LibrarieDataSet libDataSet = nuli;
// Referin la un obiect de tip CartiTableAdapter
private LibrarieDataSetTableAdapters.CartiTableAdapter
ta = nuli;

7. Populm controlul DataGridView la ncrcarea formei. Deci tratm


evenimentul Load pentru form. Acionai dublu click pe suprafaa formei. n
corpul h a n d le r- ului, introducei codul marcat cu Bold:
private void Forml_Load(object sender, EventArgs e)

{
//
//
//
ta

Instaniem adaptorul de date. Observai c este


necesar s specificm spaiul de nume n care este
definit clasa CartiTableAdaptor
= new
LibrarieDataSetTableAdapters.CartiTableAdapter();

// Crem un dataset
libDataSet = new LibrarieDataSet();
// Umplem dataset-ul cu datele din tabela Carti
t a .Fill(libDataSet.Carti);
// bs permite legarea controlului dataGridViewl
// la sursa de date din dataset
BindingSource bs = new BindingSource(libDataSet,
" C a r ti" ) ;

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

325

// Legarea se face prin proprietatea DataSource


dataGridViewl.DataSource = b s ;

}
8.

La acionarea butonului S a lv e a z a , se transmit modificrile din d a ta s e t n baza


de date. Tratm evenimentul Click. Acionai dublu click pe buton. Metoda de
tratare se editeaz astfel:
private void buttonl_Click(object sender, EventArgs e)

{
// Propagm modificrile spre baza de date.
int afectate = ta.Update(libDataSet.Crti);
labell.Text = afectate + " rnduri afectate";

}
9.

Compilai i rulai cu F5.

Aplicaia afieaz forma:

0 r n d u ri a fe c ta te

Cod

Salveaza

Titlu

Autor

ion

Liviu Rebreanu

1437

Rou si Negru

Stendhal

33

3512

Quo Vadis

Sienkiewicz

35

6423

:Ana KArenina

Pre

: 32

48

Tolstoi

<

Dac spre exemplu operm modificri n celulele din rndurile 3 i 4, iar apoi
apsam S a lv e a z a , obinem:

2 r n d u ri a fe c ta te

*
<

Cod

Titlu

Autor

Pre

231

Ion

Liviu Rebreanu

32

1437

Rou si Negru

Stendhal

33

3512

Quo Vadis

Henrik Sienkiewicz

35

6423

Ana Karenina

48
/V

.....

>

Partea a III - a. Baze de date

326

La o nou rulare cu F5 vei constata c modificrile aduse bazei de date sunt


persistente.

Observaii:

Mediul VCSE creeaz cele dou fiiere ale bazei de date (.mdf i .LDF) n
folderul de baz al aplicaiei, la un loc cu fiierul .csproj. n momentul n
care facei Build cu F5 (modul depanare), se face o copie a celor dou
fiiere n folderul \Bin\Debug, iar aplicaia se lanseaz i lucreaz cu
aceste copii. La noi rulri cu F5, nu se mai face Build dac nu ai adus
modificri n cod, ci numai lansri n execuie. Constatai c baza de date
din \Bin\Debug se actualizeaz. Dac ai operat modificri n cod, atunci la
un F5 se face i Build i baza de date original se copiaz peste cea din

\Bin\Debug.

Stringul de conectare se genereaz n mod automat la crearea bazei de


date cu ajutorul mediului integrat. Se poate vizualiza astfel: n Solution
Explorer, click dreapta pe fiierul a p p .c o n fig i selectai O pen. Vei
constata informaiile de conectare se pstreaz n format XML.
Atribuirea dataGridViewl.DataSource = bs; leag controlul de
d a ta s e t, astfel nct orice modificare operat in celulele controlului, se
transmite n mod automat tabelei din d a ta se t.

Dataset-urile i XML
Cnd lucrai cu cfafasef-uri, avei posibilitatea s salvai datele local, ntr-un
fiier de tip XML, astfel nct informaiile s persiste i n alt loc dect n baza de
date dup ncheierea sesiunii.
Salvai datele cu ajutorul metodei WriteXml () a clasei DataSet astfel:
ds.WriteXml(@"C:\date.xml") ;
Cnd deschidei o nou sesiune a aplicaiei, avei alternativa de a rencrca n
d a ta s e t datele preluate din fiierul XML. Citirea se face cu metoda ReadXml ():
d s . R e a d X M L (" C :\ d a t e .x m l " );

Exemplu:
Ne ntoarcem la aplicaia U p d a te D a ta b a s e , realizat anterior. Introducei ca
ultim linie n corpul metodei de tratare a evenimentului Click pentru butonul
S a lv e a za , apelul:
libDataSet.WriteXml(@"C:\carti_bune.xml");
Rulai cu F5, apoi cutai fiierul carti_bune.xml.
informaiile din d a ta s e t s-au salvat n format XML.

Vei constata c toate

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

IU

Controalele i legarea datelor


Anumite proprieti ale controalelor se pot lega la o surs de date. Sursele
de date sunt diverse: o proprietate a altui control, o celul, un rnd sau o tabel
ntr-un dataset, sau o simpl variabil. Conceptul se numete Data Binding. Dup
ce au fost legate, valorile din sursa de date schimb valorile din proprietatea legat
i invers.
Controalele Windows Forms suport dou tipuri de legare a datelor (data

binding):
* Legarea simpl.
Legarea complex.

Legarea simpl a datelor


Acest tip de legare v permite s ataai o proprietate a unui control la o
singur valoare din sursa de date. Este util pentru controale ca TextBox sau
Labei, care afieaz o singur valoare. Aplicaia urmtoare arat cum putei lega
proprietile a dou controale.

Aplicaia S im p le D a ta B in d in g
1.

Creai un nou proiect WindowsForms cu numele SimpleDataBinding.

2.

Pe suprafaa formei plasai dou controale: un TextBox i un Labe!.

3.

n constructorul clasei Forml, introducei codul evideniat n Bold:


public Forml()

{
InitializeComponent();
// Legm proprietatea Text a butonului (primul
// parametru) de proprietatea Text a text box-ului
buttonl.DataBindings.Add("Text", textBoxl, "Text");

}
4.

Tratm evenimentul Click al butonului. Acionai dublu click pe buton i


introducei codul marcat n Bold, n metoda de tratare:
private void buttonl_Click(object sender, EventArgs e)

{
buttonl.Text = "Salutare!";

}
5.

Rulai cu F5.

Facei click pe buton, apoi un click n text box ca s primeasc focusul. n text box
se afieaz Salutare!. Dac introducei text n textbox, eticheta butonului se
modific corespunztor.

328

Partea a III - a. Baze de date

U n u doi tre

U n u doi trej

Click pe buton

Editare n text box

Legarea complex a datelor


Aplicai acest tip de legare atunci cnd vrei s afiai o list de valori din
sursa de date. Controalele care suport legarea complex sunt DataGridView,
ListBox, ComboBox, CheckedListBox. Aceste controale au de proprietatile
DataSource i DataMember, cu ajutorul crora le putei lega la tabela unei baze de
date, astfel:
dataGridViewl.DataSource = librarieDataSet;
dataGridViewl.DataMember = "crti";
n exemplu, proprietii DataSource a gridului i se atribuie dafasef-ul aplicaiei, iar
proprietii DataMember i se atribuie numele unei tabele din dataset. Aceste setri
se pot face uor n fereastra P r o p e rtie s , aa cum vom vedea n continuare.

Aplicaia C o m p le x D a ta B in d in g l
Aplicaia utilizeaz utilizeaz facilitile mediului integrat pentru a lega
proprietatile unui control DataGridView la o tabel a unei baze de date SQL
Server 2005 Express. Urmai paii:
1.

Creai n VCSE un nou proiect de tip

Windows Forms, cu numele

ComplexDataBinding 1.
2.

Adugai proiectului o baz de date cu numele S p e c ta c o le . n acest scop,


urmai indicaiile subcapitolului Crearea unei baze de date in VCSE.
Wizardul propune numele S p e c ta c o le D a ta S e t pentru clasa pe care o
genereaz. Aceptai acest nume.

3.

Adugai bazei de date S p e c ta c o le tabela Concerte, cu urmtoarea


structur:

Capitolul 12. Aplicaii cu baze de date n modelul deconectat


Column Name

Data Type

j IDConcert

329

Allow Nulls

| int

TipConcert

nvarchar(20)

SustinutDe

nvarchar(50)

Data

datetirne

Locaie

nvarchar(20)

Completai cteva rnduri cu date n tabel.


4.

n fereastra Data Source acionai click dreapta pe tabela Concerte i


selectai E d it D a ta S e t w ith D e s ig n e r. Dup ce d e s ig n e r -ui se deschide, tragei
tabela Concerte cu mouse-ul din fereastra Data Source pe suprafaa
designerului. Prin aceast aciune am cerut ajutorul mediului integrat, care a
generat pentru noi o clas ConcerteTableAdapter.

5.

n V ie w D e s ig n e r selectai forma, iar n fereastra Data Sources deschidei


lista ataat tabelei Concerte i selectai D a ta G rid V ie w .
dbo.Cpncerte:...ECTftCOLE.MDF)

Specta

i 43.

B a l Spectacoie-DataSet

Si-(jpl
~1
!J

DataGridView
ComboBox

j 1*2 listBox
i EU

6.

Details

Urmeaz o aciune simpl: n fereastra Data Sources selectai cu mouse-ul


tabela Concerte, apoi o tragei peste form. Pe suprafaa formei apare un
control DataGridView, cu celulele legate la tabela Concerte:
'DataSources

dbo.Concerte:.. .ECTACOIE.MDF)

SpectacoleOataSet.xsd

Form l.es [Design]*

i V.-11 |

SpectacoleD-ataSet .
* j - i Concerte v

s?l spectacoleDataSet
' ) tabteAdapterManager

concerteBindingSource
* } - concerteKndlngNavigatar

t i ConcerteTableAdapter

Partea a III - a. Baze de date

330

Observai apariia n d e s ig n e r tra y a ctorva referine la obiecte de tip


TableAdaptor sau BindingNavigator.

7.

Rulai cu F5.

Vei obine:

1IDConcert

TipConcert
1 Rock

-2

Hip Hop

House

Country

Aid

SustinutDe

Data

: Metallica

12.03.2003

; Eminem

04.07.2009

Mickey Oliver
j Martina McBride
~~T ~ .... ' ........~

15.11.2009
24.02.2003
V.

< '...

ncercai singuri:
n proiectul anterior, tergei din d e s ig n e r tra y apsnd tasta d e le te toate
referinele. tergei i gridul de pe form. n fereastra Data Sources, selectai
D e ta ils , apoi tragei cu mouse-ul tabela pe suprafaa formei. Pe suprafaa formei
vor aprea patru controale de tip TextBox i un DateTimePicker. Fiecare control
este legat la una dintre coloanele tabelei.

Toate controalele indic acelai rnd din tabel. Navigarea de la un rnd la altul se
face cu ajutorul butoanelor sgeat din controlul ToolStrip din partea de sus a
formei.
A p lic a ia C o m p le x D a ta B in d in g 2
Modificm proiectul anterior astfel nct s legm proprieti ale controalelor

ListBox i TextBox la baza de date, ca s fie posibil editarea datelor i


trasmiterea modificrilor bazei de date.

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

331

Paii 1, 2, 3, 4 sunt identici cu cei ai aplicaiei precedente. Schimbai doar


numele proiectului : ComplexDataBinding2.
5.

n Dataset Designer, acionai click dreapta pe itemul ConcerteTableAdapter


i selectai Configure...
j ...

Start Page X dbo.Concerte:...ECTACOLE.MDF)

IDConcert
TipConcert
SustinutDe
Data
Locaie
C on certeT ab leA dapter
FilljGetData () j

Add Query..,

I
Configure,.,

Configurm adaptorul, deoarece vom apela metoda Update () pentru


actualizarea bazei de date i aceast metod utilizeaz interogri SQL n
acest scop. Vom genera interogrile n mod automat. Apsai butonul Next al
primului dialog. Al doilea dialog ne spune c va genera pentru noi metodele
Fill, GetData, Insert, Delete i Update. Apsai din nou Next, apoi pe
ultimul dialog, Finish.
6.

Plasai n Form Designer pe suprafaa formei un control ListBox, patru


controale TextBox, un Label i un buton :

7.

Din Toolbox alegei i plasai pe suprafaa formei, componentele:


ConcerteTableAdapter i Binding Source. Referinele se creeaz automat
i apar n designer tray.

Partea a III - a. Baze de date

332
Toolbox

Start Page

dbo.Concerten,.ECTACOLE.MDF)

Spe

- ComplexDataSindingl Components
; ^

Pointer

| 10 SpectacoleDataSet
! ( 0 ConcerteTabteAdapter
\ < 0 TabteAdapterManager
*

AJI W ind ow s F orm s

C o m m o n C on trols

C o n ta in e rs
r

M e n u s & T o o lb ars

- Data
! ^

0 RNDURI AFECATATE

Pointer

Salveaza

j |g^| DataSet
D ...................................................

;:p i DataGridVew
J-

i ? BmdmgSource

8.

tandingSour ce 1

Selectai n d e s ig n e r tra y bindingSourcel. n fereastra Properties atribuii


proprietii DataSource valoarea SpectacoleDataSet, iar proprietii
DataMember, tabela Concerte:

(Name)

b in d in g S o u rc e l

! 'ii

AIlowNew

True

;EI (AppiicationSettings)

DataMember

(Name)
(none)

. - tv

b is h

Q IJiJ O th er D ata Sources

; '3

b in d in g S o u rc e l

AllowNew

True

DataMember

I C o n c e rte

v,> None

S - t l P roject D ata Sources

9.

&Q, con certe ableAdapter 1

Concerte

SpectacoleD ataSet

Selectai controlul ListBox. Acionai click pe sgeata dreapta sus. n


fereastra care se deschide, facei seleciile ca n figur:

' - ' ListBox Tasks


i0

Use data bound items

D ata Binding Mode


Data Source
..OseKBrnreamroj QjSp|a y M e m b e r

b in d in g S o u rc e l
1S u s tin u tD e

0 R A N D U R I A F E D A T A ' V alue M e m b e r
5 e |e c te d V alue

_1

(n o n e )

Capitolul 12. Aplicaii cu baze de date n modelul deconectat

333

10. Selectai controlul TextBox cel mai de sus. n fereastra P ro p e rtie s , expandai
itemul Data Bindings i setai proprietatea Text la valoarea SustinutDe :
iQ (DataBindings)
(Advanced)

' ^

Tag

(none)

Text

(none)

bindingSourcel
jj

IDConcert
TipConcert

jO SustinutDe

11. Executai aceleai operaii de la pasul 10, pentru urmtoarele trei texffaox-uri,
cu diferena c vei lega proprietatea Text la celelalte coloane ale tabelei.
12. La ncrcarea formei, vom umple d a ta se t-u \. Dublu click pe suprafaa formei,
n E d ito ru l de C o d scriei:
private void Forml_Load(object sender, EventArgs e)

{
// Fill () ncarc datele din baza de date n dataset
concerteTableAdapterl.Fill(spectacoleDataSet.Concerte);

13. La click pe butonul S a lv e a z , transmitem bazei de date modificrile fcute de


utilizator. Dublu click pe buton. Scriei n metoda h a n d le r.
private void buttonl__Click(object sender, EventArgs e)

{
// Aplicm sursei de date modificrile fcute
bindingSourcel.EndEdit() ;
// Updatm baza de date
int afectate =
concerteTableAdapterl.Update(spectacoleDataSet);
labell.Text = afectate + " rnduri afectate";

}
14. Rulai cu F5.
Se obine:

Partea a III - a. Baze de date

334

Forml
M e ta llic a

Eminem
M ic k e y O livet
M a rtin a M c B rid e

Erninem
H ip H o p
: B u c u re ti

04.07.2009

1 r nduri a fe c ta te

S a lv e a z a

La click n lis t b o x , textele se modific n controalele text box n mod automat,


astfel nct toate controalele de pe form indic acelai rnd din tabel. Valorile
celulelor tabelei se pot edita din te x t b o x - uri, iar modificrile n baza de date sunt
persistente.

Capitolul 13. Relaii ntre tabele

335

Capitolul 13

Relaii ntre tabele


ntre tabelele unei baze de date (i a unui dataset) pot s existe relaii de tip
coala.mdf exist dou tabele:
Clase i Elevi. O clas are mai muli elevi. Construim deci o relaie ntre cele
dou tabele, de tip u n a la m a i m u lte (one to many).

p r in te - c o p il. S presupunem c n baza de date

Constrngerea Cheie Strin-Cheie Primar


n tabela Clase avem un cmp Clasa, care reprezint numele clasei (ex.
Xll-B). l setm cheie primar. n tabela Elevi introducem un cmp cu acelai
nume. Nu dorim s existe elevi pentru care cmpul Clasa are o valoare care nu
exist n tabela Clase. Impunem o constrngere de tip fo r e ig n k e y - p r im a r y k e y .
Este o constrngere referenial. clase este tabela printe, iar Elevi, tabela
copil. Un rnd al tabelei printe poate s refere multiple rnduri n tabela copil.

Aplicaia Scoaia
Aplicaia creeaz baza de date i tabelele precizate mai sus, impunnd o
constrngere de cheie strin-cheie primar. Dac un rnd n tabela Clase se
terge, atunci dorim s se tearg toate rndurile corespunztoare din tabela
Elevi pentru a pstra in t e g r ita te a d a te lo r. Vom seta regula de tergere pentru
aceast relaie: N CASCAD.

Atentie !
V sugerm s nu ocolii acest proiect, deoarece pe structura lui vom lucra
n temele urmtoare, unde va fi dezvoltat i completat.
1.

Realizai n VCSE un proiect de tip Windows Forms, cu numele Scoaia.

2.

Adugai proiectului o baz de date cu numele S c o a ia . n acest scop, urmai


indicaiile subcapitolului Crearea unei baze de date in VCSE. Aceptai
numele ScoalaDataSet pentru clasa de tip DataSet care se genereaz.

Column Name
j C lasa

D a ta T y p e
n v a rc h a r(5 0 )

N rE levi

in t

D irig in te

n v a rc h a r(B O )

Allow Nulls

Partea a III - a. Baze de date

336

Tabela Elevi
C o lu m n N am e

I ;

D a ta T y p e

Id E le v

in t

N um e

n v a rc h a r (5 0 )

M e d ia

re a l

A llo w N ulls

jiJ

Dup completarea schemei, introducei cteva rnduri n fiecare tabel.


4.

n Database Explorer, click dreapta pe D a ta b a s e D ia g ra m s . n dialogul A d d


T able selectai pe rnd tabelele Clase i Elevi i apsai butonul A d d .
Diagramele celor dou tabele apar n d e sig n e r.
d b o .D ia g ra m l...\S C O A L A .M D F )*

Clase

Form l.es [Design]

S tart Page

15

Clasa

IdElev

NrElevi

Nume

Diriginte

Media

Clasa

5.

Introducem constrngerea de cheie strin. Punctai cu mouse-ul n cmpul


Clasa din tabela Clase i tragei innd butonul apsat pn pe cmpul
Clasa al tabelei Elevi. Se deschide un dialog care identific cheia primar,
cheia strin i numele relaiei care se creaz:

Relationship name:
m

Primary key table:


Clase
Clasa

Foreign key table:


v j

Elevi

Clasa

6 . Apsai OK s nchidei dialogul anterior. Urmtorul dialog v permite s

stabilii regulile relaiei de cheie strin. Setai pentru Delete i Update regula
C a s c a d e , apoi apsai OK:
INSERT Arid UPDATE Specification
Update Rule

Cascade
Cascade

B Id e n tity

(Name)
Description

FK Elevi Clase

Capitolul 13. Relaii ntre tabele

337

7.

n designer, relaia se vizualiteaz ca o linie cu o cheie spre tabela printe i


simbolul infinit spre tabela copil (relaie una la mai multe). Salvai diagrama
sub numele Diagraml.

8.

Plasai pe suprafaa formei un control MenuStrip, un SplitContainer, iar n


cele dou panouri ale acestuia, cte un control DataGridView:

9.

Adugai meniului Clase, opiunile: Adug clasa, terge clasa, Modifica


clasa. Adugai meniului Elevi, opiunile: Adaug elev, terge elev, Modifica

elev.
Adugai meniului Rapoarte, opiunile: Diriginti-clase i Media pe clase.
10. Configurm dataset-ul aplicaiei cu ajutorul Wizard-ului. n fereastra D a ta
S o u r c e s , acionai click dreapta pe itemul ScoalaDataSet i selectai Configure
DataSet with Wizard. n dialogul care se deschide, selectai toate categoriile:
tabele, vederi, proceduri stocate, funcii, apoi apsai Finish.
11. Din fereastra D a ta S o u rc e s , tragei cu mouse-ul tabela Clase peste gridul din
stnga al formei, apoi tragei tabela Elevi peste gridul din dreapta.
12. Rulai cu F5
La rulare, se o t: ^e:

Partea a III - a. Baze de date

338

Interogri. Proceduri stocate.


Continum s dezvoltm proiectul coala, nceput anterior. Opiunile din
meniuri nu sunt nc funcionale. Ca s fie, trebuie s interogm baza de date.
Dac vrem s introducem noi clase sau elevi, avem nevoie de comanda SQL
i n s e r t .Cnd vom dori s tergem din baza de date o clas sau un elev, aplicm
d e l e t e ,iar cnd modificm datele ne trebuie u p d a t e .
O ntrebare fireasc ar fi: cum trimitem aceste interogri serverului de baze
de date, din codul nostru C# ? O prim variant este s manevrm clasele
SqlConnection, SqlCommand, SqlDataAdapter. Este laborios dac scriem tot
codul necesar.
Din fericire, mediul integrat ne ajut mult n aceast privin. Vom genera n
mod
automat
metode
C#
pentru
clasele
ciaseTableAdapter
i
EleviTableAdapter. Aceste metode ncapsuleaz interogrile SQL sau
p ro c e d u ri s to c a te . n continuare adugm interogri aplicaiei coala.

Aplicaia co ala - adugarea interogrilor


1.

n Solution Explorer, acionai dublu click pe itemul ScoalaDataSet.xsd. n


D a ta s e t
D e s ig n e r , pe
diagrama tabelei Clasa, click dreapta pe
CiaseTableAdapter. Selectai A d d Q u e ry ...

Add Q ue ry.,,
Configure..,

2.

Dialogul urmtor v permite s generai o metod care conine o interogare


SQL, o procedur stocat, sau o metod care apeleaz o procedur stocat
existent:
TabteAdapter Q uery Configuration Wizard
C h o o se a C o m m a n d T y p e
T able Adapter query uses SQL statements or a stored procedure

How should the TableAdapter query access the database?


@ Use SQL statem ents
Specify a SELECT statem ent to load data.

C reate new stored procedure


Specify a SELECT statem ent, and the wizard will generate a new stored procedure to select records.

Capitolul 13. Relaii ntre tabele

339

Selectai U se S Q L s ta te m e n ts i apsai OK.


3.

n dialogul urmtor, selectai INSERT i apsai N e xt:


TableAdapter Query Configuration Wizard
C ho ose a Q u e ry T y p e
Choose the type of query to be generated

7
W hat type of SQL query would you like to use?

SELECT which returns rows

Returns one or many rows or columns.

SELECT which returns a single value

Returns a single value (for example, Sum, Count, or any other aggregate function).
O UPDATE
Changes existing data in a table.
O DELETE
Removes rows from a table.

INSERT

Adds a new row to a table.

4.

Dialogul care se deschide propune o interogare INSERT TO pentru adugarea


unei clase. Apsai butonul Q u e ry B u ild e r...
Tab

BB8i i

ZHuBinAT

mm

Specify a SQL INSERT statement


The INSERT statement will be used by the query.

Type your SQL statement or use the Query Builder to construct it. What data should be loaded into the
table?
W hat d ata should the ta b le load?
i INSERT IN' : - ,: ; Oase' ([dasa], [NrElevi], [Diriginte]) VALUES (@Clasa, @NrElevi, Diriginte);
: SELECT diasa, Mflfewi, Diriginte FROM Clase WHERE (Clasa = Clasa)

( Query Builder... j

5.

Se descc re : s.oc_ Q u a y B u ild e r. Acesta este un instrument util, pentru c


v perrr :e s ditectaci re diagrama Clase cmpurile pe care le nserai, iar
codul se ce-ereaz 3
Evident, putei edita i manual:

Partea a III - a. Baze de date

340

>

* (All Columns)
1+ Clasa
E i NrElevi
i+ j Diriginte
V
>

<

Column

New Value

Clasa

Clasa

NrElevi

NrElevi

~
ft
v

INSERT INTO Clase


(Clasa, NrElevi, Diriginte)
VALUES (Clasa, NrElevi, Diriginte)
p

-r

i __ __j "

Execute Query

:.

OK

Cancel

Ai remarcat modul n care se specific valorile rndului care se insereaz? De


fapt, 0Clasa, @NrElevi, @Diriginte reprezint numele parametrilor
metodei insert ()
care se va genera, ca membr a clasei
ClaseTableAdapter. n dialogul urmtor, setai numele metodei :
InsertClasa.
6.

Ca s introducei datele, creai o nou form. n Solution Explorer, click


dreapta pe numele proiectului, selectai A d d , apoi W in d o w s F o rm ... Numii
forma FormlnsertClasa:

7.

Din Toolbox, selectai componenta ClaseTableAdapter i plasai-o pe


suprafaa formei. n d e s ig n e r tray, apare referina claseTableAdapterl.
Facem acest lucru deoarece avem nevoie de adaptor pentru apelul insert (),

Capitolul 13. Relaii ntre tabele


dar
n
clasa
FormlnsertClasa
nu
claseTableAdapter, definit n clasa Forml.
8.

este

341

vizibil

adaptorul

Acionai dublu click pe butonul A d a u g . n metoda de tratare, scriei:


private void buttonl_Click(object sender, EventArgs e)

{
if (textBoxl.Text == "" || textBox2.Text == "" ||
textBox3.Text == "")

{
MessageBox.Show(
"Nu ati completat toate cmpurile!");
return;

}
claseTableAdapter1.Insert(textBoxl.Text,
int.Parse(textBox2.Text), textBox3.Text);
Close () ;

}
9.

Pe forma F o r m l, acionai dublu click pe opiunea A d u g cla s a . n metoda de


tratare scriei:
private void adaugaClasaToolStripMenuItem_Click(
object sender, EventArgs e)

{
// Instaniem forma FormlnsertClasa
FormlnsertClasa fInsCl = new FormlnsertClasa();
fInsCl.ShowDialog();
// Acum n baza de date avem un rnd nou
// ncrcm datele din baza de date n dataset
claseTableAdapter.Fill(scoalaDataSet.Clase);

}
10.

Compilai i rulai cu F5.

La rulare, introducei clase cu nume diferite, cu ajutorul opiunii A d u g c la s a :

Clase

Elevi

Rapoarte
NrElevi

IdElev

Diriginte
Popescu

Nume

ForrnlnsertC,

Vernescu
Colcei
Nr Elevi:
Diriginte: iDanciu Elena

Partea a III - a. Baze de date

342

Generarea procedurilor stocate


O procedur stocat (stored procedure) consist dintr-un grup de comenzi
SQL adunate sub un nume. Comenzile au fost anterior create i stocate pe
serverul de baze de date. Procedurile stocate sunt compilate o singur dat i
apoi aplicaia client le poate apela de cte ori este necesar. Sunt foarte rapide.
Accept date prin parametri de intrare. Datele sunt specificate n timpul execuiei.
n aplicaia anterioar, nainte de apelul insert (), am verificat dac toate
cmpurile sunt completate. Nu am verificat alte dou aspecte importante: dac
valoarea introdus pentru Nr Elevi este sau nu un numr ntreg i dac clasa
introdus nu exist deja n baza de date. n ambele situaii, se arunc excepii.
Prima problem se rezolv relativ uor, cu ajutorul metodei
int. TryParse (string, int), care ncearc s converteasc primul argument
n numr, iar dac nu reuete retureaz false.
A doua problem necesit interogarea bazei de date (un SELECT) pentru a
vedea dac clasa nu exist deja n baza de date. Pentru aceasta putem genera o
nou metod n clasa adaptorului, ns vom prefera s crem o procedur stocat,
pentru a vedea cum se procedeaz. Urmai indicaile :
E

n Dataset Designer, selectai diagrama Clase i facei click dreapta pe


adaptorul ClaseTableAdapter. Selectai Add Query, apoi n dialogul care
apare, selectai Create new stored procedure:
TableAdapter Query Configuration Wizard
C hoose a Com mand Type
TableAdapter query uses SQL statements or a stored procedure

How should the TableAdapter query access the database?


O Use SQL statements
Specify a SELECT statement to load data.

Create new stored procedure


Specify a SELECT statement, and the wizard will generate a new stored procedure to select records.

O Use existing stored procedure

n dialogul urmtor, alegei SELECT wich returns a single value:


TableAdapter Query Configuration Wizard
C hoose a Q u e ry Type
Choose the type of query to be generated

What type of SQL query would you like to use?


O SELECT which returns rows
Returns one or many rows or columns.

SELECT which returns a single value


Returns a single value (for example. Sum, Count, or any other aggregate function)

O UPDATE

Capitolul 13. Relaii ntre tabele

343

n dialogul urmtor, editai interogarea astfel:


f

G e n e ra te th e s to r e d p ro c e d u re
The SELECT statement will be used to create a stored procedure that will be called by
the query.

f ? - :A

Type your SQL statement or use the Query Builder to construct it. What data should be loaded into the table?

What data should the table load?


SELECT COUNTH FROM Clase
WHERE Clasa = @Clasa|

Am adugat clauza WHERE. Parametrul @Clasa devine n mod automat


parametru de intrare al procedurii stocate, c o u n t () returneaz numrul de
rnduri care conin clasa gciasa.

Apsai butonul N e x t i stabilii numele procedurii stocate MaiExistaClasa.


Putei s pstrai n dialogul urmtor acelai nume i pentru funcia care
apeleaz procedura stocat. Apsai butonul F in ish .

Dac vrei s vedei sau s editai codul procedurii stocate, mergei n


Database Explorer, expandai itemul S to re d P ro c e d u re s i dublu click pe
procedura MaiExistciasa:
dbo.M aEKista...LA\SCOALA.M DF)

start Page

Forml.es

Forml.cs [Df

JiLTER PROCEDURE dbo.MaiExistaClasa


(
BClasa nvarchar(50)

J
AS

SET NOCOUNT ON;


SELECT COUNT(*) FROM Clase
WHERE Clasa = SClas^

Acum suntem n msur s completm codul metodei buttonl_Click:


private void buttonl_Click(object sender, EventArgs e)

{
if (textBoxl.Text == "" || textBox2.Text == "" ||
textBox3.Text == "")

{
MessageBox.Show(
"Nu ati completat toate cmpurile!");
return;

Partea a III - a. Baze de date

344

i n t i n t r e g = O;
i f ( ! i n t . T ry P a rs e (te x tB o x 2 . T e x t,

o u t in tr e g ) )

{
M essa ge B o x. Show (
"N r e le v i tr e b u ie
re tu rn ;

s f i e

num r i n t r e g ! " ) ;

}
i f (

( in t ) c la s e T a b le A d a p t e r l. M a iE x is t a C la s a (
te x tB o x l.T e x t )

= = 1)

{
M e s s a g e B o x . S h o w ( " C la s a e x i s t a
re tu rn ;

d e ja !" ) ;

}
c la s e T a b le A d a p te r l. I n s e r t ( t e x t B o x l. T e x t,
i n t . P a rs e (te x tB o x 2 . T e x t ) , te x tB o x 3 . T e x t ) ;
C lo s e ( ) ;

IM PO R TA N T!
M e to d a insert, ca d e a ltfe l to a te m e to d e le c a re c o n in in te ro g ri, p o t s
a ru n c e e xce p ii. D e a ce e a , tre b u ie in c lu s e n b lo c u ri
N o i n u a m f c u t-o aici, p e n tru cla rita te .

try-catch.

Tem de lucru:
Im plem entai facilitatea de adugare a unui nou e lev n baza de date la
selectarea opiunii A d u g e le v din meniul Elevi. Trebuie s creeai o funcie
suplim entar care interogheaz baza de date determ innd dac valoarea pe care
o introduce utilizatorul pentru cm pul C la s a exist sau nu n tabela C la s e .

tergerea unei nregistrri din baza de date


Pentru a terge o clas din baza de date, este nevoie de o funcie care
ncapsuleaz com anda SQL DELETE. Procedm astfel:

1. A dugai o nou form cu num ele FormDeleteClasa:

WB

Clasa care se terge:

terge

Capitolul 13.
2.

Relaii ntre tabele

345

Din Toolbox, selectai componenta ClaseTableAdapter i plasai-o pe


suprafaa formei FormDeleteClasa. n designer tray, apare referina
claseTableAdapterl.

11. n S o lu tio n E x p lo r e r , acionai dublu click pe itemul ScoalaDataSet.xsd. n


Dataset Designer, pe diagrama tabelei Clasa, click dreapta pe
ClaseTableAdapter. Selectai Add Query...
12. n primul dialog, selectai Use SQL statements. Apsai Next. n al doilea
dialog, selectai DELETE. n Query Builder, editai interogarea astfel:
DELETE FROM Clase
WHERE
(Clasa = 0Original_Clasa)
@Original_Clasa este numele parametrului de intrare al funciei care se
genereaz.
13. Stabilii n urmtorul dialog, numele funciei: DeleteClasa.
14. Pe Forml, n View Designer, efectuai dublu click pe opiunea stergeClasa.
n corpul handler-ului introducei:
private void stergeClasaToolStripMenuItem_Click(
object sender, EventArgs e)

(
FormDeleteClasa fDelCl = new FormDeleteClasa();
fDelCl.ShowDialog();
// Rencrcm cele dou tabele din dataset
// cu datele modificate din baza de date
ClaseTableAdapter.Fill(scoalaDataSet.Clase);
eleviTableAdapter.Fill(scoalaDataSet.Elevi);

}
15. Acionai dublu click pe butonul terge, al formei FormDeleteElev. n metoda
de tratare introducei:
private void buttonl_Click(object sender, EventArgs e)

{
claseTableAdapterl.DeleteClasa(textBoxl.Text);
Close () ;

}
16. Rulai cu F5.
La execuie vei constata c atunci cnd tergei o clas, se terg i toate rndurile
orfane din tabela Elevi, conform regulii de tergere n cascad pe care am impus-o
pentru meninerea integritii datelor la crearea constrngerii de cheie strin.

346

Partea a III - a. Baze de date

Tem de lucru:
Implementai facilitatea de tergere a unui elev, la selectarea opiunii terge

elev din meniul Elevi. Elevul va fi cutat dup cmpul IdElev.

Vederile unei baze de date (Views)


Un V ie w este o tabel virtual, compus din rezultatul unei interogri.
Vederile se creaz dinamic. Includ date selectate din una sau mai multe tabele ale
bazei de date, i eventual date rezultate n urma unui calcul.
Modificarea datelor n tabele duce automat la modificarea datelor afiate n
vederi. Au avantajul c nu ocup spaiu fizic pe disc.
Vederile se folosesc frecvent atunci cnd se dorete afiarea rezultatului
j o i n -ului tabelelor i cnd nu se dorete modificarea datelor ci doar vizualizarea lor.
Ne vom lmuri n cele ce urmeaz.

Aplicaia co ala - adugarea vederilor


Vedere cu date selectate dintr-o singur tabel
S presupunem c vrem s vedem o tabel care conine numai coloanele
Diriginte i Clasa din tabela Clase. Nu este cazul s definim o tabel nou.
Construim o vedere care afieaz doar datele din aceste coloane. Procedai astfel:
1.

Vederea va fi afiat ntr-un grid. Avem nevoie de o form nou. Adugai o


form nou proiectului, acionnd click dreapta n S o lu t io n E x p lo r e r , alegei
Add i selectai Windows Form... Salvai clasa formei cu numele
FormViewDirigClasa.

2.

Din Toolbox alegei un control DataGridView i plasai-l pe suprafaa formei.

3.

n fereastra D a ta b a s e E x p lo r e r , click dreapta pe itemul Views, apoi selectai

Add New View.

4. n dialogul Add Table, selectai tabela Clase, apsai Add, apoi click pe
butonul Close.
5.

n View Designer, selectai cmpul Diriginte pe diagrama Clase, apoi


cmpul Clasa. Interogarea SELECT se genereaz n mod automat:

Capitolul 13. Relaii ntre tabele


dbo.View3: Vi...A\SCOALA.MDF)*
Clase

dbo.View2: Vi... A\SCOALA,MDF)*

347

* (All Columns)
j v . Clasa
NrElevi
v Diriginte

< *4
Table

Output

Diriginte

Clase

Clasa

Clase

Column

Alias

<

0
,v

SELECT
FROM

Sort Type

pf

Diriginte., Clasa
dbo. Clase

6.

Apsai butonul S a ve , apoi introducei numele vederii: viewDirigClase.

7.

Avem o vedere, dar aceasta nu este nc integrat n d a ta s e t. Pentru aceasta,


deschidei DataSet Designer cu dublu click pe itemul ScoalaDataSet.xsd
n Solution Explorer. Din panoul Database Explorer, tragei cu ajutorul
mouse-ului vederea pe suprafaa designerului. Obinei:

Database Explorer

ScoalaDataSet.xsd* ; " dbo.yiewpirjg...LA\SCOALA.MDF)

dbo.View2i Vi,..A\SCOALA,MDF)*

|J Data Connections
Jjr, coala.mdf
SI- J j i Database Diagram^
& C l Tables
dti- JJJ Clase
$i

13 Elevi

B- C J Views
S ' g l i ViewDirigClase I

[3

Diriginte

JO Clasa
-

Stored Procedures

S' C j

Functions

51 L_i Synonyms
$ Types
JJJ Assemblies

8.

n Solution Explorer, dublu click pe forma vederii, pentru a deschide F o rm


D e s ig n e r. Din fereastra Data Sources, tragei vederea pe suprafaa formei.

9.

Acionai dublu click pe opiunea D irig in ti-c la s e din meniul R a p o a rte , aflat pe
F o r m l. n corpul metodei de tratare scriei:

348

Partea a III - a. Baze de date


private void dirigintiClaseToolStripMenuItem_Click(
object sender, EventArgs e)
{
FormClaseDirig fCIDir = new FormClaseDirig();
fCIDir.ShowDialog();

10. Facei Build i rulai cu F5.


La rulare, n momentul n care selectai opiunea D irig in ti-C la s e , obinei:

Vedere cu date selectate din dou tabele


Aa cum am spus, tabela temporar rezultat n urma unui JOIN poate fi
afiat ntr-un View.
Ne ntoarcem la aplicaia coala. S presupunem ni se cere media pe clase.
Construim o vedere care afieaz clasa, dirigintele i media clasei. Avem nevoie
de informaii din ambele tabele, deoarece Diriginte este cmp n tabela Clase,
iar Media (unui elev) este cmp n tabela Elev. Reamintim c ntre cele dou
tabele exist o constrngere de cheie strin, clasa este cheie strin n tabela
Elev. Procedai ca mai jos:

1. Adugai o form nou proiectului, cu numele FormViewMediaClase.


2.

Din Toolbox alegei un control DataGridView i plasai-l pe suprafaa formei.

3. n fereastra Database Explorer, click dreapta pe itemul Views, apoi selectai


A d d N e w View.

4.

n dialogul A d d T able, Clase, adugai pe rnd ambele tabele cu ajutorul


butonului A d d , apoi nchidei cu butonul C lose.

5.

n V ie w D e s ig n e r, selectnd opiunile din figura de mai jos, vei obine


interogarea necesar:

Capitolul 13. Relaii ntre tabele

.......................

.... .
<
j * (A ll C o lu m n s)

U * (AN C o lu m n s )
0

C la s a

349

[* =

= 4

-1

[jK fia v
|__ |N um e

N rE levi
P I D irig in te

[< -

L i M e d ia

[ j C lasa

:<
T a ble

O u tp u t

C lasa

C lase

G ro u p By

D irig in te

C lase

G ro u p By

E levi

C olum n

SELECT
FROM

M edia

Alias

M e diaC lasei

S , ,.

S , ,,

G ro u p By

F ilte r

| A vg

d b o ,C la s e ,C la s a , d b o .C la s e .D irig in te j A V G (d b o ,E le v i.M e d ia ) AS M e d ia C la se i
d b o , C lase IN N E R JO IN
d b o ,E le v i ON d b o ,C la s e ,C la s a = d b o ,E le v i,C la s a

GROUP BY d b o .C la s e .C la s a , d b o ,C la s e .D irig in te

Evident, putei s completai i manual codul SQL. Observai c se face un


J O IN IN T E R IO R care returneaz cte un rnd pentru fiecare clas. Media

clasei se calculeaz cu funcia

avg

().

6.

Apsai butonul S a v e , apoi introducei numele vederii: viewMediaClase.

7.

Vederea trebuie inserat n d a ta se t. Deschidei DataSet Designer cu dublu


click pe itemul ScoalaDataSet.xsd n Solution Explorer. Din panoul
Database Explorer, tragei cu ajutorul mouse-ului vederea pe suprafaa
designerului.

11. n Solution Explorer, dublu click pe forma vederii, pentru a deschide F o rm


D e s ig n e r. Din fereastra Data Sources, tragei noua vedere pe suprafaa formei
FormViewMediaClase.
12. Acionai dublu click pe opiunea M e d ia p e cla s e din meniul R a p o a rte , aflat pe
F o r m l. In corpul metodei de tratare scriei:
private void mediaPeClasaToolStripMenuItem_Click(
object sender, EventArgs e)
f
// Instaniem forma i o afim
FormViewMediaClase fV = new FormViewMediaClase();
fV.ShowDialog();

}
8.

Rulai cu F5.

350

Partea a III - a. Baze de date

La execuie, dac selectai opiunea de meniu Media pe clase, obinei:

Probleme propuse
1. Adugai aplicaiei coala un View care afieaz pe trei coloane: numele
diriginilor care au elevi cu medii peste o valoare introdus de la tastatur,
numrul de elevi din fiecare clas care ndeplinesc aceast restricie i clasa.
2.

Creai o aplicaie care ntreine o baz de date cu numele F irm a . Baza de date
conine dou tabele: Clieni si Comenzi. Tabelele vor defini cel puin
urmtoarele coloane: Clieni: (IDCIient, Nume, Prenume, Telefon) si Comenzi:
(IDCIient, Data, ValoareComanda). Aplicaia va implementa operaii de
adugare de Clieni si de Comenzi. Va permite de asemenea afiarea tuturor
clienilor, iar pentru fiecare client, se va afia valoarea total a comenzilor
sale.

3.

Implementai o aplicaie care s permit eliminarea dintr-o baz de date a


tuturor produselor care au preul cuprins ntre dou limite introduse de la
tastatur. Dac n baza de date nu exist nici o nregistrare cu proprietatea de
mai sus, s se afieze un mesaj. Pentru un produs se memoreaz: codul,
denumirea, preul, data recepiei.

4.

S se realizeze o aplicaie care s permit manipularea unei baze de date care


conine un tabel cu structura: nume medicament, compensat sau nu, procent
compensare si pre ntreg. Pentru aceast tabel s se poate actualiza preul
unui medicament localizat prin nume. S se realizeze o list cu medicamentele
care nu beneficiaz de compensare.

Bibliografie
[1]

Ecma Technical Committee 39 Task Group


C# L a n g u a g e S p e c ific a tio n 4-th Edition, june 2006

[2]
[3]

Jesse Liberty.

P ro g ra m m in g C#. 2-nd Edition. OReilly 2002.

Andrew Troelsen .

P ro C# 2 0 0 8 a n d th e .N e t 3 .5 P la tfo rm . 4-th Edition.

Apress 2008.

[4]

Microsoft MSDN Express Library 2008

[5]

Trey Nash.

[6]

Stanley Lippman. C#

A c c e le ra te d C # 2 00 8. Apress 2008
P rim e r: A P ra c tic a l A p p ro a c h . Pearson Education

Inc. 2003

[7]

Herbert Schildt. C# 2 .0

[8]

Donis Marshall.

The C o m p le te R e fe re n c e . 2-nd Edition

P ro g ra m m in g M ic ro s o ft V is u a l C# 2 0 0 5 : T he L a n g u a g e .

Microsoft Press 2006.

[9]

Rob Harrop.

[10]

James Huddleston, Ranga Raghuram.

E ffe c tiv e D ata A c c e s s in C#. Wrox Press 200


B e g in n in g C# 2 0 0 5 D a ta b a s e s

fro m N o v ic e to P ro fe s s io n a l. Apress 2006

[11]

Paul Kimmel.

[12]

John Sharp, Jon Jagger.

A d v a n c e d C# P ro g ra m m in g . McGraw Hill/Osborne 2002


M ic ro s o ft V is u a l C # .N E T S te p b y S tep.

Microsoft Press 2003

[13]

F. Scott Barker. V isu a l C # 2 0 0 5 E x p re s s E d itio n S ta rte r Kit. Wiley


Publishing Inc. 2005

[14]

Matthew MacDonald.

P ro

.N E T

2 .0

W in d o w s

F o rm s

and

C u s to m

C o n tro ls . Apress, 2006.

[15]

John Paul Mueller.


2002

[16]

Daniel Solis.

[17]

Matthew MacDonald. Pro WPF in C# 2008: Windows Presentation


Foundation with .NET 3.5, Second Edition. Apress 2008

[18]

Peter Wright. B e g in n in g V is u a l C# 2 0 0 5 E x p re s s E d itio n F ro m N o v ic e to


P ro fe s s io n a l. Apress 2006.

[19]

V is u a l C# .N E T D e v e lo p e r's H a n d b o o k . SYBEX Inc.

Illu s tra te d C# 2 0 0 8 . Apress 2008.

MAHESH CHAND.

A P ro g ra m m e rs G u id e to A D O .N E T in C#. Apress

2003.

[20]

Mickey Williams.

M ic ro s o ft V is u a l C # .N E T . Microsoft Corporation 2002