Documente Academic
Documente Profesional
Documente Cultură
Net Framework
Net Framework
.NET
Presented by developerWorks, your source for great tutorials
ibm.com/developerWorks
Table of Contents
If you're viewing this document online, you can click any of the topics below to link directly to that section.
2
3
12
35
61
80
98
122
140
142
158
177
187
202
203
Page 1 of 203
ibm.com/developerWorks
Despre autor...
Gabriel NEGARA
Page 2 of 203
ibm.com/developerWorks
Page 3 of 203
ibm.com/developerWorks
Page 4 of 203
ibm.com/developerWorks
Descriere
System
System.Collections
System.ComponentModel
System.Data
Page 5 of 203
ibm.com/developerWorks
System.Data.OleDb
System.Data.SQLClient
System.Drawing
System.IO
System.Math
System.Reflection
System.Security
System.Threading
System.Windows.Forms
ibm.com/developerWorks
3. Clase si structuri
Clase versus Structuri
La prima vedere, clasele si structurile par foarte asemanatoare. Ambele pot contine
membri, cum ar fi campuri si metode, ambele necesita un constructor pentru a se crea
o noua instanta si, ca toate tipurile din .NET Framework, ambele sunt derivate din
Object. Diferenta dintre clase si structuri este accea ca structurile sunt tipuri valoare,
iar clasele sunt tipuri referinta. La nivel de alocare, aceasta inseamna ca datele de
instantiere pentru clase sunt alocate pe heap, in timp ce pentru structuri acestea sunt
alocate pe stack. Acesul la stack a fost proiectat in asa fel incat sa fie facil si rapid, dar
stocarea unor date de dimensiuni mari pe stack pot conduce la diminuari ale
performantei aplicatiei.
in termeni practici, structurile reprezinta varianta optima pentru obiecte de dimensiuni
mici si pentru care se definesc putine instante, persistente pentru perioade relativ mici
in memorie. Clasele sunt optim folosite pentru obiecte de dimensiuni mai mari si pentru
care de definesc un numar mai mare de instante, cu posibilitatea mentinerii lor in
memorie pentru perioade mari de timp.
Sinteza
Tipurile definite de uzilizator includ clase si structuri. Ambele pot avea membri campuri, proprietati, metode sau evenimente. Clasele sunt tipuri referinta iar
structurile sunt tipuri valoare.
Cuvantul rezervat class este folosit in Visual C# pentru a defini clase. Structurile sunt
create utilizand cuvantul cheie struct. Atat clasele, cat si structurile pot contine tipuri
imbricate.
Tipurile definite de utilizator sunt instantiate in acceasi maniera ca tipurile predefite,
exceptand faptul ca atat tipurile caloare cat si tipurile referinta trebuie sa foloseasca
cuvantul cheie new pentru instantiere.
Page 7 of 203
ibm.com/developerWorks
Metodele pot avea parametri, care reprezinta valori solicitate de metoda. Parametrii
sunt transmisi, implicit, prin valoare. Transmiterea parametrilor prin referinta se face
in Visual C# folosind cuvantul rezervat ref. Visual C# permite specificarea
parametrilor de iesire pentru o anumita metoda.
Constructorul este prima metoda apelata la instantierea unui tip. Constructorul
furnizeaza o modalitate de a seta valori implicite ale datelor sau de a executa alte
operatii necesare, inainte ca obiectul sa fie disponibil pentru operatii ulterioare.
Destructorii sunt apelati exact inainte ca un obiect sa fie distrus si pot fi folositi pentru
a executa cod de clean-up, de dealocare de memorie. Pentru ca dealocarea
memoriei alocate obiectelor este controlata de common language runtime,
utilizatorul nu poate controla momentul apelarii destructorului.
public
private
internal
protected
protected-internal
ibm.com/developerWorks
ele nu vor avea niciodata un nivel de acces mai mare decat cel al tipului parinte.
Membrii de tip static apartin tipului si nu unei instante anume a tipului respectiv. Ei
pot fi accesati fara a crea o instanta a tipului si sunt accesati folosind numele tipului.
6. Garbage Collection
.NET Framework executa managementul automat al memoriei, ceea ce inseamna ca
atunci cand un obiect nu mai este folosit, .NET Framework elibereaza automat
memoria folosita de acel obiect. Acest proces se numeste garbage collection.
Sa consideram urmatorul exemplu:
void GarbageCollectionExample()
{
TipObiect obiect = new TipObiect();
}
La sfarsitul acestei proceduri, variabila obiect iese domeniul sau de vizibilitate, iar
obiectul la care face referire nu mai este referentiat de nici o variabila din cadrul
aplicatiei. Garbage collector-ul gestioneaza in background arborele de referinte si
identifica obiectele catre care nu se mai face referinta. Cand gaseste un astfel de
obiect, cum ar fi TipObiect din exemplul anterior, il sterge si solicita eliberarea zonei de
memorie ocpate de obiectul respectiv. Pentru ca garbage collector-ul ruleaza continuu,
utilizatorul nu trebuie sa distruga explicit obiectele la care nu se mai face referire in
program de la un anumit moment.
Garbage collector-ul reprezinta, de fapt, un fir de executie de prioritate scazuta, in
conditii normale. El intervine in executia programului cand timpul procesor nu este
consumat de sarcini mai importante. Totusi, atunci cand zonele de memorie libera se
imputineaza semnificativ, firul de executie asociat garbage collector-ului creste in
prioritate. Memoria utilizata de obiecte care nu mai sunt referentiate in program este
solicitata intr-o maniera mai insistenta, pana cand se elibereaza o zona suficienta de
memoria, caz in care firul de executie al garbage collector-ului trece la o prioritate
scazuta.
Aceasta abordare non-deterministica de eliberare a memoriei are ca scop maximizarea
performantei aplicatiei si furnizeaza un mediu de aplicatii mai putin predispus la
actiunea bug-urilor (less bug-prone ). Exista, insa, un cost. Datorita mecanismului prin
care opereza garbage collector-ul, utilizatorul nu poate sti momentul in care un obiect
va fi dealocat. Deci, nu exista control asupra momentului apelarii destructorului clasei
Visual C# in cauza. Aceste metode ar trebui sa nu contina cod care se proiecteaza a fi
executat la un anumit moment. in schimb, pot fi scrise clase care utlizeaza o cantitate
importanta de resurse si care contin o metoda Dispose() pentru eliberarea explicita a
acestor resurse, atunci cand o instanta a acestei clase nu mai este necesara in
program.
Referinte circulare
Page 9 of 203
ibm.com/developerWorks
Page 10 of 203
ibm.com/developerWorks
Page 11 of 203
ibm.com/developerWorks
tipuri intregi
tipuri flotante
tipul Boolean
tipul Char
Page 12 of 203
ibm.com/developerWorks
Tip
Reprezentare C#
Descriere
Domeniu
System.Byte
byte
de la 0 la 255
System.Int16
short
de la -32768 la
32767
System.Int32
int
de la -2 la 31 la 2
la 31 - 1
System.Int64
long
de la -2 la 63 la 2
la 63 - 1
System.SByte sbyte
de la -128 la 127
System.UInt16 ushort
de la 0 la 65535
System.UInt32 uint
de la 0 to 2 la 32
-1
System.UInt64 ulong
de la 0 to 2 la 64
-1
Reprezentare C#
Descriere
System.Single
float
System.Double
double
System.Decimal
decimal
Page 13 of 203
ibm.com/developerWorks
System.Boolean
System.Char
System.String
System.Object
System.Boolean
Tipul System.Boolean este folosit pentru a reprezenta o valoare care este fie true, fie
false. In C#, o variabila booleana este desemnata prin intermediul tipului bool, cu
valorile posibile true si false.
System.Char
Tipul System.Char reprezinta un caracter Unicode pe 16 biti. In C#, o variabila de tip
char (tipul C# asociat) poate fi definita prin specificarea explicita a unui caracter intre
apostroafe: char caracter;
caracter = 't';
sau atribuind valoarea numerica a codului Unicode al caracterului variabilei de tip char,
folosind o valoare hexazecimala din 4 cifre, corespunzatoare: char caracter;
caracter = '\u01fe';
System.String
Tipul System.String este un tip referinta care reprezinta o succesiune de date de tip
Char. Cu alte cuvinte, un string poate desemna un cuvant, un paragraf, un cod sau
orice alta succesiune de caractere. Tipul C# asociat este desemnat de cuvantul
rezervat string.
Exemplu de utilizare: string sir;
sir = "Acesta este un string.";
System.Object
Tipul Object este parintele tuturor tipurilor din .NET Framework. Orice tip, fie valoare,
fie referinta, este derivat din System.Object. Tipul C# asociat - object. Unei variabile
object i se poate asocia orice valoare sau obiect: object obj;
obj = 233;
obj = new System.Collections.ArrayList();
!
Daca un obiect de un anumit tip este stocat intr-o variabila object, trebuie reconvertit
explicit la acel tip pentru a accesa intreaga sa functionalitate.
Page 14 of 203
ibm.com/developerWorks
Tipuri de conversii
Datele pot convertite in doua feluri: implicit, caz in care conversia este executata
automat, si explicit - conversie executata de utilizator.
Conversii implicite
Sunt conversii care se executa atunci cand nu exista riscul pierderilor de date. De
exemplu: int un_short = 100;
long un_long;
un_long = un_short;
Daca un tip poate fi convertit implicit la un alt tip, atunci primul tip poate fi utilizat
oriunde in program unde se solicita cel de-al doilea tip, fara a folosi o sintaxa speciala.
De exemplu: // functia prelucare_long
// are un parametru de tip long
int x = 100; // conversie implicita de la int la long
// efectuata la apelul functiei
prelucare_long(I);
Tabelul urmator ilustreaza conversiile implicite permise in C#:
De la
La
byte
short
int
long
float
double
char
sbyte
ushort
uint
ulong
Conversii explicite
In cazul unei conversii in care tipurile nu pot fi convertite implicit, trebuie aplicata o
conversie explicita. Aceasta conversie se mai numeste cast. In C#, conversiile explicite
necesita folosirea unei sintaxe speciale. Exemplu:
int un_int = 100;
Page 15 of 203
ibm.com/developerWorks
short un_short;
un_short = (short)un_int;
! Conversiile explicite pot fi riscante. In exemplul anterior, conversia s-a efectuat fara
nici un fel de problema pentru ca atat o variabila int, cat si una de tip short poate retine
valoarea 100. Sa consideram acum urmatorul exemplu:
int un_alt_int = 80000;
short un_alt_short;
un_alt_short = (short)un_alt_int;
Codul acestui exemplu nu va furniza eroare de compilare sau la run-time. Totusi,
examinand valoarea lui short, aceasta nu va fi cea dorita, deoarece valoarea maxima a
domeniului tipului short este mai mica decat valoarea la care se incearca conversia.
! Deoarece conversiile explicite sunt adesea riscante, este indicata folosirea lor numai
in cazuri absolut necesare, implementand un sistem adecvat de tratare a conversiilor
nereusite si a tuturor exceptiilor care ar putea fi aruncate. (vezi cursul 5).
Functionalitati asociate tipurilor de date Toate tipurile de date au o functionalitate
implicita (built-in ). Acestea suporta urmatoarele patru metode:
? Din cele prezentate mai sus, reiese faptul ca tipurile de date ocupa un relativ mic de
memorie. Totusi, cum este posibil ca fiecare tip sa implementeze aceste metode?
Raspunsul este dat in cele ce urmeaza.
Boxing Boxing reprezinta conversia implicita a tipurilor valoare la tipuri referinta. Toate
clasele si tipurile sunt derivate din Object, fiecare din cele patru metode amintite fiind
membre ale clasei Object. Deoarece toate clasele sunt derivate din Object, fiecare
clasa poate fi convertita implicit la acest tip. La apelul uneia dintre cele patru metode,
Common Language Runtime creaza o referinta temporara variabila de tip valoare
declarata de utilizator si se permite tratarea acesteia ca fiind de tip referinta.
Boxing explicit(manual) - prin atribuirea variabilei detip valoare unei variabile de tip
Object. Exemplu:
short s = 10;
object O;
O = s;
Unboxing reprezinta conversia unei variabile boxed la un tip valoare. Se realizeaza
prin conversia explicita a obiectului la tipul dorit. Se poate executa unboxing numai
pentru obiectele care au fost supuse operatiei de boxing.
Metoda Parse
Page 16 of 203
ibm.com/developerWorks
Descriere
String.Insert
String.PadLeft,
String.PadRight
String.Remove
String.Replace
String.Insert
String.Split
String.Substring
String.ToCharArray
String.ToLower,
String.ToUpper
String.TrimEnd,
String.TrimStart, String.Trim
Descriere
String.Compare
String.Concat
String.Format
String.Join
Page 17 of 203
ibm.com/developerWorks
Sinteza
.NET Framework furnizeaza un sistem robust, puternic tipizat de tipuri de date.
Principalele tipuri - intregi, flotante, boolean, caracter si string.
Exista doua tipuri de conversii - implicite, executate automat de CLR, atunci cand nu
exista riscul pierderii de date si explicite, efectuate explicit prin scriere de cod,
programatorul trebuind sa analizeze ci atentie cazurile care ar putea conduce la
erori.
Boxing - macanismul care permite tratarea tipurilor valoare ca tipuri referinta.
Unboxing - converteste un tip referinta asupra caruia s-a efectuat anterior boxing
catre un tip valoare.
Tipurile .NET contin functionalitate built-in specifica tipului. Metoda Parse este
implementata de toate tipurile valoare, fiind utila pentru conversia string-uriloe la
tipuri valoare. Clasa String contine un set de functii care faciliteaza manipularea
string-urilor.
Page 18 of 203
ibm.com/developerWorks
Page 19 of 203
ibm.com/developerWorks
ibm.com/developerWorks
//declarare
short[] array_shorts;
// initializare
array_shorts = new short[20];
Un tablou poate fi redefinit, modificandu-i dimensiunea la run-time. Exemplu:
// declarare si initializare
int[] intregi = new int[20];
// reinitializare
intregi = new int[45];
In exemplul anterior, datele continute de tablou sunt pierdute la reinitializare. Nu exista
nici o modalitate de salvare a datelor la reinitializare (excluzand o varianta manuala).
La crearea unui tablou cu elemente de tip referinta, declararea si initializarea tabloului
nu conduc la umplerea tabloului cu membri de tipul respectiv. De fapt, se creaza un
tablou de referinte null care pointeaza la acel tip. Pentru a completa tabloul cu membrii,
trebuie asignata fiecare variabila la un obiect. De exemplu:
// se creaza un tablou de obiecte
TipObiect[] obiecte = new TipObiect[10];
// se asigneaza elementului obiecte[0] un nou obiect de tip
TipObiect
obiecte[0] = new TipObiect();
// asigneaza elementului obiecte[1] un obiect existent
TipObiect un_obiect = new TipObiect();
obiecte[1] = un_obiect;
// se atribuie celorlalte elemente cate un nou obiect
for (int contor = 2; contor < 10; contor++)
{
obiecte[contor] = new TipObiect();
}
Tablouri multidimensionale
Tablourile prezentate pana acum sunt liniare, adica, tablouri cu o singura dimensiune.
Exista in .NET Framework doua tipuri de tablouri multidimensionale: tablouri
rectangulare si tablouri jagged.
Tablouri rectangulare
Sunt tablouri in care fiecare membru al fiecarei dimensiuni este extins in fiecare alta
Dezvoltare de aplicatii in Visual Studio .NET
Page 21 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Colectiile sunt utile pentru gestionarea grupurilor de elemente create dinamic la run
time. De exemplu, ne putem imagina o colectie in care un element contine informatii
despre un salariat al unei institutii. Creand o colectie de obiecte de tip Salariat, va fi
posibila accesarea obiectelor, iterarea acestora, adaugarea de noi obiecte sau
eliminarea obiectelor care devin irelevante.
Clasa ArrayList
System.Collections.ArrayList - confera functionalitati specifice de colectie utile intr-o
serie intreaga de situatii. Aceasta clasa permite adaugarea si eliminarea dinamica de
elemente din lista. Elementele sunt accesate prin index Exemplu:
System.Collections.ArrayList lista = new
System.Collections.ArrayList();
Metoda Add
Dupa instantiere, pot fi adaugate elemente intr-un ArrayList utilizand metoda Add:
TipObiect obiect = new TipObiect();
lista.Add(obiect);
!
Orice lista de tip ArrayList este o colectie zero-based . Primul obiect introdus in lista are
indexul zero, elementele adaugate ulterior primind indexul imediat urmator elementului
anterior.
In C#, indexatorii sunt folositi pentru accesarea elementelor colectiilor, utilizand o
sintaxa similara tablourilor. Exemplu:
object obj;
obj = lista[0];
!
Toate referintele dintr-o colectie sunt de tipul object. Se impune, deci, folosirea
conversiilor explicite, pentru a obtine un element avand acelasi tip ca tipul elementului
din lista, returnat de indexator:
TipObiect obj;
obj = (TipObiect)listaObiecte[1];
Metodele Remove si RemoveAt
Remove - elimina obiectul a carui referinta este primita ca parametru din colectie
RemoveAt - elimina din colectie elementul de la indexul a carui valoare este primita
ca parametru
Exemplu:
Page 23 of 203
ibm.com/developerWorks
Descriere
BitArray
Queue
SortedList
Page 24 of 203
Stack
ibm.com/developerWorks
Page 25 of 203
ibm.com/developerWorks
}
Sinteza:
Constante si enumerari (const si enum). Constantele pot avea orice tip. Enumerarile
trebuie sa aiba un tip numeric integral.
Tablourile pot fi unidimensionale sau multidimensionale. Tablourile
multidimensionale pot fi rectangulare sau jagged.
Colectiile permit gestionarea grupurilor de obiecte, cu elemente de acelasi tip sau de
tipuri diferite System.Collections ofera un set de clase cu diverse functionalitati
specifice colectiilor.
Sintaxa foreach permite iterarea membrilor unui tablou sau colectii, fara a putea
modifica membrii. Pentru a altera valorile membrilor unui tablou sau colectii, se
poate utiliza o sintaxa de tip for.
3.Proprietati
Proprietatile sunt membri ai claselor care acceseaza variabile sau obiecte membre.
Prezinta similaritati atat fata de campuri cat si fata de metode. Valorile sunt setate si
inspectate folosind acceasi sintaxa ca in cazul campurilor: de fapt aceste doua operatii
sunt efectuate prin apelul unor metode specializate. Proprietatile pot contine cod care
valideaza valorile inainte de a le seta sau pot indeplini alte functionalitati impuse de
aplicatie.
Implementarea proprietatilor
Proprietatile permit accesarea valorilor si obiectelor membre intr-o maniera mai robusta
in comparatie cu inspectarea obisnuita a campurilor. O proprietate este o metoda
specializata care se comporta ca un camp. Valorile proprietatilor sunt setate si
inspectate in acelasi mod ca si campurile, fapt ilustrat in exemplul urmator:
// seteaza proprietatea Text a butonului btnExit la "Exit"
btnExit.Text = "Exit";
string sir;
// returneaza valoarea lui btnExit.Text si o asigneaza
string-ului sir
sir = btnExit.Text;
Pana acum, o proprietate arata si se comporta exact ca un camp. Totusi, codul asociat
unei proprietati este mai complex. Exista doua metode speciale asociate unei
proprietati, un getter si un setter care returneaza si, respectiv, seteaza valoarea
proprietatii. Exemplu:
// proprietatea se numeste Xmax
// o variabila locala care stocheaza valoarea
Page 26 of 203
ibm.com/developerWorks
private short x;
// implementarea proprietatii
public short Xmax
{
get
{
// returneaza valoarea variabilei locale
return x;
}
set
{
// seteaza valoarea variabilei locale
x = value;
}
}
Cuvantul rezervat value este un cuvant special folosit in setter-ul unei proprietati si
reprezinta intotdeauna valoarea la care se seteaza proprietatea. Proprietatile pot
expune orice tip de obiecte, tablouri sau colectii. Valoarea sau obiectul este retinut, de
obicei, intr-o variabila privata locala (x in exemplul anterior) si returnat atunci cand
proprietatea este accesata.
Exemplul anterior poate fi considerat trivial, proprietatea Xmax comportandu-se exact
ca un camp. Avantajul utilizarii proprietatilor consta in posibilitatea scrierii de cod
aditional in getter-ul si setter-ul proprietatii pentru a efectua calcule sau valida input-ul.
Exemplu:
private short x;
public short Xmax
{
get
{
// returneaza valoarea variabilei locale
return x;
}
set
{
// valoarea nu trebuie sa depaseasca 500
Page 27 of 203
ibm.com/developerWorks
Page 28 of 203
ibm.com/developerWorks
In anumite cazuri, pot fi implementate proprietati care pot fi scrise, dar nu citite, de
catre utilizator. Exemplu: pozitionarea unei forme in functie de setari specifice
localizarii(culturii) aplicatiei (localizare - concept care va fi prezentat intr-un curs viitor) forma este pozitionata la lansarea aplicatiei, nefiind necesara consultarea valorii
proprietatii respective.
O proprietate write-only se creaza similar unei proprietati obisnuite, omitand
implementarea getter-ului. Exemplu:
private short x;
public short XmaxForm
{
set
{
x = value;
}
}
Indexatori
Sunt proprietati specializate care permit accesarea obiectelor dintr-un grup. Numele
proprietatii este this, asociindu-se o variabila index. Exemplu:
// tablou care va stoca valorile retunate de indexator
private int[] tablou;
// sintaxa speciala care foloseste cuvantul rezervat this
public int this[int index] // indexatorul
{
get
{
return tablou[index];
}
set
{
tablou[index] = value;
}
}
Proprietati ale colectiilor
Expunerea colectiilor de obiecte ca proprietati permite controlarea accesului la
obiectele componente si validarea operatiilor de atribuire. Modalitatile de implementare
Dezvoltare de aplicatii in Visual Studio .NET
Page 29 of 203
ibm.com/developerWorks
Page 30 of 203
ibm.com/developerWorks
proprietati - expun variabile sau obiecte membre, furnizand cod pentru validarea
valorilor proprietatilor sau pentru efectuarea altor operatii; proprietatile read-only si
write-only limiteaza abilitatea utilizatorului de a consulta sau modifica propriatatile.
indexator - proprietate implicita a colectiilor
proprietatile colectiilor expun grupuri de obiecte din colectie
4.Delegati.Evenimente
Evenimentele reprezinta o notificare determinata de o actiune survenita intr-o sectiune
a a aplicatiei. La aparitia unui eveniment, altor parti ale aplicatiei li se ofera
oportunitatea de a raspunde prin executis unor metode denumite event handler-e.
Delegati
Un delegat este, in principiu, un pointer type-safe la o functie care permite
transmiterea unei referinte catre inceputul unei metode si apelarea metodei fara a
folosi un apel explicit al acesteia. La declararea unui delegat, se specifica signatura
metodei apelate si tipul returnat
Exemplu:
public delegate int firstDelegate(double D);
// acest delegat poate invoca metode care returneaza un int
// si primesc un parametru double
// metoda care va fi invocata de delegat
public int ReturnInt(double D)
{
// implementare...
}
// declararea unei instante firstDelegate si
// invocarea metodei ReturnInt
public void invokeMethod()
{
firstDelegate aDelegate = new firstDelegate(ReturnInt);
}
Invocarea metodei pentru care s-a instantiat delegatul:
aDelegate(6780.87);
Declararea si folosirea unui delegat:
Dezvoltare de aplicatii in Visual Studio .NET
Page 31 of 203
ibm.com/developerWorks
Page 32 of 203
ibm.com/developerWorks
Page 33 of 203
ibm.com/developerWorks
Page 34 of 203
ibm.com/developerWorks
simplitate
pozitionarea controalelor
consistenta: organizare, culori, forme, marime, tipuri, imagini, transparenta
estetica
Sinteza:
o interfata consistenta din punct de vedere vizual si logic este mult mai usor de
inteles si folosit
elementele de baza ale unei interfete sunt formele, controalele si meniurile
o interfata reusita trebuie sa tina cont de cateva aspecte legate de look si feel
sunt importante deciziile de design adresate direct utilizatorilor - semnificatii
culturale, consistenta, simplitate
2. Forme
Formele reprezinta unitatea fundamentala a unei interfete utilizator. Ele furnizeaza o
platforma pe care se plaseaza controalele si permit prezentarea aplicatiei intr-o
maniera consistenta si atractiva. Formele afiseaza date si primesc input-ul utilizatorilor.
De obicei, aplicatiile contin una sau mai multe forme, organizate astfel incat sa urmeze
logica fireasca a aplicatiei.
stabilirea rolului unei forme intr-o aplicatie
Dezvoltare de aplicatii in Visual Studio .NET
Page 35 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Efect
Manual
Page 37 of 203
ibm.com/developerWorks
CenterScreen
CenterParent
Valoare
Efect
Font
Cursor
BackGroundImage
Opacity
- variaza gradul de transparenta al formei
- valori posibile: in intervalul [0, 1]. Valoarea 1 indica faptul ca forma este complet
opaca, iar valoarea 0 creaza o forma complet transparenta. Valorile intermediare
imprima formei o transparenta partiala. Valoarea implicita este 1 (opacitate totala).
// o forma semi-transparenta
Page 38 of 203
ibm.com/developerWorks
MyForm.Opacity = .5;
! in fereastra Properties, Opacity este reprezentata ca o valoare procentuala.
Utilizarea metodelor specifice formelor
Orice forma incapsuleaza un set functional de baza mostenit din clasa
System.Windows.Forms.Form. Printre acestea, se gasesc metodele responsabile de
modul de afisare si de posibilitatile de accesare a formei in mediul de lucru. Cele mai
importante astfel de metode:
Form.Show
Form.ShowDialog
Form.Activate
Form.Hide
Form.Close
Folosirea acestor metode implica existenta unei instante a formei in memorie. Pe langa
instantele formelor create in cod, aplicatia creaza o instanta a formei de start-up in
lansarii in executie a programului.
Show si ShowDialog
- Form.Show - face forma vizibila (se incarca in memorie o instanta a formei, se
afiseaza forma pe ecran si primeste focus-ul aplicatiei). Proprietatea Visible este setata
la true dupa apelul lui Form.Show. Pentru o forma incarcata in memorie dar care este
invizibila (de exemplu, daca proprietatea Visible a fost setata la valoarea false), apelul
Form.Show are acelasi efect ca setarea proprietatii Visible la valoarea true.
- Form.ShowDialog - in plus, afiseaza forma modal, adica forma trebuie inchisa inainte
ca orice alta forma sa poata primi focus-ul.
// DialogForm este o clasa asociata unei forme existente
DialogForm myForm = new DialogForm();
//afiseaza fereastra in mod uzual
myForm.Show();
//afizeaza fereastra modal
myForm.ShowDialog();
Activate
pentru o forma vizibila, dar care nu a primit inca focus-ul, se poate utiliza metoda
Form.Activate
apelata in cadrul aplicatiei active, metoda Form.Activate aduce forma in prim-planul
aplicatiei si ii transmite focus-ul
apelarea metodei pentru o aplicatie inactiva in interfata utilizator, determina clipirea
titlului aplicatiei din taskbar
forma pentru care se apeleaza metoda Activate trebuie sa fie vizibila pentru a obtine
Dezvoltare de aplicatii in Visual Studio .NET
Page 39 of 203
ibm.com/developerWorks
efectul scontat.
//apelarea metodei Activate
myForm.Activate();
Hide
face forma invizibila. Desi forma persista in memorie, nu va mai fi vizibila pana la
apelarea metodei Form.Show sau la setarea proprietatii Visible la valoarea true in
cod
apelul metodei Hide seteaza proprietatea Visible la false
//apelarea metodei Hide
myForm.Hide();
Close
Form.Close inchide forma si o elimina din memorie
se inchid toate resursele continute de forma, fiind preluate de garbage collector
apelul Form.Close anuleaza efectul unui apel ulterior Form.Show, pentru ca
resursele asociate formei nu mai sunt disponibile
apelul Form.Close pentru forma de start-up determina inchidera aplicatiei
//apelarea metodei Close
myForm.Close();
Evenimente din cadrul formelor
Eveniment - o notificare survenita in urma unei actiuni din program. Aplicatia lanseaza
evenimentul, iar o alta componenta a aplicatiei are oportunitatea de a trata evenimentul
respectiv. Fiecare dintre metodele prezentate anterior lanseaza unul sau mai multe
evenimente; utilizatorul are oportunitatea de a trata prin cod aceste evenimente.
Exemple: apelul metodei Form.Hide determina lansarea evenimentelor Deactivate si
VisibleChanged. Un event handler este o metoda care se executa ca raspuns la
lansarea unui eveniment.
Crearea unui event handler pentru o forma, un control sau o componenta
1. Design view - selectarea formei sau a controlului pentru care se va crea event
handler-ul
2. Properties - butonul Events
3. din lista evenimentelor disponibile se selecteaza evenimentul dorit
4. se scrie codul pentru event handler
ibm.com/developerWorks
Load
Activated/Deactivate
VisibleChanged
Closing
Closed
Load
Se lanseaza in momentul in care o forma este incarcata pentru prima oara in program
la primul apel al metodelor Form.Show sau Form.ShowDialog.
Exemplu:
Form myForm = new Form();
myForm.Show();
// se lanseaza Load
myForm.Hide();
// forma este acum invizibila
myForm.Show();
// nu se mai lanseaza Load
myForm.Close();
// se inchide forma
Dezvoltare de aplicatii in Visual Studio .NET
Page 41 of 203
ibm.com/developerWorks
myForm.Show();
// exceptie, forma nu mai este disponibila
!
evenimentul Load este lansat o singura data pe parcursul duratei de viata a unei
instante a formei
Activated/Deactivate
Evenimentul Activated poate aparea in urmatoarele situatii (la primirea focus-ului):
- la apelul metodelor Form.Show, Form.ShowDialog, Form.Activate
- cand o forma este adusa in prim-planul aplicatiei
Deactivate apare ori de cite ori o forma pierde focus-ul:
- prin interactiunea utilizatorului cu interfata
- la apelul metodelor Form.Hide sau Form.Close (Form.Close lanseaza evenimentul
numai daca forma este activa)
! Activated si Deactivate sunt lansate numai cand focus-ul este modificat prin
intermediul programului.
VisibleChanged
- lansat la schimbarea proprietatii visible a formei la apelul metodelor Form.Show,
Form.ShowDialog, Form.Hide si Form.Close.
Closing - lansat in cazul in care forma este in curs de inchidere, dar nu este inca
inchisa complet
- prin apelul Form.Close sau prin apasarea butonului Close al formei
- signatura event handler-ului asociat evenimentului Closing include o instansa a clasei
CancelEventArgs
//anularea inchiderii formei
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
Closed
- se lanseaza dupa ce forma a fost inchisa prin apelul Form.Close sau prin inchiderea
manuala a formei; apare dupa lansarea evenimentului Closing si dupa executia tuturor
handler-elor asociate acestuia
Sinteza:
Page 42 of 203
ibm.com/developerWorks
BackColor
ForeColor
Text
Font
Cursor
BackGroundImage
Opacity
Form.Show
Form.ShowDialog
Form.Activate
Form.Hide
Form.Close
Load
Activated/Deactivate
VisibleChanged
Closing
Closed
3. Controale si componente
Controalele reprezinta al doilea element al unei interfete vizuale, in ordinea importantei,
dupa forme.
Functionalitate:
- o parte dintre controale, cum ar fi Button sau TextBox, sunt desemnate sa accepte
input-ul utilizatorului si sa execute operatii bazate pe interactiunea utilizatorului
- o alta parte constituie componente specializate, proiectate sa execute interactiuni
complexe cu alte parti ale aplicatiei.
Page 43 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Page 45 of 203
ibm.com/developerWorks
Page 46 of 203
ibm.com/developerWorks
Descriere
Tip EventArgs
MouseEnter
System.EventArgs
MouseMove
System.MouseEventArgs
MouseHover
System.EventArgs
MouseDown
System.MouseEventArgs
MouseWheel
System.MouseEventArgs
MouseUp
System.MouseEventArgs
MouseLeave
System.EventArgs
Descriere
Page 47 of 203
ibm.com/developerWorks
Button
Clicks
Delta
Page 48 of 203
ibm.com/developerWorks
- TabPage
Proprietatile Dock si Anchor implementeaza redimensionarea automata controalelor pe
o forma.
Colectia de controale asociate unei forme permite adaugarea dinamica de controale la
run time.
Adaugarea de noi controale la un ToolBox se face prin selectarea din lista controalelor
inregistrate in sistem a controlului dorit sau prin selectarea fisierului .dll sau .exe
asociat, din file system.
Event handlere - metode care trateaza evenimentele
Componente de tip Extender Provider - furnizeaza informatii aditionale pentru
controalele de pe o forma.
4. Meniuri
Meniurile faciliteaza accesul la sectiuni importante din cadrul aplicatiei.
OBIECTIVE:
* Explicarea importantei meniurilor in cadrul interfetelor
* Crearea unui meniu folosind componenta MainMenu
* Crearea unui meniu contextual folosind componenta ContextMenu
* Activarea si dezactivarea unui menu item
* Crearea de shortcut-uri pentru un menu item
* Crearea unui check mark sau a unui buton radio pentru un menu item
* Explicarea procedurii prin care un menu item poate deveni invizibil
* Adaugarea dinamica a unui menu item la un meniu
* Clonarea dinamica a unui meniu
Meniurile permit utilizatorilor sa acceseze comenzi si functii intr-o maniera familiara,
usor de inteles. In momentul proiectarii meniurilor, trebuie avut in vedere parcursul
logic al aplicatiei, elementele componente ale meniului trebuie grupate in concordanta
cu o anumita functionalitate.
Crearea meniurilor folosind Design View
Se foloseste componenta MainMenu. Aceasta contine si gestioneaza o colectie de
controale MenuItem care reprezinta elementele vizuale ale unui meniu la run time.
Componenta MainMenu
Page 49 of 203
ibm.com/developerWorks
Page 50 of 203
ibm.com/developerWorks
Page 51 of 203
ibm.com/developerWorks
menuItem1.Checked = true;
menuItem1.Checked = false;
Afisarea butoanelor radio
Se utilizeaza proprietatea RadioCheck.
! butoanele radio sunt folosite frecvent pentru afisarea unor optiuni exclusive
Ascunderea elementelor meniurilor
Se utilizeaza proprietatea Visible.
menuItem1.Visible = false;
!
Submeniurile continute de menu item-ul care devine invizibil vor deveni, de asemenea,
invizibile si, deci, innaccesibile.
Clonarea meniurilor
Se refera la copierea unor elemente de meniu la run time. Clonare imseamna
transmiterea tuturor informatiilor posibile obiectului caruia i se asigneaza obiectul
rezultat in urma acestei operatii.
Exemplu: clonarea meniului Edit (si a submeniurilor asociate) dintr-un main menu
pentru a servi drept meniu contextual unui control.
// fileMenuItem este un menu item existent,
// myButton este un Button
// declararea si
ibm.com/developerWorks
De exemplu, intr-un meniu, pot fi adaugate item-uri care sa afiseze caile spre cele mai
recente fisiere deschise de aplicatie. Aceste noi elemente de meniu nu vor avea event
handlere asociate, dar poate fi specificata o metoda de tratare a evenimentului Click,
ca argument al constructurului noului item. Aceasta metoda trebuie sa fie void si sa
aiba aceeasi signatura ca celelalte event handlere. Exemplu:
public void ClickHandler (object sender, System.EventArgs e)
{
// implementare...
}
Adaugarea dinamica a elementelor de meniu
Exemplu:
// ClickHandler este o metoda cu signatura
// corespunzatoare unui event handler
MenuItem myItem;
myItem = new MenuItem("Item 1", new EventHandler(ClickHandler));
//se adauga item-ul creat la un alt menu item
fileMenuItem.MenuItems.Add(myItem);
Sinteza
* meniurile permit accesul facil la comenzi din carul aplicatiei prin intermediul unei
interfete usor de folosit
* meniurile contextuale permit accesul la anumite comenzi in situatii contextuale
* meniurile se pot modifica la run time in functie de anumite situatii
Page 53 of 203
ibm.com/developerWorks
Descriere
Alt
Page 54 of 203
ibm.com/developerWorks
Control
Handled
KeyCode
KeyData
KeyValue
Modifiers
Shift
Evenimentele KeyUp si KeyDown sunt cel mai frecvent utilizate pentru a determina
daca s-a apasat Alt, Ctrl sau Shift, prin intermediul proprietatilor instantei
KeyEventArgs transmisa ca parametru handler-ului. Proprietatile KeyEventArgs Alt,
Control si Shift returneaza o valoare booleana care indica daca aceste taste sunt
apasate - true daca tasta corespunzatoare este apasata si false daca a fost eliberata.
Exemplu: se verifica daca tasta Alt este apasata
private void textBox1_KeyUp(object sender,
System.Windows.Forms.KeyEventArgs e)
{
if (e.Alt == true)
MessageBox.Show("Tasta ALT este inca apasata");
}
Proprietatea KeyEventArgs.KeyCode se poate utiliza pentru a examina tasta care a
lansat evenimentul. Returneaza o valoare Key care reprezinta tasta care a fost apasata
(evenimentul KeyDown) sau eliberata (evenimentul KeyUp).
Exemplu:
afisarea intr-un MessageBox a reprezentarii sub forma de string a tastei care a fost
apasate.
private void textBox1_KeyDown(object sender,
System.Windows.Forms.KeyEventArgs e)
{
MessageBox.Show(e.KeyCode.ToString());
}
KeyPress
Atunci cand utilizatorul apasa o tasta care are o valoare ASCII asociata, se lanseaza
evenimentul KeyPress. Printre tastele care au o valoare ASCII asociata sunt incluse
Dezvoltare de aplicatii in Visual Studio .NET
Page 55 of 203
ibm.com/developerWorks
caracterele alfabetice si numerice (a-z, A-Z, 0-9), precum si anumite taste speciale,
cum ar fi Enter and Backspace. Daca o tasta sau o combinatie de taste nu genereaza
o valoare ASCII, apasarea lor nu va determina aparitia evenimentului KeyPress.
Exemple de astfel de taste includ Ctrl, Alt si tastele functionale. La aparitia acestui
eveniment, se trasmite handler-ului ca parametru o instanta a clasei
KeyPressEventArgs. Aceasta instanta contine informatii despre tasta apasata care pot
fi folosite pentu validarea input-ului. Proprietatea KeyPressEventArgs.KeyChar contine
caracterul ASCII reprezentat de combinatia de taste care a lansat evenimentul.
KeyPressEventArgs.Handled este proprietatea care indica daca evenimentul a fost
tratat.
Validarea caracterelor
Tipul Char contine mai multe metode statice utile pentru validarea caracterelor
furnizate de evenimentul KeyPress. Cele mai importante astfel de metode:
* Char.IsDigit
* Char.IsLetter
* Char.IsLetterOrDigit
* Char.IsPunctuation
* Char.IsLower
* Char.IsUpper
Exemplu:
utilizarea metodei Char.IsDigit pentru a testa daca s-a apasat o tasta numerica:
private void textBox1_KeyPress (object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
if (Char.IsDigit(e.KeyChar) == true)
MessageBox.Show("Ai apasat o tasta numerica");
}
Tratarea focus-ului
Focus-ul reprezinta abilitatea unui obiect de a primi input prin intermediul mouse-ului
sau tastaturii. Un singur control poate detine focus-ului la un moment dat. Acesta se
afla pe forma activa a aplicatiei. Fiecare control implementeaza metoda Focus care
seteaza focus-ul controlului care a apelat-o. Returneaza o valoare booleana care
indica daca setarea focus-ului s-a executat cu succes sau nu. Proprietatea CanFocus
returneaza true in cazul in care controlul poate primi focus-ul si false in caz contrar.
if (textBox1.CanFocus == true)
textBox1.Focus();
Evenimentele referitoare la primirea sau pierderea focus-ului au loc in urmatoarea
Page 56 of 203
ibm.com/developerWorks
ordine:
1. Enter
2. GotFocus
3. Leave
4. Validating
5. Validated
6. LostFocus
Enter si Leave - controlul primeste si, respectiv, pierde focusul.
GotFocus si LostFocus - controlul obtine pentru prima oara focus-ul, respectiv,controlul
pierde focus-ul.
Validating si Validated - cele mai utile evenimente pentru validarea field-level.
Validating si Validated
Validating - are loc inainte ca un control sa piarda focus-ul. Proprietatea
CausesValidation a controlului care va primi focus-ul si a celui care trebuie validat
trebuie setata la true pentru ca evenimentul sa poata fi lansat. Exemple de cazuri de
utilizare: un event handler care testeaza daca input-ul respecta un anumit format,
imposibilitatea parasirii unui control pana la introducerea unor informatii de un anumit
tip.
Validated - este lansat dupa ce controlul a fost validat cu succes. Poate fi folosit pentru
a executa operatii bazate pe input-ul validat.
Exemplu:
event handler pentru evenimentul Validating
private void textBox1_Validating(object sender,
System.ComponentModel.CancelEventArgs e)
{
// verifica valoarea introdusa in textBox1
if (textBox1.Text == "")
// se reda focus-ul controlului
e.Cancel = true;
}
Validare form-level
Reprezinta procesul validarii simultane (in acelasi moment al executiei aplicatiei) a
tuturor campurilor de pe o forma. O procedura centralizatoare implementeaza validarea
form-level si este apelata, de obicei, in momentul in care utilizatorul doreste sa treaca
la un nou pas al aplicatiei.
Dezvoltare de aplicatii in Visual Studio .NET
Page 57 of 203
ibm.com/developerWorks
Exemplu:
la apasarea unui buton, se verifica toate toate controalele de tip TextBox au fost
completate si se transmite focus-ul primului TextBox care nu indeplineste aceasta
conditie, in cazul in care exista un asemenea TextBox.
private void btnValidate_Click(object sender,
System.EventArgs e)
{
// parcurgerea iterativa a tuturor controalelor de pe forma
foreach (System.Windows.Forms.Control aControl in this.Controls)
{
// se verifica daca este un TextBox si
// daca contine stringul vid
if (aControl is System.Windows.Forms.TextBox)
{
if (aControl.Text == "")
// se transmite focus-ul primului control care
// indeplineste conditia de mai sus
aControl.Focus();
return;
}
}
}
Keyboard Handler pentru validare form-level
Reprezinta o tehnica mai sofisticata de validare form-level. Un keyboard handler
centralizat permite gestionarea input-ului din toate campurile de pe o forma. Se
folosesc evenimentele KeyPress, KeyDown si KeyUp.
! pentru ca o forma sa lanseze aceste evenimente, proprietatea KeyPreview formei
trebuie setata la valoarea true. In acest caz, forma lanseaza evenimente legate de
apasarea tastelor inaintea controlului care detine focus-ul. Pentru a preveni executia
event handler-ului asociat evenimentului KeyPress al unui control, se seteaza
proprietatea KeyPressEventArgs.Handled la true:
private void Form1_KeyPress(object sender,
System.Windows.Forms.KeyPressEventArgs e)
{
//evita pasarea evenimentului event handler-ului
Page 58 of 203
ibm.com/developerWorks
Page 59 of 203
ibm.com/developerWorks
Page 60 of 203
ibm.com/developerWorks
Page 61 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Page 63 of 203
ibm.com/developerWorks
implementarea clasei de baza, iar instantele claselor derivate pot fi tratate ca instante
ale clasei de baza. Clasele derivate pot implementa functionalitati aditionale.
2. Overloading
Supraincarcarea (overloading) permite crearea mai multor membri ai unei clase avand
acelasi nume. Fiecare astfel de membru trebuie sa aiba o signatura diferita.
Supraincarcarea este cel mai frecvent folosita pentru metode, dar C# permite si
supraincarcarea operatorilor.
Sa consideram situatia crearii unei metode care poate avea diversi parametri. Sa
consideram urmatorul exemplu:
public void Afisare(int valoare)
{
// Implementare...
}
Sa presupunem ca utilizatorul doreste modificarea numarului si/sau tipurilor
parametrilor. Solutia acestei probleme este data de supraincarcare. Acesta implica
definirea mai multor functii cu acelasi nume. Metodele supraincarcate trebuie sa aiba
acelasi nume, dar acest lucru nu se respecta pentru tipul returnat sau pentru
modificatorii de acces asociati. La apelul unei metode supraincarcate, common
language runtime examineaza tipurile argumentelor transmise la apelul metodei. Se
cauta apoi o potrivire a listei argumentelor printre signaturile metodei supraincarcate si
se face apelul corespunzator. Daca nu se gaseste o astfel de potrivire, se genereaza o
eroare.
Metodele sunt membrii cel mai frecvent folositi pentru supraincarcare. C# permite
supraincarcarea operatorilor, oferind astfel functionalitati ale operatorilor pentru tipurile
definite de utilizator.
Supraincarcarea metodelor
Se poate crea o metoda supraincarcate similar crearii unei metode oarecare: prin
declararea unei metode cu un nume, un nivel de acces, returnand un anumit tip si
specificand o lista de argumente. O metoda supraincarcata trebuie sa aiba acelasi
nume ca si o alta metoda existent, dar trebuie sa aiba o signatura diferita. Nivelul de
acces si tipul returnat pot fi identice sau diferite.
Exemplu:
// metoda supraincarcata
public void Afisare(int i)
{
MessageBox.Show(i.ToString());
Page 64 of 203
ibm.com/developerWorks
}
// metoda cu acelasi nume, dar signatura diferita
public void afisare(string s)
{
MessageBox.Show(s);
}
Supraincarcarea operatorilor in C#
In aplicatii care utilizeaza tipuri definite de utilizator, se impune frecvent necesitatea
definirii unui set de operatii aritmetice, logice sau a unor operatori de comparare care
utilizeaza aceste tipuri de date. Exemplu:
public struct PrezenteLab
{
int nrPrez;
int nrPrezExtra;
}
Acesta structura poate fi utilizata pentru a gestiona evidenta situatiei prezentelor la un
laborator de informatica. Pentru o utilizare facila si eficienta, apare necesitatea
supraincarcarii operatorilor.
Sintaxa generala a supraincarcarii unui operator este urmatoarea:
public static tip operator op (argument1[, argument2])
{
//implementare...
}
Componenta tip din cadrul sintaxei reprezinta tipul returnat de operator. argument1,
argument2 etc. reprezinta argumentele asociate operatorului. Pentru un operator unar,
vom avea un singur argument, si trebuie sa aiba acelasi tip ca tipul returnat. Pentru un
operator binar, vom avea doua argumente, dintre care cel putin unul trebuie sa aiba
acelasi tip ca tipul retunat. op reprezinta insusi operatorul, de exemplu +, -, >, !=, si asa
mai departe. Un operator supraincarcat trebuie sa fie public, pentru a putea fi accesat.
Un operator supraincarcat trebuie sa fie, de asemenea, static. Definitia unui operator
supraincarcat trebuie sa apara in cadrul definitiei tipului asupra caruia i se aplica
operatorul. Sintaxa supraincarcarii operatorilor este similara pentru structuri si clase.
Exemplu: supraincarcarea operatorului + pentru structura definita anterior.
public struct PrezenteLab
{
int nrPrez;
Dezvoltare de aplicatii in Visual Studio .NET
Page 65 of 203
ibm.com/developerWorks
int nrPrezExtra;
// supraincarcarea operatorului +
public static PrezenteLab operator + (PrezenteLab a,
PrezenteLab b)
{
PrezenteLab rezultat = new PrezenteLab();
rezultat.nrPrez = a.nrPrez + b.nrPrez;
rezultat.nrPrezExtra = a.nrPrezExtra + b.nrPrezExtra;
return rezultat;
}
}
Utilizarea operatorului supraincarcat in cod:
// Saptamana2, Saptamana3 sunt instante
// ale structurii PrezenteLab
PrezenteLab total = new PrezenteLab();
total = Saptamana2 + Saptamana3;
Pornind de la ideea generala de supraincarcare, putem defini mai multe signaturi
pentru a suprincarca un acelasi operator. Exemplu:
public struct PrezenteLab
{
int nrPrez;
int nrPrezExtra;
// operatorul + supraincarcat anterior
public static PrezenteLab operator + (PrezenteLab a,
PrezenteLab b)
{
PrezenteLab rezultat = new PrezenteLab();
rezultat.nrPrez = a.nrPrez + b.nrPrez;
rezultat.nrPrezExtra = a.nrPrezExtra + b.nrPrezExtra;
return rezultat;
}
// supraincarcare aditionala (o alta signatura,
// o alta functionalitate)
Page 66 of 203
ibm.com/developerWorks
3. Polimorfism
Polimorfism bazat pe interfete
Interfetele permit definirea comportamentelor obiectelor. Clase diferite pot implementa
aceeasi interfata si pot, deci, interactiona cu alte obiecte intr-o maniera polimorfica.
O interfata actioneaza ca un sablon. Orice obiect care implementeaza o anumita
interfata garanteaza implementarea membrilor definiti in acea interfata. Daca un obiect
necesita interactiune cu o interfata specifica, orice obiect care implementeaza interfata
poate raspunde acestei interactiuni.
O interfata defineste numai membrii care vor deveni disponibili prin implementarea unui
obiect. Definitia unei interfete nu implica aspecte legate de implementarea membrilor,
specificandu-se, in schimb, lista parametrilor si tipul returnat. Sarcina implementarii
unei interfete revine, in totalitate, clasei care utilizeaza interfata.
Ca urmare, este posibila, pentru obiecte diferite, scrierea de implementari total diferite
ale acelorasi membri. Sa consideram, de exemplu, o interfata IForma, care defineste o
metoda CalculArie. O clasa Cerc care implementeaza aceasta interfata va calcula aria
intr-un mod diferit fata de o clasa Patrat care implementeaza aceeasi interfata.
Definirea interfetelor
Interfetele se definesc folosind cuvantul rezervat interface. De exemplu:
Page 67 of 203
ibm.com/developerWorks
Page 68 of 203
ibm.com/developerWorks
unei interfete:
public interface ICalculate
{
// alti membri...
event System.EventHandler OutOfMemory;
}
Definirea unei interfete
Se declara interfata folosind cuvantul rezervat interface. In cadrul definitiei interfetei, se
definesc signaturile metodelor, proprietatilor si evenimentelor membre ale interetei.
Polimorfism bazat pe interfete
Orice obiect care implementeaza o anumita interfata poate interactiona cu un alt obiect
care solicita acea interfata. Sa consideram, drept exemplu, urmatoarea metoda:
public void CalculateSomething(ICalculate ic)
{
// implementare...
}
Aceasta metoda necesita o implementare a interfetei ICalculate. Orice obiect care
implementeaza aceasta interfata poate fi transmis ca parametru acestei metode.
Obiectul va fi implicit convertit la interfata corespunzatoare. Cand un obiect
interactioneaza prin intermediul interfetei sale, numai membrii interfetei sunt accesibili.
Se poate executa, de asemenea, o conversie explicita a obiectelor care
implementeaza interfete specifice. Exemplu - conversia unui obiect WorkStation la
interfata ICalculate (obiectul ws trebuie sa implementeze ICalculate):
WorkStation ws = new WorkStation();
ICalculate calculateTool;
// converteste ws la interfata ICalculate
calculateTool = (ICalculate)ws;
Implementarea interfetelor
In C#, se utilizeaza caracterul : pentru a specifica o clasa sau o structura care
implementeaza o anumita interfata. Urmatorul exemplu indica faptul ca o clasa
implemeneaza o anumita interfata:
public class WorkStation : ICalculate
{
// cod aditional...
Page 69 of 203
ibm.com/developerWorks
}
Clasele pot implementa mai multe interfete. Exemplu:
public class WorkStation : ICalculate, IMovieViewer,
IInternetExplorer
{
// cod aditional....
}
Atunci cand o clasa sau o structura implementeaza o interfata, trebuie scrise
implementari separate pentru fiecare membru al interfetei. Daca se implementeaza mai
multe interfete, trebuie furnizate implementari pentru fiecare membru al fiecarei
interfete.
Implementarea membrilor interfetelor in C#
In C#, implementarea unui membru al interfetei in cadrul clasei sau structurii se
realizarea prin definirea unui membru care are acelasi nume cu membrul definit in
cadrul interfetei. Acest membru trebuie sa aiba acelasi modificator de acces ca in
cadrul interfetei. Exemplu:
public interface ICalculate
{
void BeginCalculation(int input);
}
public class WorkStation : ICalculate
{
public void BeginCalculation(int i)
{
// implementare...
}
}
In cazul unei astfel de implementari a membrilor unei interfete, ei sunt disponibili atat
interfetei, cat si clasei insesi. Deci, acesti membri pot fi accesati daca obiectul este
convertit la propria sa clasa sau la interfata implementata.
Este, de asemenea, posibila implementarea explicita a interfetei si blocarea accesului
la membrii sai pentru clasa care implementeaza interfata. Un membru astfel
implementat poate fi accesat numai cand obiectul parinte este convertit la interfata pe
care o implementeaza (si care contine membrul respectiv). Implementarea explicita a
unui membru al unei interfete se realizeaza prin specificarea completa a numelui
interfetei si a membrului. Exemplu:
Page 70 of 203
ibm.com/developerWorks
Page 71 of 203
ibm.com/developerWorks
Mostenirea
Mostenirea permite crearea mai multor clase distincte, dar care au in comun o anumita
functionalitate. Clasele specializate, denumite clase derivate, mostenesc o clasa
comuna, numita clasa de baza. Clasa de baza incapsuleaza functionalitatea comuna
care va fi prezenta in fiecare clasa derivata, in timp ce clasele derivate implementeaza
functionalitati specifice. De exemplu, sa consideram o clasa Laptop. Aceasta clasa
implementeza toata functionalitatea specifica unei clase Computer. In plus ea poate
implementa diverse metode specifice, cu ar fi StandByMode, apelata, de exemplu, la
inchiderea capacului laptop-ului.
Comportamente polimorfice in clasele derivate
Clasele derivate sunt, in general, intr-o relatie de tipul is-a fata de clasa de baza. De
exemplu, un Laptop este un (is-a ) Computer, iar un Computer este un Dispositif. Orice
instanta a unei clase derivate se poate comporta polimorfic ca o instanta a clasei de
baza. Deci, daca o metoda necesita un parametru de tip Computer, i se poate furniza
in schimb un obiect Laptop. Orice clasa derivata poate fi convertita implicit la clasa sa
de baza. In momentul conversiei catre clasa de baza, fiecare membru implementat de
clasa derivata va deveni inaccesibil; numai membrii clasei de baza vor fi disponibili.
Crearea claselor derivate
Se utilizeaza : (doua puncte). Exemplu:
public class Laptop : Computer
{
// implementare...
}
Clasele pot mosteni o singura clasa de baza, dar pot implementa una sau mai multe
interfete. Daca o clasa implementeaza mai multe interfete, odata cu derivarea dintr-o
clasa de baza, numele interfetelor trebuie enumerate dupa : (doua puncte), despartite
prin virgula. De exemplu:
public class Laptop : Computer,
ICalculate, IFileManager
{
// implementare...
}
Odata ce o clasa derivata a fost declarata, se pot implementa membrii aditionali pentru
a adauga functionalitati specifice clasei.
Crearea de clase care nu pot fi derivate
Uneori, este necesara definirea unor clase care nu vor putea fi mostenite. De exemplu,
o clasa specializata care va fi utilizata pentru scrierea unor componente si nu va fi utila
altor programatori, se defineste in asa fel incat sa nu poate fi mostenita. In C#, pentru a
realiza acest lucru, se utilizeaza cuvantul rezervat sealed:
Page 72 of 203
ibm.com/developerWorks
Page 73 of 203
ibm.com/developerWorks
Pentru a suprascrie un membru al unei clase de baza, acesta trebuie declarat virtual.
Membrii non-virtuali sunt nu pot fi suprascrisi. Exemplu de declarare a unei metode
virtuale:
public virtual void OverridableMethod()
{
// implementare...
}
Ascunderea membrilor clasei de baza
Un membru al clasei de baza poate fi ascuns prin inlocuirea sa cu o implementare
complet noua. Mecanismul este cunoscut sub numele de ascundere (hiding). La
ascunderea unui membru, se inlocuieste implementarea din clasa de baza cu o noua
implementare. Noua implementare trebuie sa aiba aceeasi signatura ca a membrului
ascuns si trebuie sa fie asociata unui membru de acelasi tip, dar poate avea nivel de
acces, tip returnat diferite, si o implementare complet diferita. Orice metoda care are
acelasi nume ca o metoda existenta, dar o signatura diferita, este tratata ca o
supraincarcare a metodei initiale si nu se va realiza ascunderea. Pentru a ascunde un
membru al unei clase de baza se defineste un membru in clasa de baza avand aceeasi
signatura si folosind cuvantul rezervat new:
// clasa de baza
public class ClasaDeBaza
{
public string metoda(int i)
{
// implementare...
}
}
// clasa derivata
public class ClasaDerivata : ClasaDeBaza
{
// ascunderea metodei din clasa de baza
// signatura identica, insa nivel de acces diferit,
// tip returnat diferit
internal new int metoda(int i)
{
// implementare...
}
Page 74 of 203
ibm.com/developerWorks
}
Mentinerea compatibilitatii cu membrii ascunsi
La ascunderea unui membru al unei clase, se ascunde implementarea din clasa de
baza si se creaza o noua implementare care nu trebuie sa aiba caracteristicile
implementarii membrului din clasa de baza. Acest aspect poate conduce la implicatii
nedorite in ceea ce priveste interoperarea cu alte obiecte. Daca un obiect apeleaza
metoda din exemplul anterior, in ideea de a obtine un String, la returnarea unui int, de
catre metoda care ascunde metoda initiala, se poate genera o eroare. Ascunderea
membrilor trebuie facuta deci cu atentie.
Desi ascunsa, implementarea membrilor din clasa de baza poate fi accesibila sub
anumite circumstante. Aceasta depinde de clasa, si nu de tipul obiectului, ca in cazul
membrilor suprascrisi. De exemplu, sa consideram urmatorul fragment de cod:
// folosim clasele din exemplul anterior
ClasaDerivata X = new ClasaDerivata();
ClasaDeBaza Y;
// X si Y refera acelasi obiect, dar
// variabilele au tipuri diferite
Y = X;
// se apeleaza noul membru
X.metoda(23);
// se apeleaza metoda originala
Y.metoda(23);
Deci, tipul variabilei determina daca se va apela membrul din clasa derivata sau
membrul original (ascuns). Ca urmare, se poate modifica implementarea unui membru
fara a se distruge abilitatea unei clase de a se comporta polimorfic.
Accesarea membrilor clasei de baza
La suprascrierea sau ascunderea unor membri, poate aparea necesitatea accesarii
implementarii acestor astfel de membri din clasa de baza. Pentru aceasta, se utilizeaza
cuvantul rezervat base. Se face astfel o referinta la implementarea clasei de baza si se
permite invocarea membrilor implementati in clasa de baza. Exemplu:
// apelul unei metode din clasa de baza
// dintr-o metoda care suprascrie metoda respectiva
public override string metoda(int i)
{
base.metoda(i);
// implementare...
Page 75 of 203
ibm.com/developerWorks
}
Membri protected
membri public - accesibili din orice sectiune a aplicatiei, incluzand clase externe
membri internal - accesibili membrilor assembly-ului local, dar nu si apelantilor
externi
membri private - disponibili numai in interiorul clasei
membri protected si protected internal - discutati in cele ce urmeaza
Un membru definit protected are aceeasi vizibilitate fata de apelantii externi ca si
membrii private. Diferenta consta in faptul ca membrii protected pot fi accesati din
clasele derivate. Exemplu:
// o metoda private si o metoda protected
// in clasa de baza
public class BaseClass
{
// o metoda private nu poate fi apelata
// din clase derivate
private void private_method()
{
// implementare....
}
// un membru protected poate fi
// apelat din clase derivate
protected void protected_method()
{
// implementare...
}
}
// clasa derivata
public class InheritedClass : BaseClass
{
public void Demo()
{
// apel legal, metoda protected
this.protected_method();
Page 76 of 203
ibm.com/developerWorks
Page 77 of 203
ibm.com/developerWorks
ibm.com/developerWorks
}
set
{
// implementarea setter-ului
}
}
}
!
Se pot crea noi clase abstracte prin derivarea din alte clase abstracte. In acest caz,
clasa abstracta derivata nu trebuie sa implementeze membrii abstracti definiti in clasa
de baza (acest lucru este, insa, permis).
Sinteza - cuvinte cheie
mostenire (derivare)
supraincarcare (overriding)
ascundere (hiding)
base
protected, protected internal
virtual
abstract
Page 79 of 203
ibm.com/developerWorks
ibm.com/developerWorks
speciale care sunt utilizate pentru a comunica starile de eroare ale diferitelor sectiuni
ale aplicatiei. Se poate scrie cod care sa trateze exceptiile, astfel incat acestea sa nu
stopeze executia aplicatiei.
Erori logice
Erorile logice apar atunci cand aplicatia este compilata si executata corect, dar nu se
obtin rezultatele scontate. Acestea pot fi considerate eroriele cel mai dificil de tratat,
pentru ca, adesea, nu exista informatii aditionale care sa indice sursa erorii. Erori
logice pot surveni, de exemplu, din plasarea inadecvata a punctului zecimal. De
exemplu:
public float CalculNota(int punctajLab, int punctajExamen)
{
float nota;
nota = punctajLab * 0.3 + punctajExamen * 0.07;
return nota;
}
Modul break
Modul break permite intreruperea executiei programului si executia codului linie cu
linie. In mod break, se pot utiliza uneltele de debugging pentru a examina valorile
variabilelor si proprietatile aplicatiei. In Visual Studio .NET, se intra in mod Break sub
una din urmatoarele circumstante:
s-a selectat Step Into, Step Over sau Step Out din meniul Debug sau din toolbar.
executia programului avanseaza la o linie care contine un breakpoint activ.
se intalneste un Stop
se arunca o exceptie netratata
Descriere
Windows
Start/Continue F5
Break All
Ctrl+Alt+Break
Stop Debugging
Shift+F5
Detach All
Page 81 of 203
ibm.com/developerWorks
Restart
Ctrl+Shift+F5
Apply Code
Changes
Processes
Exceptions
Ctrl+Alt+E
Step Out
Shift+F11
QuickWatch
Ctrl+Alt+Q
New Breakpoint
Ctrl+B
Clear All
Breakpoints
Ctrl+Shift+F9
Disable All
Breakpoints
Mai mult, anumite functii de debugging pot fi accesate prin clic dreapta pe un element
din fereastra de cod si alegand o functie meniul pop-up respectiv. Tabelul urmator
sintetizeaza o parte din aceste functii.
Tabel: functii de debugging accesibile din meniuri pop-up accesibile din cadrul ferestrei
de cod.
Optiune
Descriere
Insert Breakpoint
New Breakpoint
Add Watch
QuickWatch
Show Next
Statement
Page 82 of 203
ibm.com/developerWorks
Run To Cursor
Set Next
Statement
Page 83 of 203
ibm.com/developerWorks
Page 84 of 203
ibm.com/developerWorks
Descriere
Running
Documents
This
Call Stack
Threads
Modules
Memory
Disassembly
Registers
Sinteza
- tipuri de erori: de sintaxa, la executie si logice
- modul break - ferestre din meniul Debug
Page 85 of 203
ibm.com/developerWorks
Cum functioneaza tracing-ul? Clasele Trace si Debug fac parte din spatiul de nume
System.Diagnostics care contine metode statice care permit testarea anumitor conditii
la run time si salvarea rezultatelor sub forma de log-uri. Output-ul generat de aceste
metode este afisat in fereastra Output si poate fi vizualizat pe durata debugging-ului.
Output-ul este transmis, de asemenea, colectiei Listeners. Aceasta colectie contine un
grup de clase care pot primi output de la clasele Trace si Debug. Trace si Debug
partajeaza aceeasi colectie Listeners si toti asculatatorii din colectie primesc input de la
Trace si Debug. Exista mai multe tipuri de Listeners, incluzand ascultatori care scriu in
fisiere text si Trace Listeners care scriu in loguri de evenimente. Dupa executia
programului, se pot examina aceste fisiere pentru identificarea erorilor din aplicatie.
Tracing-ul este, de asemenea, util in optimizarea programelor.
Clasele Trace si Debug sunt aproape identice. Clasa Debug este folosita, in principal in
faza de dezvoltare, in timp ce Trace poate fi utilizata pentru testare si optimizare dupa
ce o aplicatie a fost compilata si s-a generat o versiune release a aplicatiei.
Scrierea output-ului furnizat de clasele Trace si Debug
Metodele care realizeaza acest lucru sunt:
Page 86 of 203
ibm.com/developerWorks
Page 87 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Daca este necesar, se poate seta proprietatea Trace.AutoFlush la valoarea true, sau
se poate apela Trace.Flush dupa fiecare scriere.
Comutatoare Trace (Trace Switches)
De obicei, la debugging, se doreste primirea intregului output provenit din constructii
care utilizeaza Trace si Debug. Totusi, dupa ce o aplicatie a fost compilata si lansata,
este de dorit activarea tracing-ului numai in anumite cazuri. Comutatoarele Trace sunt
comutatoare configurabile utilizate pentru a vizualiza constructii Trace. Acestea pot fi
configurate prin intermediul aplicatiei prin modificarea fisierului de configurare al
aplicatiei dupa ce aceasta a fost compilata si distribuita.
Exista in .NET Framework doua tipuri de comutatoare Trace. Instantele clasei
BooleanSwitch returneaza o valoare booleana. Deci, acestea sunt caracterizate prin
doua stari: on sau off. Clasa TraceSwitch permite utilizatorilor sa seteze nivelul
reprezentat de comutator, care poate fi o valoare intre 1 si 5, depinzand de tipul de
output pe care utilizatorul doreste sa il primeasca.
Ambele comutatoare necesita doi parametri in constructor: un NumeDeVizualizare,
care reprezinta numele comutatorului in cadrul interfetei utilizator si o Descriere, care
contine o scurta descriere a comutatorului. De exemplu:
BooleanSwitch firstBooleanSwitch = new BooleanSwitch("Switch1",
"Controls Data Tracing");
TraceSwitch firstTraceSwitch = new TraceSwitch("Switch2",
"Controls Forms Tracing");
Clasa TraceSwitch contine cinci setari care reprezinta diverse nivele de eroare. Aceste
setari sunt expuse prin intermediul proprietatii TraceSwitch.Level. Proprietatea poate fi
setata la una din cele cinci valori ale enumeratorului TraceLevel:
TraceSwitch.TraceError
TraceSwitch.TraceWarning
TraceSwitch.TraceInfo
TraceSwitch.TraceVerbose
Page 89 of 203
ibm.com/developerWorks
ibm.com/developerWorks
Exemplu:
<system.diagnostics>
<switches>
<add name="firstBooleanSwitch" value="0" />
<add name="firstTraceSwitch" value="3" />
</switches>
</system.diagnostics>
In acest exemplu, firstBooleanSwitch este setat pe off, iar firstTraceSwitch este setat la
TraceLevel.Info. Se modifica apoi valorile comutatoarelor, in functie de output-ul pe
care dorim sa il vizualizam. Se pot adauga, eventual, comentarii adecvate, pentru a
explica configurarile efectuate prin intermediul fisierului XML.
<system.diagnostics>
<switches>
<!-- pentru a primi mesaje Trace, setati valoarea la un intreg
nenul... -->
<add name="firstBooleanSwitch" value="0" />
<!-- setati valoarea la 1,2,3 sau 4 pentru, respectiv, mesaje
minimale, normale, detaliate sau complete -->
<add name="firstTraceSwitch" value="3" />
</switches>
</system.diagnostics>
Sinteza
- clasele Debug si Trace classes allow you to display and log messages
- colectia Trace.Listeners:
* DefaultTraceListener
* TextWriterTraceListener
* EventLogTraceListener
- comutatoare Trace: BooleanSwitch, TraceSwitch
- fisierul de configurare al aplicatiei
3. Exceptii
Chiar si dupa testarea si debugging-ul complet al aplicatiei, pot inca aparea erori la
Dezvoltare de aplicatii in Visual Studio .NET
Page 91 of 203
ibm.com/developerWorks
ibm.com/developerWorks
}
// urmeaza blocuri catch sau finally
Un bloc try poate fi urmat de unul sau mai multe blocuri catch. Un bloc catch contine
cod care va fi executat atunci cand exceptia va fi aruncata. Blocurile catch pot fi
generice sau specifice exceptiei. Exemplu: un bloc catch generic.
// bloc try... catch
{
// se executa la aruncarea oricarei exceptii
}
Se poate obtine o referinta a exceptiei care a fost aruncata. Acest lucru permite
accesarea in cadrul rutinei de tratare a exceptiei a informatiei continute de exceptie. Se
pot crea astfel blocuri catch multiple, specifice exceptiilor respective.
Exemplu:
// bloc try...
catch (System.NullReferenceException e)
{
// se prinde o exceptie NullReferenceException
}
catch (System.Exception e)
{
// acest bloc va prinde toate celelalte exceptii
}
Blocurile finally contin cod care trebuie executat independent de faptul ca o exceptie a
fost aruncata sau nu. Exemplu:
public void Parsare(string sir)
{
try
{
double x;
x = Double.Parse(sir);
}
catch (System.ArgumentNullException e)
{
// cod pentru cazul in care s-a
Dezvoltare de aplicatii in Visual Studio .NET
Page 93 of 203
ibm.com/developerWorks
Page 94 of 203
ibm.com/developerWorks
Rearuncarea exceptiiilor
Uneori, structura de tratare a exceptiilor, initial proiectata, nu este capabila sa trateze
total o anumita exceptie. In acest caz, se utilizeaza cuvantul rezervat throw, in cadrul
blocului catch, pentru rearuncarea exceptiei, adica transmiterea acesteia catre functia
apelanta. Exemplu:
try
{
// cod...
}
catch (System.NullReferenceException e)
{
// cod care testeaza posibilitatea tratarii exceptiei
// daca aceasta nu va putea fi tratata complet, va fi rearuncata
throw e;
}
In cazul unui catch generic, se utilizeaza cuvantul rezervat throw, fara a mai specifica o
referinta catre o anumita exceptie:
// bloc catch
catch
{
throw;
}
La rearuncare, se poate crea o noua exceptie care contine mesaje informative,
incluzand caracteristicile exceptiei initiale (in cazul in care dorim furnizarea de
informatii suplimentare catre nivelul superior al aplicatiei, caruia i se transmite exceptia
prin throw) Exemplu:
// bloc catch
catch (NullReferenceException e)
{
throw new NullReferenceException(
"Obiectul X este neinitializat", e);
}
Exceptii definite de utilizator (custom)
Un al doilea scenariu in care se poate arunca o noua exceptie este dezvoltarea de
Dezvoltare de aplicatii in Visual Studio .NET
Page 95 of 203
ibm.com/developerWorks
componente. In cazul unei conditii care nu poate fi rezolvate, este indicata aruncarea
unei exceptii definite de utilizator in cadrul aplicatiei client.
!
Aruncarea exceptiilor nu trebuie sa devina o obisnuinta, ci trebuie efectuata numai in
conditii exceptionale din program.
Exceptiile de tip custom se creaza prin derivarea din clasa
System.ApplicationException. Aceasta incapsuleaza intreaga functionalitate necesara
unei exceptii, incluzand proprietatile Message, StackTrace si InnerException. Exemplu:
public class CustomException: System.ApplicationException
{
KindOfObject an_object;
public KindOfObject ErrorObject // proprietate
{
get
{
return an_object; // read-only
}
}
// constructor - parametri de tip KindOfObject si string
public CustomException(KindOfObject o, string a) : base(s)
// se apeleaza constructorul din clasa de baza
{
// se seteaza proprietatea
an_object = o;
}
}
Dupa crearea unei clase exceptie, se poate arunca o noua instanta a acestei clase:
Exemplu:
KindOfObject a = new KindOfObject();
// cod care corupe obiectul a omis...
throw new CustomException(a, "Obiectul a a fost corupt!");
Sinteza
Page 96 of 203
ibm.com/developerWorks
- exceptii
- tratarea exceptiilor: try, catch, finally
- rearuncarea exceptiilor
- clasa System.ApplicationException
Page 97 of 203
ibm.com/developerWorks
ibm.com/developerWorks
centrale.
Un obiect DataSet contine o colectie de zero sau mai multe obiecte DataTable, fiecare
dintre acestea fiind o reprezentare in-memory a unei tabele. Structura unui obiect
DataTable este definita de colectia DataColumns, care enumereaza coloanele dintr-o
tabela si de colectia Constraint care enumereaza legaturile, constrangerile din tabela.
Aceste doua colectii definesc schema tabelei. Un obiect DataTable contine, de
asemenea, o colectie DataRows, care contine datele corespunzatoare din DataSet.
Un DataSet contine o colectie DataRelations care permite crearea asocierilor intre
liniile unei tabele si liniile altei tabele. Colectia DataRelations enumereaza un set de
obiecte DataRelation care definesc relatiile intre tabelele din DataSet.
Data Provider
Legatura cu baza de date este creata si mentinuta de un data provider. Acesta este
format dintr-un set de componente interconectate care coopereaza pentru a furniza
date intr-o maniera eficienta, performanta.
Exista patru tipuri de furnizori de date in .NET Framework:
- SQL Server .NET Data Provider
- OleDb .NET Data Provider
- ODBC Data Provider
- Oracle Data Provider
Fiecare dintre acesti furnizori contin versiuni ale urmatoarelor clase generice:
- Connection - realizeaza conexiunea la baza de date
- Command - executa o comanda asupra unei surse de date: comenzi non-query
(INSERT, UPDATE sau DELETE) sau comanda SELECT, returnand un DataReader
- DataReader - desemneaza o multime de inregistrari (recordset) bazata pe conexiune,
de tip forward-only , read-only
- DataAdapter - populeaza un DataSet sau DataTable non-conexiune si executa
modificari
Mecanismul accesarii bazelor de date in ADO.NET este urmatorul:
- un obiect Connection stabileste o conexiune intre aplicatie si baza de date. Aceasta
conexiune poate fi accesata direct de un obiect Command sau de un obiect
DataAdapter. Obiectul Command executa o comanda asupra bazei de date. Daca se
returneaza valori multiple, se utilizeaza un obiect DataReader care va contine datele
returnate. Aceste date pot fi procesate direct de de aplicatie. Alternativ, se poate utiliza
un DataAdapter pentru a popula un obiect DataSet. Modificarile asupra bazei de date
se pot efectua prin intermediul unui obiect Command sau unui obiect DataAdapter.
Connection
Reprezinta conexiunea curenta la baza de date.
Tipuri de conexiuni:
Dezvoltare de aplicatii in Visual Studio .NET
Page 99 of 203
ibm.com/developerWorks
ibm.com/developerWorks
2. Comenzi SQL
Structured Query Language (SQL) - limbajul universal al bazelor de date relationale.
SQL poate fi utilizat pentru a prelua si filtra inregistrari din baza de date, pentru a
adauga inregistrari, pentru a sterge inregistrari din baza de date si pentru a modifica
valorile unei inregistrari existente.
Exista 4 constructii de baza:
- SELECT - pentru selectarea anumitor inregistrari din baza de date
- UPDATE - pentru modificarea unor inregistrari in baza de date
- INSERT - pentru inserarea unei noi linii intr-o tabela
- DELETE - pentru eliminarea unei inregistrari
SELECT
Sintaxa:
SELECT lista_campuri
FROM lista_tabele
WHERE (Optional) filtre
ORDER BY (Optional) criteriu_de_ordonare
Sintaxa minimala:
SELECT campuri FROM tabele
Exemplu:
SELECT StudentID, Prenume FROM Studenti;
Selectarea tuturor campurilor dintr-o tabela:
SELECT * FROM Studenti
WHERE - filtreaza inregistrarile dupa un anumit criteriu
SELECT * FROM Studenti WHERE Prenume = 'Vlad'
O conditie mai complexa:
SELECT * FROM Studenti WHERE Prenume = 'Vlad' AND Nume = 'Tepes'
Operatorul IN:
ibm.com/developerWorks
ibm.com/developerWorks
INSERT INTO Studenti (Prenume, Nume, Varsta, Sex) VALUES ('Vlad', 'Tepes', 500,
'M')
3. Accesarea datelor
Conectarea la o baza de date
Exista mai multe posibilitatati de conectare la o baza de date:
- crearea unei conexiuni in mod design utilizand uneltele grafice din Visual Studio .NET
Conexiunile curente sunt vizualizate in fereastra Server Explorer, ca noduri copil ale
nodului Data Connections. Adaugarea unei conexiuni la proiect se face prin drag and
drop
- in fereastra Server Explorer se executa clic dreapta pe nodul Data Connections si se
selecteaza Add Connection, setandu-se proprietatile conexiunii in fereastra Data Link
care se deschide
- varianta manuala - adaugarea unui obiect Connection din Toolbox sau declararea si
instantierea obiectului in cod
- crearea unei conexiuni direct in cod - se seteaza manual proprietatea
ConnectionString. Exemplu:
// declararea si instantierea unui obiect OleDbConnection
OleDbConnection firstConnection = new OleDbConnection();
// setarea proprietatii connection string
firstConnection.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;DataSource=" +
"C:\\Mdb_databases\\studenti.mdb";
Utilizarea comenzilor asupra bazelor de date
Un obiect Command contine o referinta la o procedura stocata in cadrul bazei de date
sau o comanda SQL si poate executa comanda respectiva prin intermediul unei
conexiuni active la baza de date. Un astfel de obiect contine toate informatiile necesare
executiei comenzii, inclusiv o referinta la conexiunea activa, specificarea efectiva a
comenzii si, eventual, parametrii solicitati de comanda.
Clase de tip Command:
-OleDbCommand - interactiunea cu diverse tipuri de baze de date
-SqlCommand - interactiunea cu SQL Server 7 sau cu versiuni mai noi
Deoarece obiectele de tip Command implica existenta unei conexiuni active si nu
necesita interactiunea cu un DataAdapter, ele furnizeaza o modalitate rapida si
eficienta de interactiune cu baza de date.
Actiuni posibile:
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
Text, parametri sunt specificati in cadrul comenzii SQL prin caractere (?). De exemplu:
SELECT StudentId, Prenume, Nume
FROM Studenti
WHERE (Prenume = ?) AND (Nume = ?)
Parametrii sunt inserati in ordinea in care apar in colectia Parameters.
Obiectele de tip SqlCommand utilizeaza parametri identificati prin nume, mai precis, in
cadrul comenzii SQL, un parametru este identificat prin simbolul @, urmat de valoarea
proprietatii ParameterName a parametrului respectiv:
SELECT StudentId, Prenume, Nume
FROM Studenti
WHERE (Nume = @Nume)
Executia unei comenzi non-query utilizand un obiect Command
- INSERT, UPDATE, DELETE, CREATE TABLE si ALTER
- CommandType - setata la StoredProcedure sau Text - se specifica eventualii
parametri - se apeleaza metoda Command.ExecuteNonQuery
// apel identic pentru OleDbCommand sau SqlCommand
firstCommand.ExecuteNonQuery();
Utilizarea unui obiect Command pentru a returna o valoare singulara
- CommandType - setata la StoredProcedure sau Text
- se specifica eventualii parametri
- se apeleaza metoda Command.ExecuteScalar
Object o;
o = firstCommand.ExecuteNonScalar();
DataReader
Pentru a utiliza un obiect Command care are asociate interogari care returneaza valori
multiple, se apeleaza metoda ExecuteReader pentru a returna un DataReader. Un
DataReader este un obiect care gestioneaza date intr-o maniera read-only,
forward-only, eficienta si rapida. Un DataReader itereaza inregistrarile returnate intr-o
multime rezultat. Viteza de accesare a datelor este mare, dar limitarile provin din faptul
ca maniera de prelucrarea este read-only, forward-only si nu se pot face modificari
asupra bazei de date. Mai mult, este necesara mentinerea unei conexiuni active pe
durata efectuarii acestor operatii, ceea ce determina un consum destul de semnificativ
de resurse.
Crearea unui DataReader
Un DataReader nu poate fi creat explicit. El este instantiat printr-un apel al metodei
Page 106 of 203
ibm.com/developerWorks
ibm.com/developerWorks
while (firstReader.Read())
{
// accesarea coloanelor prin nume
Console.WriteLine(firstReader["Prenume"].ToString());
}
firstReader.Close();
// se inchide DataReader-ul
firstConnection.Close();
// se inchide conexiunea
DataReader - tipizare
Clasa DataReader expune, de asemenea, metode tipizate de extragere a informatiilor,
de tip Get:
bool bool_var;
bool_var = myDataReader.GetBoolean(3);
// se utilizeaza numarul coloanei
Metoda GetOrdinal
int StudID;
string student;
// se preia indexul coloanei, utilizand numele acesteia
StudID = firstDataReader.GetOrdinal("StudentID");
student = firstDataReader.GetString(StudID);
Multimi rezultat multiple
Daca proprietatea CommandType a obiectului Command este setata la valoarea Text,
se pot returna mai multe multimi de inregistrari drept rezultat. Exemplu de comanda
SQL care va furniza rezultate multiple:
SELECT *
FROM Studenti;
SELECT *
FROM Profesori;
Un DataReader returneaza implicit prima multime de inregistrari in mod automat.
Pentru a accesa urmatoarea multime rezultat, se apeleaza metoda NextResult.
Exemplu:
do
{
Page 108 of 203
ibm.com/developerWorks
while (firstReader.Read())
{
// iterarea inregistrarilor multimii rezultat curente
}
} while (firstReader.NextResult());
Executia interogarilor SQL Ad Hoc
Sunt comenzi ale caror interogari se construiesc la run-time. Exemplu 1:
string cmd;
cmd = "SELECT * FROM Studenti WHERE Nume = '" + sir_de_caractere
+ "'";
Exemplu 2:
public void DeleteRecord(string sir)
{
string cmd;
cmd = "DELETE * FROM Studenti WHERE Nume = '" + sir + "'";
OleDbCommand firstCommand = new OleDbCommand(cmd,
firstConnection);
firstConnection.Open();
firstCommand.ExecuteNonQuery();
firstConnection.Close();
}
!
Atentie la validarea continutului variabilelor utilizate in constructia comenzilor SQL!
Crearea si configurarea obiectelor DataAdapter
Asigura legatura intre o sursa de date si un DataSet, gestionand schimbul de date intre
aceste doua entitati. Un DataAdapter incorporeaza functionalitatea necesara extragerii
datelor, popularii unui DataSet si aplicarii modificarilor in baza de date.
Clase .Net Framework: SqlDataAdapter, OleDbDataAdapter.
Un DataAdapter este utilizat, in general, pentru gestionarea schimbului de date dintre
un obiect DataTable continut intr-un DataSet si o singura tabela sursa.
Modalitati de creare a unui DataAdapter:
- utilizand fereastra Server Explorer (se adauga, prin drag and drop, o tabela in
design-ul aplicatiei)
- folosind Data Adapter Configuration Wizard (utilizand componenta DataAdapter din
Toolbox)
ibm.com/developerWorks
- manual
ibm.com/developerWorks
- Command
* ExecuteNonQuery
* ExecuteScalar
* ExecuteReader
- parametri
- DataReader
- DataAdapter
ibm.com/developerWorks
ibm.com/developerWorks
ParentRow = unDataSet.Tables["optionale"].
Rows[2].GetParentRow(oRelatie);
Constrangeri
Constrangerile definesc reguli de adaugare si manipulare a datelor in tabele. Tipuri de
constrangeri: UniqueConstraint (o coloana nu trebuie sa aiba valori duplicate) si
ForeignKeyConstraint (defineste regulile de modificare a liniilor copil atunci cand se
modifica o linie parinte).
Constrangerile sunt manipulate prin intermediul colectiei Constraints a tabelei si sunt
active atunci cand proprietatea EnforceConstraints a DataSet-ului este setata la true.
Exemple:
myDataColumn.Unique = true;
// se creaza o canstrangere UniqueConstraint
Creare manuala:
UniqueConstraint myConstraint = new
UniqueConstraint(myDataColumn);
myDataTable.Constraints.Add(myConstraint);
Stabilirea unei chei multiple:
DataColumn[] KeyColumns = new DataColumn[2];
KeyColumns[0] = StudentsTable.Columns["FirstName"];
KeyColumns[1] = StudentsTable.Columns["LastName"];
UniqueConstraint myConstraint = new
UniqueConstraint(KeyColumns);
StudentsTable.Constraints.Add(myConstraint);
Constrangeri Foreign Key
ForeignKeyConstraint myConstraint = new
ForeignKeyConstraint(Studenti.Columns["StudentID"],
Optionale.Columns["StudentID"]);
Adaugarea la colectia Constraints:
Studenti.Constraints.Add(myConstraint);
Reguli ForeignKeyConstraint referitoare la relatia parent-child :
UpdateRule: invocata la modificarea unei linii parinte
DeleteRule: invocata la stergerea unei linii parinte
AcceptRejectRule: invocata la apelarea metodei AcceptChanges a obiectului
DataTable caruia ii apartine constrangerea.
ibm.com/developerWorks
Fiecare dintre aceste reguli sunt expuse ca proprietati ale obiectului care desemneaza
constrangerea si pot avea diverse valori: Cascade, None, SetDefault, SetNull.
Fiecare DataSet mentine doua versiuni ale informatiilor continute: versiunea curenta,
care contine copia client a DataSet-ului si evidenta modificarilor efectuate, si versiunea
originala, care contine datele in formatul in care se gaseau la prima populare a
DataSet-ului. La apelul metodei Update a obiectului DataAdapter, valorile initiale sunt
utilizate de comenzi UPDATE, INSERT si DELETE pentru a executa modificarile in
baza de date.
Editarea datelor
- prin intermediul controalelor din interfata utilizator conectate la anumite entitati din
baza de date
- prin constructii programatice (vezi exemplu)
// accesare prin index sau nume
aDataRow[3] = "M";
aDataRow["Studenti"] = "Vlad";
Metoda RejectChanges anuleaza modificarile efectuate asupra unui DataRow:
aDataRow.RejectChanges();
AcceptChanges - se aplica modificarile efectuate asupra obiectului DataRow apelant:
with the edited version.
aDataRow.AcceptChanges();
Se poate determina starea unui obiect DataRow analizand proprietatea RowState.
Valori posibile:
- Unchanged
- Modified
- Added
- Deleted
- Detached
Obiectele DataTable si DataSet contin, de asemenea, metode RejectChanges si
AcceptChanges, care permit refuzarea sau acceptarea modificarilor din DataTable,
respectiv DataSet.
Modificarea bazei de date
firstDataAdapter.Update();
secondOtherDataAdapter.Update();
Metoda Update are ca efect copierea versiunii client a datelor in baza de date.
Page 114 of 203
ibm.com/developerWorks
ibm.com/developerWorks
}
Tratarea erorilor de Update
Clasele SqlDataAdapters si OledbDataAdapters contin un eveniment RowUpdated
care se lanseaza dupa modificare unei linii, inainte de lansarea eventualelor exceptii.
Acest eveniment trebuie tratat in mod adecvat. Evenimentul RowUpdated contine o
instanta SqlRowUpdatedEventArgs sau OleDbRowUpdatedEventArgs, care furnizeaza
informatii utile in determinarea erorii care a survenit.
Proprietati ale RowUpdatedEventArgs:
Command
Errors
RecordsAffected
Row
Status
Continue
ErrorsOccurred
SkipAllRemainingRows
SkipCurrentRow
Exemplu:
private void aDataAdapter_RowUpdated(object sender,
System.Data.SqlClient.SqlRowUpdatedEventArgs e)
{
// se verifica proprietatea Status
if (e.Status == UpdateStatus.ErrorsOccurred)
{
MessageBox.Show("A survenit o eroare de tipul " +
e.Errors.ToString()+".
Informatii aditionale : " + e.Errors.Message);
// se ignora modificarile de la linia curenta,
// continuandu-se cu urmatoarele
e.Status = UpdateStatus.SkipCurrentRow;
}
}
ibm.com/developerWorks
ibm.com/developerWorks
Exemplu 2:
String[] studenti = new String[3];
studenti[0] = "Aionesei";
studenti[1] = "Agafitei";
studenti[2] = "Georgescu";
TextBox1.DataBindings.Add("Text", studenti, "");
// al treilea parametru este vid, sursa de date
// nu este complexa, nu are membri
Eliminarea unei legaturi:
Label1.DataBindings.Remove(Label1.DataBindings["Text"]);
// se elimina legatura existenta pentru proprietatea
// Text a etichetei Label1
Eliminarea tuturor legaturilor asociate unui control - prin apelarea metodei Clear:
Label1.DataBindings.Clear();
Navigare (Data Currency)
Fiecare forma gestioneaza obiecte CurrencyManager asociate surselor de date prin
intermediul unui obiect central BindingContext. Accesarea unui anumit currency
manager se face prin intermediul proprietatii BindingContext, specificand sursa de date
a obiectului in cauza. De exemplu:
this.BindingContext[DataSet1.Students];
Inregistrarea curenta poate fi setata prin intermediul proprietatii Position a unui
BindingContext:
// tabela Studenti face parte din DataSet1
// setarea inregistrarii curente la prima
// inregistrare din sursa de date
this.BindingContext[DataSet1.Studenti].Position = 0;
// setarea inregistrarii curente la a
//treia inregistrare din sursa de date
this.BindingContext[DataSet1.Studenti].Position = 2;
// avansarea la urmatoarea inregistrare
this.BindingContext[DataSet1.Studenti].Position ++;
Navigarea prin colectia de date dintr-o forma Windows
Se seteaza proprietatea Position a membrului BindingContext dorit.
Page 118 of 203
ibm.com/developerWorks
Este imposibila deplasarea inaintea primei inregistrari sau dupa ultima inregistrare.
Exemplu: utilizarea evenimentului PositionChanged din cadrul clasei CurrencyManager
pentru dezactivarea butoanelor de navigare atunci cand linia curenta este pozitionata
pe prima sau ultima inregistrare.
// handler
public void OnPositionChanged(object sender, System.EventArgs e)
{
if (this.BindingContext[DataSet1.Students].Position == 0)
// dezactivarea butonului Back
BackButton.Enabled = false;
else
// activare
BackButton.Enabled = true;
// similar pentru butonul Forward
}
// linia de adaugat in constructorul formei
this.BindingContext[DataSet1.Customers].PositionChanged += new
EventHandler(this.OnPositionChanged);
Legare complexa
Prin setarea proprietatii DataSource:
DataGrid1.DataSource = DataSet1.Students;
Proprietatea DisplayMember desemneaza numele coloanei la care se leaga controlul.
Exemplu:
ComboBox1.DataSource = DataSet1.Students;
ComboBox1.DisplayMember = "StudentID";
Filtrarea si sortarea datelor
DataView permite lucrul cu un subset al datelor continute intr-un DataTable. Aceasta
clasa contine metode pentru sortarea si filtrarea datelor, permitand si modificarea
obiectului DataTable pe care il reprezinta.
Crearea unui DataView
Se specifica obiectul DataTable care va fi filtrat. Exemplu:
DataView aDataView = new DataView(aDataTable);
Alternativa:
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
anotherDataViewManager.DataSet = anotherDataSet;
Colectia DataViewSettings contine proprietatile DataView asociate tabelelor dintr-un
DataSet. Exemplu:
aDataViewManager.DataViewSettings["Students"].RowFilter =
"Prenume = 'Costel'";
Sinteza:
- data binding
- data provider
- data consumer
- CurrencyManager
- DataView
- RowFilter si Sort
- DataViewManager
ibm.com/developerWorks
Spatiu de nume
Continut
System.Drawing
System.Drawing.Design
System.Drawing.Drawing2D
System.Drawing.Imaging
System.Drawing.Printing
System.Drawing.Text
Majoritatea claselor care faciliteaza randarea grafica sunt incluse in spatiul de nume
System.Drawing. Pentru randare avansata, se utilizeaza clase din spatiul de nume
System.Drawing.2D, iar pentru implementarea unor functionalitati de printare, clase din
System.Drawing.Printing.
Clasa Graphics
Clasa Graphics, localizata in spatiul de nume System.Drawing, este principala clasa
utilizata pentru randare grafica. Un obiect Graphics reprezinta suprafata grafica a unui
element vizual, cum ar fi o forma, un control sau un obiect Image. Deci, o forma are
asociat un obiect Graphics utilizat pentru a desena in interiorul formei; un control are
asociat un obiect Graphics folosit pentru a desena in interiorul controlului, s.a.m.d.
Page 122 of 203
ibm.com/developerWorks
Descriere
Point
PointF
Size
SizeF
Rectangle
ibm.com/developerWorks
RectangleF
Exemplu:
// conversie de la o structura punct reprezentata
// prin valori float la un punct
// reprezentat prin intregi
Point aPoint;
PointF aPointF = new PointF(10.9F,31.23F);
aPoint = new Point((int)aPointF.X, (int)aPointF.Y);
Exemplu:
crearea unei structuri Rectangle prin specificarea unui structuri Size si a unei structuri
Point:
Point pointOrigin = new Point(100, 50);
Size aSize = new Size(40, 50);
// se creaza un Rectangle 40 pe 50 avand
// coltul din stanga sus specificat de Point(100,50)
Rectangle aRectangle = new Rectangle(pointOrigin, aSize);
Desenarea formelor
Orice obiect Graphics incapsuleaza o varietate de metode pentru randarea formelor
simple si complexe pe ecran. Acestea sunt incadrate in doua categorii generale:
- metode de tip Draw - linii, arce, contururi ale formelor;
- metode de tip Fill - forme solide - dreptunghiuri, elipse sau poligoane
Metode pentru desenarea structurilor bazate pe linii:
Metoda
Descriere
DrawArc
DrawBezier
DrawBeziers
DrawClosedCurve
DrawCurve
DrawEllipse
DrawLine
DrawLines
ibm.com/developerWorks
DrawPath
DrawPie
DrawPolygon
DrawRectangle
deseneaza un dreptunghi
DrawRectangles
Descriere
FillClosedCurve
FillEllipse
FillPath
FillPie
FillPolygon
FillRectangle
FillRectangles
FillRegion
Fiecare dintre aceste metode primesc diversi parametri care specifica coordonatele
punctelor si locatia formelor care se vor desena. Fiecare metoda necesita un obiect
care sa efectueze randarea. Pentru structuri liniare, se utilizeaza un obiect Pen. Pentru
forme solide, se folosesc obiecte Brush.
Color, Brush si Pen
Aceste tipuri sunt utilizate pentru a determina modul de randare a unei imagini grafice.
Obiectele Pen redau linii si arce, obiectele Brush redau forme solide, iar obiectele de
tip Color definesc culorile folosite in vizualizare.
Color
Structura Color reprezinta o singura culoare si se gaseste in spatiul de nume
System.Drawing. Culorile individuale sunt derivate din patru valori: Alpha - gradul de
transparenta, Red, Green si Blue, cuprinse intre 0 to 255. O noua culoare se poate
crea folosind metoda Color.FromArgb:
Color aColor;
aColor = Color.FromArgb(128, 255, 12, 50);
Pentru culori opace, parametrul Alpha se omite:
ibm.com/developerWorks
Color aColor;
aColor = Color.FromArgb(255, 12, 43);
Exista un set de culori definite in .NET Framework. Exemplu:
Color aColor;
aColor = Color.Tomato;
Brush
Obiectele Brush sunt sunt folosite pentru randarea formelor solide. Toate aceste
obiecte sunt derivate din clasa abstracta de baza Brush si furnizeaza implementari
diferite ale obiectelor utilizate pentru randarea obiectelor solide, in diferite stiluri.
Tipuri de obiecte Brush:
Tip
Spatiu de nume
Descriere
SolidBrush
System.Drawing
TextureBrush
System.Drawing
HatchBrush
System.Drawing.Drawing2D
hasureaza interiorul
obiectelor
LinearGradientBrush System.Drawing.Drawing2D
PathGradientBrush
System.Drawing.Drawing2D
ibm.com/developerWorks
ibm.com/developerWorks
Descriere
AddClosedCurve
AddEllipse
adauga o elipsa
AddPath
AddPie
AddPolygon
AddRectangle
adauga un dreptunghi
AddRectangles
AddString
ibm.com/developerWorks
O figura poate fi creata si pas cu pas, prin adaugare de linii, arce si curbe (se utilizeaza
metodele din tabelul de mai jos). Primul pas in crearea figurii este aplearea metodei
GraphicsPath.StartFigure. Se adauga apoi elemente la figura respectiva, apelandu-se,
in final, metoda GraphicsPath.CloseFigure pentru inchiderea figurii. Exemplu:
GraphicsPath somePath = new GraphicsPath();
somePath.StartFigure();
// adaugare de elemente ...
somePath.CloseFigure();
O figura pentru care s-a apelat StartFigure, fara a se apela CloseFigure, va ramane
deschisa.
!
La run-time, o figura deschisa se va inchide prin adaugarea unei linii intre primul si
ultimul punct ale figurii.
Metode GraphicsPath pentru adaugarea de elemente liniare la o figura:
Metoda
Descriere
AddArc
adauga un arc
AddBezier
AddBeziers
AddCurve
AddLine
adauga o linie
AddLines
Sinteza
- Graphics
- Pen, Brush, Color
- SystemPens, SystemBrushes, SystemColors
- GraphicsPath
2. Controale utilizator
Programarea Windows Forms este bazata pe controale. Controalele permit
incapsularea unui set de unitati functionale discrete si furnizeaza utilizatorului o
reprezentare grafica a acestor functionalitati. .NET Framework pune la dispozitie o
varietate de unelte si tehnici care ajuta la crearea controalelor personalizate din cadrul
aplicatiei utilizator.
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
In .NET Framework, controale sunt clase specializate care includ cod pentru randarea
unei interfete grafice. Exista mai multe surse posibile pentru controalele utilizate in
aplicatii. Controalele incluse in Microsoft Visual Studio .NET acopera o gama larga de
functionalitati si permit dezvoltarea de aplicatii cu o serie intreaga de caracteristici. Pot
fi utilizate, de asemenea, o serie de controale implementate de alti programatori sau
pot fi folosite controale ActiveX.
Controale personalizate - privire de ansamblu
Toate controalele din .NET Framework sunt derivate direct sau indirect din clasa de
baza Control. Acesta clasa pune la dispozitie functionalitatea de baza necesara unui
control. De exemplu, clasa Control implementeaza logica tratarii input-ului utilizatorului
prin interactiunea cu tastatura si mouse-ul si logica interactiunii cu mediul Windows. In
plus, un control derivat din clasa Control contine un set de proprietati, metode si
evenimente comune tuturor controalelor. Crearea functionalitatii specifice controlului,
precum si vizualizarea grafica a acestuia sunt sarcini ce revin utilizatorului.
Exista trei tehnici de baza pentru crearea unui control:
- derivarea dintr-un control existent :
reprezinta cel mai rapid si facil mod de dezvoltare a unui control; noul control contine
toata functionalitatea controlului de baza si poate actiona ca baza pentru alte controale,
mostenind reprezentarea vizuala a controlului din care de deriveaza. Aceasta tehnica
este folosita atunci cand este necesara duplicarea functionalitatii unui control Windows
Forms si adaugarea de functionalitati specifice sau definirea unui aspect vizual nou.
Majoritatea controalelor Windows Forms pot fi utilizate drept clase de baza pentru
crearea de controale noi. Exemplu: crearea unui TextBox cu validare implicita
(functionalitate specifica) sau crearea unui Button cu colturile rotunjite (aspect vizual
specific).
- derivarea din clasa UserControl:
tehnica utilizata pentru crearea de controle care inglobeaza un numar de controale
Windows Form sub forma unei singure unitati functionale. Se deriveaza din clasa
UserControl care pune la dispozitie o functionalitate de baza, la care se pot adauga
proprietati, metode, evenimente si alte controale. Dupa adaugarea controalelor
componente, se scrie cod pentru implementarea functionalitatilor specifice. Rezultatul
este un control proiectat de utilizator, alcatuit dintr-un set de controale care se
comporta ca o singura unitate functionala. Majoritatea modificarilor vizuale aduse
controalelor componente constau in simpla configurare si repozitionare a controalelor
constituente.
- derivarea din clasa Control:
utilizata in cazul in care este necesara o interfata vizuala sau/si o functionalitate
complexa care nu pot fi implementate prin intermediul unui user-control sau a unui
control derivat. Controalele personalizate sunt derivate din clasa Control, clasa de baza
a tuturor controalelor. Pasii necesari dezvoltarii unuii astfel de control pot fi
consumatori de timp, oferind insa posibilitatea implementarii unui control personalizat,
cu functionalitate si aspect vizual specifice.
ibm.com/developerWorks
ibm.com/developerWorks
}
}
Modificarea aspectului vizual al unui control
Se suprascrie motoda OnPaint. Pentru modificarea formei unui control, se seteaza
proprietatea Region a controlului in metoda OnPaint. Region este o clasa care descrie
o regiune regulata sau neregulata de pe ecran, similar unui GraphicsPath. O regiune
poate fi creata pe baza unui GraphicsPath. Exemplu - un buton care este vizualizat sub
forma unui string:
public class TextButton :
System.Windows.Forms.Button
{
protected override void OnPaint(PaintEventArgs pe)
{
System.Drawing.Drawing2D.GraphicsPath aPath = new
System.Drawing.Drawing2D.GraphicsPath();
aPath.AddString("Cool", Font.FontFamily,
(int)Font.Style, 72, new PointF(0, 0),
StringFormat.GenericDefault);
// se creaza o noua regiune pornind de la aPath
Region aRegion = new Region(aPath);
// se asigneaza regiunea proprietatii Region a controlului
this.Region = aRegion;
}
}
!
- butonul astfel creat nu este rectangular, ci are forma determinata de literele
cuvantului "Cool". Pentru a executa clic pe buton, trebuie utilizata regiunea determinata
de literele acestui cuvant;
- exista controale pentru care nu se lanseaza evenimentul Paint, fiind desenate de
forma parinte.
Crearea unui user-control
Un astfel de control consta in unul sau mai multe controale legate sub forma unei
singure unitati. Controalele componente pot fi adaugate controlului utilizator la
design-time. Un control utilizator poate fi adaugat la proiect utilizand optiunea Add User
Control din meniul Project.
Exemplu, crearea unui control utilizator format din doua TextBox-uri si un Label care
Page 132 of 203
ibm.com/developerWorks
afiseaza automat suma celor doua numere introduse in TextBox-uri. Pentru aceasta,
se suprascrie metoda OnKeyPress pentru fiecare TextBox:
protected override void OnKeyPress(object sender,
KeyPressEventArgs e)
{
// se verifica daca s-a tastat o cifra
if (char.IsNumber(e.KeyChar) == false)
e.Handled = true;
Label1.Text = (int.Parse(TextBox1.Text) +
int.Parse(TextBox2.Text)).ToString();
}
La crearea unui control utilizator in Visual Studio .NET, controalele constituente sunt
tratate implicit ca private. Pentru a permite altor utilizatori sa modifice proprietatile
controalelor constitutive, acestea trebuie expuse prin intermediul proprietatilor
controlului utilizator parinte. Exemplu:
public Color ButtonColor
// proprietate a controlului parinte
// Button1 este un constituent al acestuia
{
get
{
return Button1.BackColor;
}
set
{
Button1.BackColor = value;
}
}
Expunerea completa a unui control constituent se poate efectua prin intermediul
proprietatii Modifiers, disponibila in fereastra Properties, numai in faza de design.
Crearea unui control custom
Controalele de acest tip confera cel mai inalt nivel de configurabilitate si personalizare,
dar sunt si cele mai consumatoare de timp in faza de dezvoltare. Deoarece clasa
Control nu furnizeaza o reprezentare vizuala, utilizatorul are sarcina de a scrie cod
care sa redea vizualizarea grafica a controlului. In cazurile in care este necesara o
reprezentare vizuala complexa, aceasta faza poate ocupa cea mei mare perioada de
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
Controlul trebuie construit (built) inainte de a putea fi testat. Odata ce proiectul care
contine controlul a fost construit, controlul poate fi adaugat la o forma si testat ca in
cazul oricarui alt proiect.
In cazul in care controlul face parte dintr-un proiect executabil, precum un proiect
Windows Forms, se poate adauga o noua forma la proiect care sa gazduiasca
controlul. In cazul in care controlul face parte dintr-un proiect non-executabil, cum ar fi
o librarie de clase sau un control Windows, trebuie creat un proiect aditional pentru a
putea testa controlul (se adauga proiectul continand controlul ca referinta a noului
proiect creat - Solution Explorer - References - Add Reference ).
Gazduirea unui control in Internet Explorer
Orice control Windows Forms poate fi incarcat in Internet Explorer; pentru a profita de
aceasta posibilitate, se creaza pagini HTML care contin controale Windows Forms.
Pentru a putea incarca un control in Internet Explorer, acesta trebuie instalat in Global
Assembly Cache (vezi cursul 10...) sau trebuie plasat in acelasi director virtual in care
se gaseste pagina HTML care utilizeaza controlul.
Adaugarea unui control Windows Forms intr-o pagina HTML se efectueaza utilizand
tagul <OBJECT>. Acest tag specifica faptul ca un obiect compilat va fi inserat in
pagina. Tagul <OBJECT> examineaza proprietatea classid a obiectului pentru a
identifica tipul obiectului care va fi incarcat. Deci, in proprietatea classid se va specifica
propriul control Windows Forms.
classid-ul unui control Windows Forms consta in doua parti. Prima parte este calea
catre fisierul care contine controlul, cea de-a doua este numele complet al controlului.
Separarea celor doua parti se face utilizand caracterul #. Exemplu: utilizarea tagului
<OBJECT> pentru un control din fisierul ControlLibraryExample.dll (aflat in acelasi
director ca si pagina HTML) avand numele ControlLibraryExample.firstControl:
<OBJECT id="firstControl"
classid="http:ControlLibraryExample.dll#ControlLibraryExample.firstControl
VIEWASTEXT>
</OBJECT>
Sinteza
- adaugarea controalelor utilizator la Toolbox prin intermediul optiunii Customize
Toolbox
- asocierea unui bitmap controalelor utilizand clasa ToolboxBitmapAttribute
- debugging-ul controalelor
- incarcarea controalelor in Internet Explorer utilizand tagul <OBJECT>
ibm.com/developerWorks
4. Atribute
Atributele sunt entitati din program utilizate pentru a asocia informatii, cum ar fi
adnotari, tipurilor C# definite de utilizator. Aceste informatii sunt arbitrare, adica nu sunt
dependente de limbaj in sine, utilizatorul avand libertatea de a crea si asocia informatii
de orice tip.
Utilizari:
- furnizarea de informatii la design-time (documentatii)
- furnizarea de informatii la run-time (de exemplu numele unei coloane dintr-o tabela)
- stabilirea de comportamente la run-time (stabilirea caracteristicilor unei entitati din
program, configurari etc)
Definirea atributelor
Un atribut este, de fapt, o clasa derivata din clasa System.Attribute.
Exemplu:
public class FirstAttribute: Attribute
{
public FirstAttribute(string s)
{
// cod...
}
// alte campuri, proprietati, metode...
}
Aplicare:
[First("John")] // lipseste prefixul Attribute
public class Test
{
// clasa Test are asociat atributul First,
cu valoarea "John"
}
Interogarea atributelor
Se utilizeaza mecanismul de Reflection - determinarea dinamica la run-time a
caracteristicilor tipurilor dintr-o aplicatie. Exemplu: determinarea listei tuturor claselor,
tipurilor si metodelor definite intr-o aplicatie.
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
retinut este ca atributele furnizeaza practic facilitati nelimitate, fiind foarte utile in faza
de reflection si introspectie a aplicatiei.
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
In modelul de printare .NET Framework, continutul care va fi printat este furnizat direct
de logica aplicatiei. Un proces de printare este initiat utilizand metoda
PrintDocument.Print. Aceasta starteaza procesul si lanseaza unul sau mai multe
evenimente PrintPage. Daca nu exista metode client pentru tratarea acestui
eveniment, printarea nu va avea loc. Furnizand o metoda care sa trateze evenimentul,
se poate specifica continutul care va fi printat.
Daca continutul care va fi printat contine mai multe pagini, se va lansa cate un
eveniment PrintPage pentru fiecare pagina din procesul de printare. Acest lucru
cauzeaza event-handlerului asociat evenimentului PrintPage sa se execute de mai
multe ori. Deci, aceasta metoda trebuie sa implementeze functionalitati care sa
gestioneze procesul de printare si sa asigure faptul ca sunt printate, succesiv, paginile
anumit document. Altfel, prima pagina a documentului va fi printata de mai multe ori.
Evenimentul PrintPage
Evenimentul PrintPage este principalul eveniment implicat in printarea documentelor.
Pentru transmiterea efectiva a continutului care va fi printat catre printer, trebuie
implementata o procedura de tratare a acestui eveniment, in cadrul careia sa se scrie
cod pentru redarea continutului care va fi printat in formatul dorit. Toate obiectele si
informatiile necesare transmiterii continutului catre printer sunt incapsulate in obiectul
PrintPageEventArgs, primit ca parametru de event handler. Acest obiect contine
proprietatile listate in tabelul urmator:
Proprietate
Descriere
Cancel
Graphics
HasMorePages
MarginBounds
PageBounds
PageSettings
Continutul care va fi printat este redat prin intermediul obiectului Graphics continut de
instanta PrintPageEventArgs. In acest caz, pagina printata se va comporta ca o forma,
ca un control sau ca orice alta suprafata de desenare care poate fi reprezentata
printr-un obiect Graphics. Pentru a reda continutul, se utilizeaza aceleasi metode ca in
cazul utilizarii formelor. Exemplu, printarea unei elipse:
// acesta metoda va trata evenimentul PrintPage
public void PrintEllipse(object sender,
ibm.com/developerWorks
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawEllipse(Pens.Black, e.MarginBounds);
}
Proprietatile MarginBounds si PageBounds reprezinta dimensiunile care definesc
suprafata paginii. Se poate specifica ca printarea sa aiba loc in interiorul limitelor
paginii calculand coordonatele de printare pe baza dreptunghiului definit de
MarginBounds. Printarea care se va efectua inafara limitelor marginilor, ca in cazul
antetelor sau notelor din subsolul paginilor, poate fi specificata calculand coordonatele
de printare pe baza dreptunghiului definit de PageBounds. Similar desenarii pe ecran,
coordonatele de printare sunt specificate, implicit, in pixeli.
Se poate specifica faptul ca un proces de printare contine mai multe pagini utilizand
proprietatea HasMorePages. Implicit, aceasta proprietate este setata la false. Atunci
cand, prin logica programului, se stabileste ca vor fi mai multe pagini de printat in
cazdrul unui astfel de proces, se seteaza aceasta proprietate la valoarea true. Atunci
cand ultima pagina este printata, proprietatea trebuie resetata la false.
!
Metoda care trateaza evenimentul PrintPage trebuie sa tina cont de numarul de pagini
din proces, in caz contrar, putandu-se obtine comportamente nedorite ale aplicatiei. De
exemplu, daca se omite resetarea proprietatii HasMorePages la valoarea false dupa ce
ultima pagina a fost printata, aplicatia va continua sa lanseze evenimente PrintPage.
Un proces de printare poate fi oprit, fara a fi necesara terminarea printarii paginii
curente, prin setarea proprietatii Cancel la valoarea true.
Crearea unei metode de tratare a evenimentului PrintPage: prin dublu-clic pe instanta
PrintDocument in mod design sau prin declararea in codul programului.
Printarea
Initierea unui proces de printare se realizeaza, simplu, prin apelul metodei
PrintDocument.Print. Ramane de indeplinit sarcina selectarii continutului care este
trimis la printer.
Printarea elementelor grafice
Acesta implica randarea elementelor grafice pe ecran. Se utilizeaza obiectul Graphics
din cadrul instantei PrintPageEventArgs pentru a randa elementele grafice pe ecran.
Se pot printa forme simple sau forme complexe, utilizand System.Drawing sau
System.Drawing.Drawing2D.
Exemplu: printarea unei forme complexe utilizand un obiect GraphicsPath:
// event handler pentru PrintPage
public void PrintGraphics(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
ibm.com/developerWorks
{
System.Drawing.Drawing2D.GraphicsPath myPath = new
System.Drawing.Drawing2D.GraphicsPath();
myPath.AddPolygon(new Point[] {new Point(1, 1),
new Point(12, 55), new Point(34, 8), new Point(52, 53),
new Point(99, 5)});
myPath.AddRectangle(new Rectangle(33, 43, 20, 20));
e.Graphics.DrawPath(Pens.Black, myPath);
}
Pentru a printa elemente grafice care ocupa mai multe pagini, se divide, prin logica
programului, continutul care va fi printat. De exemplu, urmatoarea metoda va desena o
elipsa pe doua pagini:
bool FirstPagePrinted = false;
// event handler pentru PrintPage
public void PrintBigEllipse(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
if (FirstPagePrinted == false)
{
FirstPagePrinted = true;
e.HasMorePages = true;
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(0, 0,
e.PageBounds.Width, e.PageBounds.Height * 2));
}
else
{
e.HasMorePages = false;
FirstPagePrinted = false;
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(0,
-(e.PageBounds.Height), e.PageBounds.Width,
e.PageBounds.Height * 2));
}
}
ibm.com/developerWorks
ibm.com/developerWorks
float YPosition = 0;
int Counter = 0;
string CurrentLine;
// numarul de linii pe pagina
MyLines = e.MarginBounds.Height/myFont.GetHeight(e.Graphics);
// printeaza fiecare linie,
// oprindu-se la sfarsitul fiecarei pagini
while (Counter < MyLines and ArrayCounter <=
myStrings.GetUpperBound(0))
{
CurrentLine = myStrings[ArrayCounter];
YPosition = TopMargin + Counter *
myFont.GetHeight(e.Graphics);
e.Graphics.DrawString(CurrentLine, myFont, Brushes.Black,
LeftMargin, YPosition, new StringFormat());
Counter +=1;
ArrayCounter +=1;
}
// daca mai sunt linii de printat,
// se trece la o alta pagina
if (!(ArrayCounter == myStrings.GetUpperBound(0)))
e.HasMorePages = true;
else
e.HasMorePages = false;
}
Daca printerul ofera suport pentru folosirea culorilor, aplicatia trebuie sa tina cont de
acest lucru. Proprietatea PrinterSettings.SupportsColor poate fi consultata pentru a
determina daca printerul suporta sau nu utilizarea culorilor. Pentru a forta printarea
alb-negru, chiar daca printerul este color, se seteaza proprietatea
DefaultPageSettings.Color la false. Exemplu:
// using System.Drawing,
// System.Drawing.Drawing2D si System.Drawing.Printing...
Brush BrushOne;
Brush BrushTwo;
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
if (printDocument1.PrinterSettings.SupportsColor == true)
{
// color...
BrushOne = Brushes.Red;
BrushTwo = Brushes.Blue;
}
else
{
// alb-negru...
BrushOne = new HatchBrush(HatchStyle.DarkVertical, Color.Black);
BrushTwo = new HatchBrush(HatchStyle.DashedHorizontal,
Color.Black);
}
PrintPreviewControl
.NET Framework implementeaza un control PrintPreviewControl care permite
efectuarea unei previzualizari grafice a continutului care va fi printat inainte ca acesta
sa fie trimis catre printer. Controlul PrintPreviewControl se gaseste in tabul Windows
Forms din Toolbox, putandu-se adauga o instanta a sa prin drag-and-drop pe o forma.
Pentru a putea previzualiza o pagina, controlul PrintPreviewControl trebuie asociat unei
instante PrintDocument. Aceasta asociere se creaza prin setarea proprietatii
PrintPreviewControl.Document:
aPrintPreview.Document = aPrintDocument;
Din acest moment, controlul PrintPreviewControl va putea afisa continutul care va fi
printat. Acest lucru se realizeaza prin apelarea metodei care trateaza evenimentul
PrintDocument.Print si preluand outputul grafic al acelei metode. Acest output este
apoi redat prin intermediul controlului PrintPreviewControl.
Pe masura ce conditiile din program se modifica, docuentul printat se poate modifica,
de asemenea. Actualizarea previzualizarii se poate realiza prin apelarea metodei
InvalidatePreview:
aPrintPreview.InvalidatePreview();
O alta proprietate importanta a controlului PrintPreviewControl este proprietatea Zoom.
Valoarea 1 determina vizualizarea la dimensiunea maxima. O valoare fractionara va
reduce imaginea, iar o valoare supraunitara o va mari.
PrintPreviewDialog
Acest control reprezinta o resursa pentru previzualizarea documentelor printate si
crearea de previzualizari personalizate. .NET Framework implementeaza un control
Page 148 of 203
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
Furnizarea de help in aplicatii permite utilizatorilor sa inteleaga mai usor aplicatia, ceea
ce conduce la cresterea productivitatii.
Pentru aplicatii complexe si dificile, este necesara scrierea de help built-in , integrat in
aplicatie. Help-ul poate fi scris in fisiere HTML care contin un set informatii accesibile
prin linkuri sau in fisiere CHM (Compressed HTML) care se pot crea cu Microsoft
HTML Help Workshop. Ambele abordari permit vizualizarea dinamica a informatiile
accesibile prin linkuri.
Clasa Help
O aplicatie poate vizualiza fisiere HTM sau CHM prin intermediul clasei Help. Aceasta
clasa incapsuleaza HTML Help 1 engine si pune la dispozitie metode statice care
permit vizualizarea fisierelor de help. Cele doua metode expuse de clasa Help sunt
ShowHelp si ShowHelpIndex.
Metoda ShowHelp afiseaza un fisier de help pentru un anumit control. Controlul care
contine fereastra de dialog HelpDialog trebuie sa fie vizualizat pentru a putea afisa
fisierul de help specificat printr-un URL. URL-ul poate fi un fisier (de exemplu,
C:\fileHelp.htm) sau un HTTP URL (de exemplu,
http://someserver.com/someHelp.htm). Pentru ca metoda ShowHelp este statica, nu
este necesara crearea unei instante a clasei Help pentru a o putea utiliza. De fapt,
clasa Help nu poate fi instantiata.
Exemplu:
Help.ShowHelp(someForm, @"C:\someHelpFile.htm");
Aditional, se poate specifica un parametru HelpNavigator. Acesta specifica care dintre
elementele fisierului de help vor fi vizualizate. Acest parametru poate fi setat la
TableOfContents, Find, Index sau Topic. Se poate specifica, de asemenea, un cuvant
de cautare, ca in exemplul urmator:
Help.ShowHelp(someForm, @"C:\someHelpFile.htm", "HelpMenu");
Clasa Help contine metoda ShowHelpIndex care vizualizeaza indexul unui fisier de
help specificat. Apelul metodei ShowHelpIndex se executa in aceeasi maniera ca si
metoda ShowHelp.
Help.ShowHelpIndex(someForm, @"C:\someHelpFile.htm");
Metodele clasei Help pot fi apelate ca raspuns la o varietate de evenimente lansate de
interactiunea cu interfata utilizator. De exemplu, mai multe aplicatii includ un meniu de
Help sau meniuri care pot fi accesate prin clic dreapta pe un anumit control. De aceea,
aplicatiile trebuie sa ofere facilitati de help organizate intr-o maniera logica si eficienta.
Componenta HelpProvider
Componenta HelpProvider permite furnizarea de help pentru controalele din interfata
utilizator. HelpProvider este un extender provider; deci, coordoneaza si mentine
proprietati pentru fiecare control adaugat pe o forma. Se poate specifica un HelpString
pentru fiecare control de pe forma. Acest string este vizualizat atunci cand controlul
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
3. Globalizare si localizare
.NET Framework pune la dispozitia programatorilor un suport bogat pentru scrierea de
aplicatii accessibile global. Se pot crea aplicatii care se adapteaza la diverse limbaje,
formate monetare, calendaristice sau alte informatii legate de cultura.
In cazul dezvoltarii de aplicatii pentru o companie care face afaceri pe plan
international, trebuie avut in vedere faptul va vor exista utilizatori provenind dintr-o
variatate de culturi. Utilizatorii din anumite regiuni ale lumii pot fi nefamiliarizati cu
standardele legate de monede sau date calendaristice din tara din care provine
dezvoltatorul aplicatiei, sau nu pot intelege limba engleza, de exemplu. Integrand
suport international in aplicatii, se largeste aria de utilizare a aplicatiei.
Globalizare si localizare
Globalizarea si localizarea sunt procese interdependente dar diferite. Globalizarea
implica aplicarea formatarii datelor existente pe baza specificului unei anumite culturi,
in timp ce localizarea implica extragerea anumitor date pe baza unei culturi.
Exemplu:
* Globalizare: scrierea numerelor reprezentand sume de bani este in anumite tari
implica utilizarea (.) ca separator pentru mii si o virgula ca separator zecimal. O
aplicatie globalizata formateaza numerele reprezentand sume de bani pe baza regulilor
de acest gen din regiunea respectiva.
* Localizare: titlul unei forme este afisat intr-un anumit limbaj, dependent de tara in care
este utilizata aplicatia. O aplication localizata preia stringul potrivit si il afiseaza in
functie de locatie.
Culture
Intr-o aplicatie, termenul cultura se refera la informatia culturala legat de regiunea in
care este utilizata aplicatia. In .NET Framework, culturile sunt identificate utilizand un
cod cultural care reprezinta limba curenta folosita in mediul de lucru. Un cod de cultura
poate, de asemenea, specifica informatii despre o anumita regiune. In general, codul
culturii este fie un cod din doua litere, care specifica limba, fie un cod din doua litere,
urmat de o liniuta si alte doua litere care specifica regiunea. Codurile care specifica
numai limbajul se numesc culturi neutre,in timp ce codurile care specifica limba si
regiunea sunt cunoscute drept culturi specifice. Exemple:
* en - limba engleza, nici o regiune
* en-CA - limba engleza, Canada
* ro - limba romana
Lista completa a codurilor culturale poate fi consultata utilizand documentatia aferenta
clasei CultureInfo in the .NET Framework.
Setarea culturii curente
ibm.com/developerWorks
ibm.com/developerWorks
// using System.Globalization
CultureInfo theCurrentCulture;
theCurrentCulture = CultureInfo.CurrentUICulture;
UI-cultura curenta se seteaza in acceasi maniera ca si cultura curenta: accesand
Thread-ul curent. De exemplu:
System.Threading.Thread.CurrentThread.CurrentUICulture = new
System.Globalization.CultureInfo("th-TH");
La setarea culturii curente, sistemul de operare incarca resursele specifice acelei
culturi, in cazul in care sunt disponibile. Daca resursele specifice nu sunt disponibile,
interfata utilizator vizualizeaza resursele pentru cultura respectiva.
!
UI-cultura trebuie setata inainte de o forma sa poata vizualiza resursele localizate.
Daca UI-cultura se seteaza programatic, ea trebuie setata in constructorul formei
principale sau in metoda main a aplicatiei.
Crearea formelor localizate
Crearea formelor localizate in .NET Framework este un proces facil. Fiecare forma
contine o proprietate Localizable care determina daca forma este localizata sau nu.
Setarea acestei proprietati la true permite localizarea. In acest caz, Visual Studio .NET
creaza automat fisierele resursa necesare, utilizand proprietatea Language a formei.
Atunci cand aceasta proprietate este setata la (Default), pot fi editate toate
UI-proprietatile sau controalele pentru a furniza o reprezentare a UI-culturii curente.
Pentru a crea o versiune localizata a formei, se poate seta proprietatea Language la o
alta valoare, diferita de (Default). Visual Studio .NET va crea un fisier resursa pentru
noul limbaj si va stoca in acel fisier toate valorile UI-specifice setate.
!
Desi, de obicei, UI-elementele sunt siruri de caractere, orice proprietate poate fi
localizata. Deci, putem avea, de exemplu, butoane care isi modifica dimensiunile
pentru a putea vizualiza corect texte in diverse limbi. Aceste fisiere pot fi vizualizate in
Solution Explorer, existand cate un fisier resursa pentru fiecare limbaj pentru care
forma are o versiune.
Atunci cand CurrentUICulture este setata la o cultura localizata, aplicatia va incarca
versiunea corespunzatoare a formei consultand fisierele resursa aferente. Daca nu
exista fisierele resursa necesare, se va vizualiza UI-cultura implicita.
Validarea input-ului cu specific international
se pot utiliza metodele de validare din structura Char pentru a valida inputul introdus
(acesta poate contine caractere specifice unei anumite limbi). Metodele Char.IsDigit,
Char.IsLetter si altele vor returna true sau false, independent de caracterele utilizate.
Deci, validarile de acest gen vor functiona corect, fara alte modificari speciale.
Formatari specifice culturilor
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
Se pot specifica valori pentru anumiti membri ai clasei CultureInfo pentru a croi
aplicatia astfel incat sa raspunda unor necesitati cu specific cultural. De exemplu, sa
consideram o aplicatie pentru un client care colaboreaza cu un grup din Japonia, dar
moneda utilizata in aplicatie este dolarul american. Aplicatia trebuie sa implementeze o
formatare cu specific japonez pentru anumite elemente.
Membri ai clasei CultureInfo care specifica formatari legate de globalizare:
* DateTimeFormat - formatarea datelor calendaristice si a timpului
* NumberFormat - formatarea datelor numerice si financiare
* TextInfo - formatarea textelor
Exemplu:
// using System.Globalization
// using System.Threading
CultureInfo modJPCulture = new CultureInfo("jp-JN");
modJPCulture.NumberFormat.CurrencySymbol = "$";
// se foloseste caracterul $
Thread.CurrentThread.CurrentCulture = modJPCulture;
Implementarea scrierii de la dreapta la stanga
Anumite limbaje folosesc o astfel de scriere. Formele Windows tandard contin o
proprietate RightToLeft care permite implementarea unei interfete cu un astfel de
specific.
Valori posibile ale proprietatii RightToLeft : Yes, No si Inherit, ultima fiind valoarea
implicita, caz in care afisarea este determinata de valoarea setata pentru controlul
parinte.
Efectul setarii proprietatii RightToLeft a unui control la valoarea Yes:
- aliniera textului este inversata
- pentru o forma, titlul va fi aliniat la dreapta
- barele de derulare verticale vor aparea pe partea stanga
- barele de derulare orizontale sunt initializate cu slider-ul in partea dreapta
- check-box-urile vor avea proprietatea CheckAlign inversata
- butoanele taburilor vor fi inversate
- la fel, alinierea elementelor in list box si combo box
Pe short, formatarea fiecarui control consta in oglindirea continutului acestuia.
Continutul unui control RightToLeft ramane, totusi, neschimbat.
Conversia caracterelor codificate
.NET Framework utilizeaza o reprezentare Unicode UTF-16 a caracterelor. Un caracter
Page 156 of 203
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
Informatiile legate de identitatea assembly-ului pot fi modificate prin setarea valorilor
acestor atribute in fisierul AssemblyInfo. Urmatorul exemplu de cod demonstreaza cum
se poate seta atributul AssemblyTitle:
[assembly: AssemblyTitle("Acesta este un assembly!")]
Crearea assembly-urilor de tip biblioteca de clase (class library)
Acestea reprezinta o multime de tipuri care pot fi referentiate si utilizate in alte
assembly-uri. De exemplu, un control personalizat care va fi utilizat in alte aplicatii va fi
construit in cadrul unui assembly de aces tip. Un astfel de assembly nu este executabil,
trebuind adaugat ca referinta intr-o alta aplicatie executabila.
Tipurile de proiecte asociate unui astfel de assembly sunt Class Library sau Windows
Control Library. Se scrie codul, se seteaza informatiile legate de identitatea
assembly-ului in fisierul AssemblyInfo si se executa Build.
Resurse si assembly-uri de resurse
O mare parte dintre aplicatii utilizeaza resurse. Acestea reprezinta date
non-executabile partajate in cadrul aplicatiei. Exemple de resurse: siruri de caractere
vizualizate in cadrul interfetei utilizator pe baza culturii setate in aplicatie sau un set de
imagini. Impachetarea acestor date in fisiere resursa permit modificarea datelor
necesare programului fara a recompila intreaga aplicatie.
Crearea fisierelor de resurse
Aplicatia ResEditor din .NET Framework poate fi utilizata pentru a crea fisiere resursa
care contin texte si imagini. ResEditor este o aplicatie de sine statatoare, nefiind
integrata in Visual Studio .NET. Ea va fi rulata separat, utilizand command prompt-ul
Visual Studio .NET. ResEditor permite crearea de fisiere .resources sau .resx care
contin siruri de caractere sau imagini. Se pot specifica tipul si numele resurselor din
cadrul fisierului. Dupa adaugarea elementelor din cadrul fisierului, se pot specifica
valori ale sirurilor de caractere resursa sau imaginile care vor fi adaugate in cadrul
resurselor de imagini. In final, fisierele pot fi salvate ca fisiere binare de tip .resources
sau fisiere XML de tip .resx.
Odata create, fisierele .resources sau .resx pot fi adaugate la proiect din meniul
Project, optiunea Add Existing Item si selectand apoi fisierul resursa dorit. Executand
Build, resursele vor fi partajate corespunzator in cadrul proiectului.
Crearea assembly-urilor de resurse
Pot fi create assembly-uri care contin numai resurse. Acest lucru este util in situatia in
care este necesara modificarea datelor continute in fisiere resursa fara a recompila
aplicatia pentru modificarea efectiva a acestora.
Un assembly de tip resursa se poate crea prin adaugarea de fisiere resursa la un
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
proiect vid. Atunci cand se va executa build, resursele vor fi compilate intr-un assembly
comun care va putea fi apoi referentiat si accesat.
Crearea unui assembly satelit
La crearea aplicatiilor internationalizate, este necesara furnizarea diferitelor multimi de
resurse pentru culturile utilizate in aplicatie. Assembly-urile satelit permit acestor
multimi de resurse sa fie incarcate automat, pe baza setarii CurrentUICulture pentru
firul de executie curent.
Pentru a fi incorporata intr-un assembly satelit, un fisier resursa trebuie sa se supuna
unei scheme specifice de nume, bazata pe cultura pentru care a fost proiectat. Numele
unui fisier resursa specific unei culturi este similar numelui fisierului resursa pentru
cultura invarianta, avand inserat, in plus, codul culturii respective intre numele de baza
si extensie. Deci, daca exista un fisier de resurse fileResources.resx, un fisier resursa
care va contine resurse pentru cultura neutra fr (Franta) va avea numele
fileResources.fr.resx. Pentru culturi specifice, un exemplu ar putea fi:
anotherFileResources.en-CA.resx.
Dupa adaugare, Visual Studio .NET va compila aceste fisiere resursa alternative in
assembly-uri satelit, creandu-se o structura de directoare asociata. La run-time,
resursele specifice culturii curente vor fi localizate automat de catre common language
runtime.
Interogarea resurselor la run-time
La run-time, se poate utiliza clasa ResourceManager pentru a returna resursele
partajate. Un ResourceManager gestioneaza accesul si interogarea resurselor
partajate in assembly. Fiecare instanta a clasei ResourceManager este asociata cu un
assembly care contine resurse.
Un ResourceManager se poate crea prin specificarea a doi parametri: numele de baza
al fisierului resursa si assembly-ul in care se gaseste acest fisier. Noul
ResourceManager va fi dedicat fisierului resursa specificat. Numele de baza specificat
este numele spatiului de nume care contine fisierul, urmat de numele fisierului, fara a
specifica extensiile. De exemplu, un fisier resursa denumit fileResources.de-DE.resx
intr-un spatiu de nume Namespace1 va avea numele de baza
Namespace1.fileResources.
Al doilea parametru refera assembly-ul in care este localizat fisierul resursa. Daca
assembly-ul care contine resursele este acelasi assembly care contine obiectul in
cadrul caruia de creaza ResourceManager-ul, se poate obtine o referinta la assembly
utilizand tipul obiectului respectiv. De exemplu:
// crearea unui ResourceManager pentru
// a accesa fisiere resursa dintr-un fisier partajat
// myResources.resx
// intr-un namespace myNamespace si acelasi assembly in care
// se gaseste obiectul curent
// se utilizeaza System.Resources
Page 160 of 203
ibm.com/developerWorks
ibm.com/developerWorks
fiecare proiect are propria sa copie a DLL-ului, acesta fiind, deci, un assembly privat.
Pentru ca mai multe aplicatii sa partajeze un assembly, acesta trebuie instalat in Global
Assembly Cache. Avantaje:
- locatie partajata
- securitate (assembly-ul este instalat in directorul sisteului de operare)
- versionare (pot fi instalate mai multe versiuni ale aceluiasi assembly
Partajarea unui assembly si instalarea in Global Assembly Cache implica semnarea
assembly-ului cu un strong name.
Strong Naming
Un strong name este un nume care garanteaza identitatea assembly-ului. Acesta
contine informatii despre assembly, cum ar fi numele, numarul versiunii, informatia
legata de cultura si o pereche de chei publica/privata. Aceste informatii sunt incriptate
utilizand cheia privata si pot fi decriptate folosind cheia publica. Dezvoltatorul aplicatiei
este singurul care detine cheia privata, ceea cea determina securitatea aplicatiei.
O pereche de chei poate fi generata prin intermediul aplicatiei sn.exe (strong name).
Un fisier care contine astfel de chei are extensia .snk. Exemplu:
sn k myKey.snk
Pentru a semna un assembly cu un strong name: - se deschide fisierul AssemblyInfo
din cadrul proiectului
- se verifica numarul versiunii assembly-ului:
[assembly: AssemblyVersion("1.0.1.1")]
- se specifica fisierul care contine cheile de criptare. Exemplu:
[assembly: AssemblyKeyFile("..\\..\\myKey.snk")]
Se executa build. Strong name-ul va fi generat si aplicat assembly-ului.
Instalarea in Global Assembly Cache
Se utilizeaza aplicatia Global Assembly Cache utility (gacutil.exe):
gacutil /i mypath\myAssembly.dll
Sinteza:
- assembly - manifest, tipuri de date, fisiere de cod si reurse
- assembly-uri de tip biblioteca de clase
- resurse
- assembly-uri de resurse
- resurse asociate culturilor
Page 162 of 203
ibm.com/developerWorks
- clasa ResourceManager
- assembly-uri private si partajate
- Global Assembly Cache
- strong name
- aplicatiile sn.exe si gacutil.exe
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
3. Securitatea aplicatiilor
Securitate inseamna protectie. Pot fi utilizate facilitatile de securitate puse la dispozitie
de .NET Framework pentru a proteja codul aplicatiilor fata de utilizatori neautorizati si
pentru a proteja sistemul in cazul utilizarii neautorizate a anumitor fragmente de cod.
Administratorul sistemului seteaza politica de securitate a sistemului. Acesta decide
tipurile de cod care vor putea fi utilizate de o masina, daca un anumit assembly poate fi
rulat pe o masina, s.am.d. Politica de securitate setata de administratorul sistemului nu
poate fi suprascrisa in cod: ea confera cel mai inalt nivel de securitate pe o anumita
ibm.com/developerWorks
masina.
Permisiuni
O permisiune este un obiect care reprezinta un utilizator, o identitate sau o resursa
(cod). Obiectele de tip permisiune sunt utilizate intr-o varietate de functii legate de
securitate.
Interfata IPermission
Orice permisiune de securitate in .NET Framework trebuie sa implementeze interfata
IPermission, care contine un nivel de functionalitate comun tuturor obiectelor de
securitate deci, arareori va fi necesara o implementare efectiva a acestei interfete.
Metodele membre ale interfetei IPermission sunt descrise in continuare:
* Copy - creaza si returneaza o copie identica a permisiunii
* Demand - parcurge stiva de apeluri si arunca o exceptie de tipul SecurityException
daca un apelant de pe stiva nu are permisiunea sa execute apelul respectiv
* Intersect - creaza si returneaza o permisiune care reprezinta intersectia a doua
permisiuni
* IsSubsetOf - determina daca permisiunea curenta este un subset al unei permisiuni
specificate
* Union - creaza o permisiune care reprezinta reuniunea permisiunii curente cu o alta
permisiune specificata.
Configurarea autorizarilor bazate pe roluri
Securitatea role-based reprezinta garantarea sau blocarea accesului la o aplicatie sau
resursa pe baza unei identitati sau rol al unui utilizator. De exemplu, sa presupunem ca
pentru o aplicatie utilizata in mediu universitar, numai profesorii vor avea acces la o
anumita sectiune a aplicatiei. Autorizarea bazata pe roluri implementeaza securitatea
de acest tip.
Clasa Principal
In .NET Framework, utilizatorii care se autentifica sunt reprezentati de obiecte
Principal. Acestea contin informatii despre identitatea sau rolul utilizatorului si poate fi
folosit pentru validarea identitatii fata de un obiect PrincipalPermission, utilizat pentru a
proteja partile sensibile ale unei aplicatii fata de utilizatori neautorizati.
Exemplu de implementare a unui model de securitate built-in:
// WindowsPrincipal reprezinta identitatea
// utilizatorului curent
AppDomain.CurrentDomain.SetPrincipalPolicy
(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal contine o referinta la un obiect WindowsIdentity care reprezinta
ibm.com/developerWorks
ibm.com/developerWorks
Permission3 =
(PrincipalPermission)Permission2.Union(Permission1);
// John sau Smith vor putea accesa codul programului
Permission3.Demand();
La crearea unui obiect PrincipalPermission, se poate specifica null pentru nume sau
rol. Aceasta permite crearea unei permisiuni care valideaza numai numele sau numai
rolul permisiunii. Exemplu: validarea rolului obiectului CurrentPrincipal (fara validarea
numelui):
// utilizatorul trebuie sa aiba rol de manager
PrincipalPermission myPermission = new
PrincipalPermission(null, "Manager");
Intersectia a doua permisiuni:
PrincipalPermission Permission1 = new PrincipalPermission(null,
"Manager");
PrincipalPermission Permission2 = new
PrincipalPermission("John",
null);
PrincipalPermission Permission3;
// intersectia permisiunilor
// Permission1 si Permission2
Permission3 =
(PrincipalPermission)Permission2.Intersect(Permission1);
// Principal-ul care acceseaza acest cod trebuie sa fie John
// cu rol de manager
Permission3.Demand();
Verificarea apartenentei utilizatorilor la roluri stabilite de sistemul de operare:
// se utilizeaza sintaxa cu doua backslash-uri (\\)
PrincipalPermission myPermission = new
PrincipalPermission("John", "BUILTIN\\Administrators");
Securitate role-based declarativa (in cadrul manifestului assembly-ului)
Orice obiect Permission are un atribut corespunzator. Aceste atribute pot fi atasate
claselor si/sau membrilor si sunt utilizate pentru a controla accesul la aceste clase si
membri. In contextul securitatii declarative, atributele de permisiune sunt atasate
membrilor protejati. Administratorul poate lua o decizie care sa permita executia
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
ibm.com/developerWorks
* Utilizand Visual Studio .NET, se pot crea Windows Installer setup projects sau
Windows Installer merge modules. Un proiect de setup poate fi executat pe un
calculator care are instalat Windows Installer 1.5 si care contine toata informatia
necesara instalarii unei aplicatii pe un calculator client. Un merge module este utilizat
pentru impachetarea fisierelor DLL si nu poate fi instalat aparte, ci numai prin
concatenare la un proiect de setup.
Setup Project Wizard permite crearea unui proiect de setup care poate fi apoi,
eventual, configurat intr-un mediu integrat de dezvoltare (IDE). Pentru a asocia un
proiect de setup unei aplicatii, se selecteaza meniul File, Add Project, New Project,
Setup And Deployment Projects, Setup Project Wizard. Se creaza astfel un proiect de
setup, specificandu-se tipul outputului proiectului si alte fisiere aditionale care vor fi
adaugate la proiect.
* Pot fi configurate proprietatile de Build ale proiectului, utilizand Setup Property Pages.
Se poate specifica modalitatea de impachetare a fisierelor, setarile de compresie, daca
se va crea sau nu un bootstrapper, directorul de instalare si setarile Authenticode
(referitoare la semnatura aplicatiei).
- Output File Name: reprezinta locatia in care va fi plasat fisierul de instalare rezultat in
ultima construirii proiectului de setup. Acest fisier are extensia .msi, in cazul aplicatiilor
Windows Installer si .msm, pentru Windows Installer merge modules.
- gruparea si compresia fisierelor - se pot utiliza fisiere de tip Cabinet (.cab), pentru
integrarea fisierelor de instalare in fisiere de o anumita dimensiune (de exemplu,
salvarea fisierelor de instalare in fisiere .cab de dimensiune 1.44M)
- optiunea Bootstrapper - se selecteaza in cazul in care pe masina pe care se va
instala proiectul nu exista Windows Installer 1.5, avand ca efect instalarea acestui
program, adaugand la proiectul de instalare 4 fisiere aditionale: Setup.exe,
InstMsiA.exe, InstMsiW.exe si Setup.ini.
* Dupa ce proiectul de instalare a fost construit, poate fi distribuit intr-o varietate de
moduri: cd-uri, dvd-uri, dischete, prin retea, pe web etc.
Aplicatiile de tip setup prezinta un nivel inalt de configurabilitate. Pot fi setate
proprietatile care furnizeaza informatii legate de originea aplicatiei care va fi instalate si
comportamentul aplicatiei la design-time, in fereastra Properties.
proprietate Register ofera posibilitatea inregistrarii unei componente COM sau a unui
font pe durata instalarii aplicatiei
File System Editor permite editarea sistemului de fisiere de pe masina pe care se
instaleaza aplicatia (target)
Registry Editor permite adaugarea/editarea intrarilor din registrii masinii target
File Types Editor permite crearea asocierilor dintre fisiere si programe de pe masina
target (exemplu: specificarea programului care va deschide implicit fisiere de tip .wav
- Winamp, Media Player etc).
User Interface Editor faciliteaza personalizarea interfetei programului de instalare
Custom Actions Editor permite stabilirea unor actiuni personalizate pe durata
instalarii (fragmente de cod care se vor executa ca raspuns la anumite evenimente
lansate pe durata instalarii)
Launch Conditions Editor permite adaugarea de criterii/conditii de cautare si executie
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
(conditiile sunt impuse masinii target, se pot cauta fisiere, intrari in registri sau
componente Windows Installer; in functie de respectarea conditiilor impuse si/sau
rezultatele cautarii, se permite sau nu executia anumitor actiuni la instalare)
utilitarul Ngen.exe permite crearea unei imagini native a aplicatiei/assembly-ului (la
jit-compilare, fisierele sunt compilate in cod nativ, ceea ce permite maximum de
eficienta, viteza si utilizare a resurselor; Ngen.exe creaza o imagine nativa a
aplicatiei, ceea ce duce la posibilitatea obtinerii acestor avantaje)
utilitarul Permview.exe permite vizualizarea permisiunilor asociate unui assembly
ibm.com/developerWorks
ibm.com/developerWorks
XML si .Net .Net Framework pune la dispozitia programatorilor un set de clase pentru
manipularea documentelor XML. Aceste clase se afla, in marea lor majoritate, in spatiul
de nume System.Xml.
Principalele clase din System.Xml sunt:
* XmlTextReader - permite accesul rapid, forward only, la continutul unui document
XML;
* XmlNodeReader - clasa care furnizeaza un XmlReader pentru un subarbore DOM;
* XmlValidatingReader - permite validarea documentelor XML folosind scheme DTD,
XSD si XDR;
* XmlTextWriter - clasa folosita pentru generarea de documente XML;
* XmlDocument - clasa care implementeaza specificatiile DOM
* XmlDataDocument - furnizeaza o implementare a unui XmlDocument care poate fi
asociat cu un DataSet. Acest document poate fi apoi manipulat folosind atat
reprezentarea relationala furnizata de DataSet, cat si reprezentarea sub forma de
arbore a unui XmlDataDocument;
* XPathDocument - permite procesari XSLT rapide asupra unui document XML;
* XslTransform - permite transformari XSLT asupra unui document XML;
* XmlSchema - permite crearea, pe durata rularii programului, a schemelor XSD,
respectand specificatiile W3C XSD;
* XmlSchemaCollection - furnizeaza o multime de scheme XSD si XDR (XMl Data
Reduced). Aceste scheme, incarcate in memorie, permit o validare rapida pe durata
parsarii pentru XmlValidatingReader.
Citirea unui fisier XML
Clasa XmlReader furnizeaza un API (Application Program Interface) pentru parsarea
documentelor XML. O implementare a acestei clase este XmlTextReader. De obicei,
se foloseste XmlTextReader daca se doreste accesul rapid la un document XML, fara
overheadul introdus de construirea arborelui DOM.
XmlTextReader reader = new XmlTextReader ("books.xml");
In exemplul anterior, documentul XML este incarcat dintr-un fisier. XmlTextReader
furnizeaza constructori si pentru incarcarea din stream-uri. Un stream este o
reprezentare abstracta a unui dispozitiv de intrare/iesire, care este sursa sau destinatia
datelor. Un stream este independent de dispozitivul din care citeste/scrie astfel nct
programul nu necesita modificari daca sursa streamului se schimba. In exemplul
urmator este prezentata metoda de incarcare a unui document XML dintr-un stream:
StringReader stream;
XmlTextReader reader = null;
try
{
ibm.com/developerWorks
ibm.com/developerWorks
}
}
Valoarea intoarsa de NodeType depinde de clasa care este utilizata. De exemplu,
XmlTextReader nu intoarce niciodata XmlNodeType care reprezinta un nod Document,
DocumentFragment, Entity, EndEntity sau Notation. Tipul continut de NodeType este
conform specificatiilor W3C DOM. Proprietatea Depth intoarce nivelul nodului curent in
arborele Xml. Aceste informatii sunt utilizate in formatarea unui document XML. Nodul
radacina are Depth = 0. Combinand informatiile furnizate de proprietatile Name, Value
si Depth, se poate executa scrierea formatata a unui document XML la consola sau
intr-un fisier.
Sinteza:
- XmlTextReader furnizeaza acces rapid, forward only, la continutul XML;
- XmlTextReader implementeaza specificatiile W3C;
- XmlTextReader furnizeaza constructori pentru citirea unui document XML dintr-un
fisier, stream sau XmlReader;
- metoda Read citeste secvential toate nodurile din documentul XML;
- pentru nodurile element, atributele pot fi obtinute folosind metoda
MoveToNextAttribute(), ceea ce furnizeaza tot o citire secventiala a atributelor;
- atributele sunt reprezentate ca o lista atasata nodului curent;
Scrierea unui fisier XML
Pentru scrierea unui document XML, se folosesc clase derivate din XmlWriter.
XmlWriter furnizeaza un API care permite scrierea intr-un fisier, intr-un stream sau
intr-un TextWriter. O clasa derivata din XmlWriter este XmlTextWriter. XmlTextWriter
nu construieste arborele DOM, furnizand astfel un acces rapid la output (fisier, stream,
etc) si inlaturand overhead-ul introdus de arborele DOM. Aceasta clasa executa o serie
de verificari si validari ale documentului xml, pentru a asigura structura corecta a
documentului care este scris. Atunci can una din aceste validari esueaza (documentul
nu este un document xml valid), se arunca o exceptie, fiind recomandata specificarea
de handleri care sa trateze aceste exceptii.
XmlTextWriter myXmlTextWriter = new XmlTextWriter ("books.xml",
null);
Cel de-al doilea parametru al contructorului precizeaza care este encoding-ul fisierului.
Daca acesta este null, se considera ca fisierul este scris in format UTF-8 . Exemplul
urmator demonstreaza modul in care poate fi scris un singur element (book) intr-un
fisier xml:
myXmlTextWriter.Formatting = System.Xml.Formatting.Indented;
myXmlTextWriter.WriteStartDocument(false);
myXmlTextWriter.WriteDocType("bookstore", nothing, "books.dtd",
nothing);
myXmlTextWriter.WriteComment("Cartile lui Mark Twain");
Page 180 of 203
ibm.com/developerWorks
myXmlTextWriter.WriteStartElement("bookstore");
myXmlTextWriter.WriteStartElement("book", null);
myXmlTextWriter.WriteAttributeString("genre","autobiography");
myXmlTextWriter.WriteAttributeString("publicationdate","1979");
myXmlTextWriter.WriteAttributeString("ISBN","0-7356-0562-9");
myXmlTextWriter.WriteElementString("title", null, "The
Autobiography of Mark Twain");
myXmlTextWriter.WriteStartElement("Author", null);
myXmlTextWriter.WriteElementString("first-name", "Mark");
myXmlTextWriter.WriteElementString("last-name", "Twain");
myXmlTextWriter.WriteEndElement();
myXmlTextWriter.WriteElementString("price", "7.99");
myXmlTextWriter.WriteEndElement();
myXmlTextWriter.WriteEndElement();
//Scrie tot textul XML si inchide fisierul
myXmlTextWriter.Flush();
myXmlTextWriter.Close();
Scrierea diverselor elemente ale unui document xml se face folosind functii
specializate: WriteDocType, WriteComment, WriteStartElement, WriteAttributeString,
WriteElementString, WriteEndElement, etc. Se observa ca exista o corespondenta intre
apelul functiilor WriteStart... si apelul functiilor WriteEnd....
Sinteza
- XmlTextWriter permite scrierea de documente XML care respecta specificatiile W3C;
- XmlTextWriter are constructori care permit scrierea intr-un fisier, stream sau
TextWriter;
- pentru fiecare tip de nod exista o functie permite scrierea acestuia.
Validarea unui document XML in timpul citirii
Utilizand clasa XmlValidatingReader se poate face validarea unui document XML in
timpul citirii sale. Validarea se poate face conform definitiilor dintr-un fisier DTD, XSD
sau XDR. Pentru a specifica exact tipul de validare se foloseste proprietatea
ValidationType, astfel (tip de validare - descriere): - Auto: implicit
- None: nu se face validare in timpul parsarii
- DTD: validare conforma definitiilor DTD
- Schema: validare conform definitiilor XSD
- XDR: validare conform definitiilor XDR
ibm.com/developerWorks
Exemplu:
XmlTextReader myXmlTextReader = new XmlTextReader (document1);
XmlValidatingReader myXmlValidatingReader = new
XmlValidatingReader(myXmlTextReader);
myXmlValidatingReader.ValidationType = ValidationType.DTD;
Parserul nu se opreste la erorile de validare, ci in cazul in care documentul XML nu
este bine format (nu respecta standardul XML). Datorita acestui fapt este permisa
detectarea tuturor erorilor de validare printr-o singura parsare, si nu este necesara
reparsarea documentului. In exemplul urmator este prezentat modul in care este
apelata o metoda handler atunci cnd se intalneste o eroare la validare. Atasarea
acestui handler se face folosind clasa ValidationEventHandler inainte de a incepe
citirea documentului XML. Daca nu este furnizat un astfel de handler,
XmlValidatingReader arunca o exceptie de tipul XmlSchemaException atunci cand se
intalneste prima eroare.
private void Validate ()
{
try
{
// setarea handler-ului pentru erorile la validare
myXmlValidatingReader.ValidationEventHandler += new
ValidationEventHandler (ValidationEvent);
while (myXmlValidatingReader.Read())
{
// instructiuni...
}
}
catch (Exception e)
{
Console.WriteLine ("Exception: {0} ", e.ToString());
}
}
private void ValidationEvent (object, errorID,
ValidationEventArgs) args)
{
Console.Write ("Eroare la validare: " + args.Message);
Page 182 of 203
ibm.com/developerWorks
}
Sinteza:
- validarea poate fi efectuata folosind scheme DTD, XSD si XDR
- validarea are loc pe durata efectuarii operatiilor de citire si parsare
- handlerul ValidationEventHandler trebuie initializat pentru a primi toate notificarile
legate de erorile de validare aparute
- erorile de validare nu stopeaza parsarea documentului XML
2. Servicii Web
Introducere...
XML Web services reprezinta componente program care permit construirea de aplicatii
scalabile, independente de platforma. Serviciile Web permit aplicatiilor sa interschimbe
mesaje utilizand protocoale standard cum ar fi HTTP, XML, XSD, SOAP si WSDL.
Pot fi create servicii web care sa ofere functionalitati specifice aplicatiilor client pe web.
Mediul de dezvoltare integrat Visual Studio .NET ofera posibilitatea crearii de proiecte
pentru aplicatii desktop distribuite, aplicatii Web applications si servicii XML Web.
Dupa crearea unui serviciu Web, acesta trebuie instalat pe un server Web pentru a
deveni disponibil aplicatiilor care doresc sa utilizeze acest serviciu. Instalarea unui
serviciu Web pe un Web server se poate realiza prin copierea fisierelor asociate pe
serverul Web.
Mecanismul de descoperire a serviciilor XML Web permite aplicatiilor client sa
localizeze documentele care descriu unserviciu XML Web service. Se returneaza,
astfel, catre client, un document care descrie serviciul web. Acest document este scris
in WSDL (Web Service Description Language) si contine informatii despre capabilitatile
serviciului XML Web, locatia si modalitatea in care se poate interactiona cu acesta.
Dupa crearea si instalarea unui serviciu XML Web, orice aplicatie va avea, teoretic,
permisiunea de a accesa si consuma servicul respectiv. Aplicatia care consuma un
serviciu Web este cunoscuta sub numele de client al serviciului Web. Un client poate fi
o componenta, serviciu sau o aplicatie desktop.
Crearea unui serviciu web in Visual Studio .NET
Crearea unu serviciu web este foarte usoara. De fapt, folosind Visual Studio se poate
crea un serviciu web fara sa fie necesara scrierea de cod. Exemplul urmator va crea un
serviciu web numit MyService, in directorul WebServices.
La crearea proiectului, se alege ca optiune Web Service. Va fi creat un nou
namespace, numit MyService, si cateva clase care vor oferi functionalitatea serviciului
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
web.
Implicit sunt create urmatoarele clase:
- Global (in fisierul Global.asax) - derivata din HttpApplication (acest fisier este
echivalent cu fisierul Global.asa din ASP)
- WebService1 (in fisierul WebService1.cs) - clasa derivata din
System.Web.Services.WebService; aceasta este clasa care implementeaza logica
serviciului web care urmeaza a fi realizat. Metodele din aceasta clasa vor fi apelate
ulterior. Componenta webservice va fi creata in directorul bin si se va numi
MyService.dll. Initial, clasa creata de Visual Studio .Net arata astfel:
namespace MyService
{
...
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace="http://tempuri.org",
Description="This is a demonstration WebService.")]
public class WebService1 : System.Web.Services.WebService
{
public WebService1()
{
//CODEGEN: This call is required by the ASP+ Web Services
Designer
InitializeComponent();
}
...
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
Implicit este creata si o metoda HelloWorld (comentata). Daca se decomenteaza
aceasta metoda avem un prim serviciu web functional (care va afisa un simplu mesaj).
Page 184 of 203
ibm.com/developerWorks
ibm.com/developerWorks
intervalul 0-10, se va obtine un vector nul. Introducand o valoare intre 0-10 se va obtine
un xml cu elemente de tipul:
<clientData>
<Name>Client 0</Name>
<ID>0</ID>
</clientData>
Crearea unui serviciu web folosind Visual Studio .Net este o operatie relativ facila, cu
un grad mare de utilitate.
ibm.com/developerWorks
ibm.com/developerWorks
aplicatii (Application) s.a.m.d.. Mai nou, din partea PHP-ului, incepand cu versiunea
4.0, acesta ofera suport pentru programarea obiectuala: incapsularea datelor,
mostenirea si polimorfismul. Aceste modele completeaza destul de bine suportul
dezvoltarii aplicatiilor Web, insa aduc unele limitari: sunt lente deoarece la fiecare
accesare fisierele sunt procesate si interpretate (in loc sa fie compilate), nu sunt
capabile sa construiasca controale reutilizabile care sa incapsuleze functionalitati
complexe pentru interactiunea cu utilizatorul.
* JSP (JavaServer Pages) face parte din familia Java si reprezinta o tehnologie care
permite crearea de aplicatii Web independente de platforma. JSP separa interfata
utilizator de continutul generat dinamic permitand schimbarea intregului sablon al
site-ului WEB fara a altera informatiile afisate. Tehnologia utilizeaza marcatori XML si
scripturi scrise in limbajul de programare Java pentru a incapsula logica aplicatiei care
genereaza continutul paginilor WEB. JSP-urile sunt o extensie a tehnologiei Java
Servlet. Servlet-urile sunt independente de platforma 100% si reprezinta module la
nivel de server care se integreaza in cadrul unei aplicatii Web si care pot fi utilizate
pentru a extinde capabilitatile unui server WEB. Tehnologia JSP si servlet-urile ofera o
alternativa pentru crearea aplicatiilor WEB fata de alte limbaje de scripting/programare
a aplicatiilor WEB, oferind independenta de platforma, performanta, separarea logicii
aplicatiei de partea de interfata utilizator, administrare usoara si extensibilitate.
Astfel, odata cu aparitia noii platforme .NET, Microsoft a adus o noua tehnologie in
programarea si dezvoltarea aplicatiilor dinamice pentru Web, si anume, ASP.NET. Desi
nu putem spune clar ca ASP.NET este o versiune urmatoare a ASP-ului, acesta
pastreaza compatibilitatea cu aplicatiile scrise in ASP.
ibm.com/developerWorks
ibm.com/developerWorks
Modelul de executie
Modelul de executie al paginilor .aspx este format din mai multe etape, pornind de la
cererea clientului pana la procesul executat de server. Vom observa ca viteza de
raspuns a unei cereri este optimizata dupa prima accesare.
La prima accesare a unei pagini .aspx, procesul de raspuns al serverului ASP.NET
este alcatuit din mai multi pasi. Acestia sunt:
- procesarea si interpretarea codului sursa
- trimiterea acestuia compilatorului
- ASP.NET invoca compilatorul in urma caruia rezulta unul sau mai multe assembly-uri
(cod intermediar-IL), plasat apoi in assembly cache
- mediul de executie incarca in memorie si executa codul intermediar, iar rezultatul este
trimis la client
Elementele constitutive ale unui WebForm
O pagina WebForms contine un numar de comenzi denumite directive la nivel de
pagina care pot fi stocate in fisierele .aspx. Aceste directive au sintaxa @ <nume
directiva> si sunt incadrate de simbolurile <% si %> (reminiscenta ASP), pozitia lor
fiind la inceputul paginii .aspx. Rolul lor este de a specifica anumite configuratii cand
este procesata o pagina WebForms.
Paginile WebForms suporta urmatoarele directive:
@ Page - defineste atribute specifice paginii WebForms care sunt utilizate de analizor
si compilator (doar pentru fisiere .aspx).
@ Control - defineste atribute specifice controalelor utilizator care sunt utilizate de
analizor si compilator (doar pentru fisiere .ascx).
@ Import - importa un spatiu de nume explicit intr-o pagina sau control utilizator.
@ Implements - indica unei pagini sau control utilizator ca implementeaza o interfata
specifica .NET Framework.
@ Register - inregistreaza controale utilizator si controale obisnuite pentru a fi utilizate
intr-un WebForms.
@ Assembly - creeaza legaturi catre assembly-uri in timpul compilarii, facand
disponibile clasele si interfetele din assembly-uri pentru a fi folosite in pagina.
@ OutputCache - declara politici de caching pentru controale dintr-o pagina sau user
control.
@ Reference - adauga referinte catre un fisier .aspx sau .ascx extern.
Ciclul de viata al unei pagini WebForms
Intr-o aplicatie Web, datorita naturii protocolului HTTP, procesul in care un browser
acceseaza o resursa Web se rezuma la urmatorii pasi:
* se stabileste o legatura cu serverul Web care primeste cererea resursei;
ibm.com/developerWorks
3. Controale
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
Controale server
Unul din aspectele care vor duce la o dezvoltare rapida a interfetelor utilizator pentru
paginile WebForms il reprezinta controalele server. Putem prognoza un viitor
asemanator evolutiei componentelor COM. Controalele server sunt folosite pentru a
crea interfata-utilizator in paginile WebForms. Caracteristicile acestora pot fi rezumate
astfel: expun un model orientat obiect, incapsuleaza un mecanism de persistenta a
starilor intre round-trip-uri, genereaza evenimente client care sunt tratate la server, la
executie genereza cod compatibil browser-ului sau dispozitivului destinat (detectat in
mod automat).
Exista doua tipuri de baza in care pot fi impartite controalele:
* HTML Controls, reprezinta elemente HTML care pot fi programate la nivelul serverului
si expun un model obiectual restrictionat la capabilitatile elementelor HTML pe care le
afiseaza;
* Web Controls, aduc facilitati superioare controalelor HTML incluzand controale mult
mai complexe, cum ar fi controlul calendar, iar modelul obiect nu reflecta neaparat
sintaxa HTML.
Prin extensie, se definesc alte doua tipuri de controale, si anume:
- controale de validare incapsuleaza functionalitati care permit validarea intrarilor
utilizatorului. Acestea se ataseaza controalelor de intrare ale utilizatorului si furnizeaza
mai multe tipuri de verificari ale datelor. Functionalitatea controalelor de validare poate
fi dedusa usor din numele claselor de care sunt reprezentate: CompareValidator,
CustomValidator, RangeValidator, RegularExpressionValidator,
RequiredFieldValidator. - controale utilizator sunt similare paginilor WebForms, diferind
de acestea prin faptul ca fisierele au extensia .ascx si nu contin tagurile <HTML>,
<BODY>, <FORM>, aceste elemente aflandu-se in pagina gazda.
Controale HTML
Primul set de controale, HTML Controls, reprezinta elemente HTML care contin
atribute facand posibila programarea lor pe server. Fiecare element HTML poate fi
programat pe server prin adaugarea atributului runat="server" si asignarea unui atribut
ID pentru a putea fi referit controlul ca membru de clasa in codul de pe server (aceasta
abordare este posibila si la ASP). Acest ID trebuie sa fie unic in cadrul paginii Web
pentru a nu aparea conflicte de nume in tratarea lor pe server. Controalele HTML sunt
instante ale claselor definite in spatiul de nume System.Web.UI.HtmlControls si sunt
derivate direct/indirect din clasa de baza HtmlControl.
De exemplu, urmatorul cod creeaza un control de editare text care este reprezentat la
runtime de clasa System.Web.UI.HtmlControls.HtmlInputText:
ASP.NET furnizeaza controale HTML predefinite, de la formulare pana la controale
pentru introducerea de informatii text pe una sau mai multe linii, de la checkbox-uri
pana la controale de selectie, butoane de tip submit, list box-uri, tabele, imagini si alte
controale corespunzatoare elementelor HTML.
Cand un WebForms continand controale HTML este procesat pe server, se creeaza
cate o instanta pentru fiecare control, iar atributele acestora devin proprietati ale
claselor corespunzatoare. Atributele nerecunoscute sunt ignorate, dar sunt accesibile
Page 192 of 203
ibm.com/developerWorks
Control HTML
corespunzator
<a runat="server">
HtmlAnchor
<button runat="server">
HtmlButton
<form runat="server">
HtmlForm
<img runat="server">
HtmlImage
HtmlInputButton
HtmlInputButton
HtmlInputButton
HtmlInputCheckBox
HtmlInputFile
HtmlInputHidden
HtmlInputImage
HtmlInputRadioButton
HtmlInputText
HtmlInputText
<select runat="server">
HtmlSelect
<table runat="server">
HtmlTable
<td runat="server">
HtmlTableCell
<th runat="server">
HtmlTableCell
<tr runat="server">
HtmlTableRow
<textarea runat="server">
HtmlTextArea
HtmlGenericControl
ibm.com/developerWorks
Label
Folosita pentru a afisa text static sau text conectat la o sursa de date in pagina:
<asp:Label runat="server" Text="un text" Font-Italic="true"
Font-Name="Arial" Font-Size="12"></asp:Label>
TextBox
Permite editarea textului folosind mai multe moduri de utilizare prin proprietatea
TextMode (implicit SingleLine): editare pe o singura linie, pe linii multiple si pentru
introducerea unei parole:
<asp:TextBox runat="server" id="email" Text="exemplu:
utilizator@domeniu.ro" Font-Name="Tahoma" Width="200px"/>
<asp:TextBox runat="server" id="adresa" Font-Name="Tahoma"
TextMode="Multiline" Rows="3">str., bl., apt...</asp:TextBox>
<asp:TextBox runat="server" id="parola" TextMode="Password"
Page 194 of 203
ibm.com/developerWorks
Width="200px"/>
CheckBox
Creeaza o caseta de marcare care permite selectarea unei stari true sau false. Pentru
utilizarea mai multor controale CheckBox exista alternativa controlului CheckBoxList cu
posibilitati de legare la o sursa de date. Se pot specifica formate de afisare folosind
proprietatile RepeatLayout si RepeatDirection.
<asp:CheckBox id="asigurat" runat="server" AutoPostBack="True"
Text="Asigurat medical" TextAlign="Right" />
Proprietatea AutoPostBack="True" este folosita pentru a trimite starea controlului pe
server imediat ce acesta a fost selectat/deselectat.
<asp:CheckBoxList id="checkboxlist1" CellPadding="5"
CellSpacing="5" RepeatColumns="2" RepeatDirection="Vertical"
RepeatLayout="Flow" TextAlign="Right" runat="server">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem>Optiunea 4</asp:ListItem>
</asp:CheckBoxList>
RadioButton
Ca si controlul CheckBox, acesta permite selectarea unui singur buton dintr-un grup
definit (excludere mutuala):
<asp:RadioButton runat="server" Text="Casatorit"
GroupName="StareCivila" />
<asp:RadioButton runat="server" Text="Necasatorit"
GroupName="StareCivila" Checked="true" />
RadioButtonList
Furnizeaza dezvoltatorului o singura selectie a unui buton radio dintr-un grup care
poate fi generat dinamic dintr-o sursa externa de date (de exemplu,. o baza de date).
<asp:RadioButtonList id=RadioButtonList1 runat="server"
RepeatLayout="Flow" RepeatColumns="2"
RepeatDirection="Horizontal">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem> Optiunea 4</asp:ListItem>
</asp:RadioButtonList>
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
DropDownList Este utilizata pentru selectarea unei optiuni dintr-un numar de optiuni
afisate ca o lista drop-down . Aceasta lista poate fi conectata la o sursa de date
externa.
<asp:DropDownList runat="server">
<asp:ListItem>Selecteaza 1</asp:ListItem>
<asp:ListItem>Selecteaza 2</asp:ListItem>
<asp:ListItem>Selecteaza 3</asp:ListItem>
</asp:DropDownList>
ListBox
Este folosit pentru a genera o lista cu bara de derulare din care se pot selecta una sau
mai multe optiuni.
<asp:ListBox runat="server" SelectionMode="Multiple">
<asp:ListItem>Optiunea 1</asp:ListItem>
<asp:ListItem>Optiunea 2</asp:ListItem>
<asp:ListItem>Optiunea 3</asp:ListItem>
<asp:ListItem>Optiunea 4</asp:ListItem>
<asp:ListItem>Optiunea 5</asp:ListItem>
<asp:ListItem>Optiunea 6</asp:ListItem>
</asp:ListBox>
Urmatoarele controale sunt utilizate pentru trimiterea informatiilor introduse in formular.
Atunci cand sunt apasate, continutul intregii pagini WebForms este trimis la serverul
Web. Acestea genereaza evenimentul Click la server care poate fi tratat in codul
programatorului.
Button
Creeaza un buton 3-D de submisie a unei pagini WebForms.
<asp:Button runat="server" Text="OK"></asp:Button>
LinkButton
Are aceeasi functionalitate ca a unui control Button, doar ca este afisat ca un hiperlink
in pagina.
<asp:LinkButton runat="server"
Text="Inregistrare"></asp:LinkButton>
HyperLink
Folosit pentru crearea unei legaturi catre un alt URL.
ibm.com/developerWorks
ibm.com/developerWorks
</asp:Table>
Calendar
Selectarea datei poate fi facuta acum mult mai elegant, solutie oferita de controlul
Calendar. Acesta permite afisarea unei singure luni, selectarea datei, trecerea de la o
luna la alta. Pune la dispozitia programatorului diferite proprietati pentru specificarea
stilului de afisare si a modului de selectare a datei. Folosind proprietatea
SelectionMode se poate specifica selectarea unei singure zile, a unei saptamani sau a
intregii luni. Controlul suporta toate tipurile de calendar definite in spatiul de nume
System.Globalization (Gregorian, Japonez, Korean, Hijri, Hebrew, Julian).
<asp:Calendar id="datai" runat="server" BackColor="LightGreen"
Font-Name="Verdana" Font-Size="10pt" />
La ora actuala, majoritatea aplicatiilor Web folosesc un sistem de gestiune al bazelor
de date in spatele aplicatiei. In sprijinul unei bune prezentari a acestor surse de date,
platforma .NET include un set de trei controale ce fac posibila afisarea unor mari
cantitati de date foarte usor. Sursa de date reprezinta o multime specifica de date care
poate fi reprezentata de un server de baze de date (MS SQL Server), un fisier XML
sau o colectie de date care implementeaza interfata System.Collections.IEnumerable.
Repeater
Reprezinta o simpla lista conectata la o sursa de date care foloseste sabloane pentru
afisarea informatiilor. Fara un sablon predefinit, programatorul este nevoit sa-si
defineasca propriul model de afisare folosind elemente HTML. In schimb, controlul este
singurul care ofera libertate maxima in definirea modului de afisare, a stilului si
formatarii.
<asp:Repeater runat="server" id="list1">
<HeaderTemplate> <ol> </HeaderTemplate>
<ItemTemplate>
<li><a href='mailto:<%# DataBinder.Eval(Container.DataItem,
"Email") %>'><%# DataBinder.Eval(Container.DataItem, "Nume")
%></a>
</li>
</ItemTemplate>
<FooterTemplate> </ol> </FooterTemplate>
</asp:Repeater>
DataList
In completarea unor functionalitati predefinite, controlul DataList afiseaza inregistrarile
unei surse de date folosind sabloane existente, dand posibilitatea totodata sa ne
definim propriile modele de afisare, sa selectam si sa editam articolele.
<asp:DataList id="list2" runat="server" BorderColor="black"
CellPadding="3" Font-Name="Verdana" Font-Size="8pt">
Page 198 of 203
ibm.com/developerWorks
4. Evenimente
Dezvoltare de aplicatii in Visual Studio .NET
ibm.com/developerWorks
5. Concluzii
Page 200 of 203
ibm.com/developerWorks
ASP.NET a fost dezvoltat pentru a lucra asemenea editoarelor WYSIWYG (What You
See Is What You Get) HTML, astfel mediul de dezvoltare Microsoft Visual Studio.NET
pe langa un GUI pe care dezvoltatorii il pot utiliza pentru a adauga controale server in
paginile WebForms, ofera suport integrat complet pentru depanarea aplicatiilor Web.
Tehnologia pe care platforma .NET o ofera prin ASP.NET, alaturi de limbajul C#, un
limbaj elegant si totodata performant, robust si productiv, va conduce la dezvoltarea
aplicatiilor Web complexe pentru organizatii mari, intreprinderi care vor putea
interopera folosindu-se de serviciile Web. ASP.NET, prin WebForms, imprumuta stilul
de programare Visual Basic folosind form-uri si evenimente si il transpune pe Web
oferind productivitate maxima in construirea aplicatiilor Web. Mai mult, modelul abstract
orientat pe obiecte al mediului ASP.NET va conduce la o dezvoltare rapida a
componentelor unei aplicatii Web, deci la aplicatii cu interfete utilizator bogate in
posibilitati de prezentare a informatiilor.
ibm.com/developerWorks
ibm.com/developerWorks
Descriere
1.
2.
3.
4.
5.
Colophon
This tutorial was written entirely in XML, using the developerWorks Toot-O-Matic tutorial
generator. The open source Toot-O-Matic tool is an XSLT style sheet and several XSLT
extension functions that convert an XML file into a number of HTML pages, a zip file, JPEG
heading graphics, and two PDF files. Our ability to generate multiple text and binary formats
from a single source file illustrates the power and flexibility of XML. (It also saves our
production team a great deal of time and effort.)
You can get the source code for the Toot-O-Matic at
www6.software.ibm.com/dl/devworks/dw-tootomatic-p. The tutorial Building tutorials with the
Toot-O-Matic demonstrates how to use the Toot-O-Matic to create your own tutorials.
developerWorks also hosts a forum devoted to the Toot-O-Matic; it's available at
www-105.ibm.com/developerworks/xml_df.nsf/AllViewTemplate?OpenForm&RestrictToCategory=11.
We'd love to know what you think about the tool.