Documente Academic
Documente Profesional
Documente Cultură
Figura 1: .NET Standard shared API şi infrastructura comună în .NET (sursa: MicroSoft)
Microsoft .NET 6 fost lansat în noiembrie 2021, în cadrul căruia cea mai mare îmbunătăţire adusă este
ASP.NET Core 6, o actualizare majoră a cadrului Microsoft în ceea ce priveşte construirea de aplicații
web moderne. ASP.NET Core 6 este construit pe .NET Core runtime și combină caracteristicile Web
API și MVC. In prezent, ultima versiune de .NET este .NET 7 care nu aduce modificări majore în
arhitectura .NET, concentrându-se în special pe performanţă.
1. Meniul File
• New – pentru a creea o soluţie nouă sau un proiect nou se poate utiliza meniul File//New – care va
deschide fereastra din care se va putea selecta opţiunea Create a new project. Aceasta va pune la
dispoziţie o fereastră cu toate tipurile de aplicaţii ce pot fi create, selecţia putându-se realiza grupate
după limbajul de programare dorit (C#, Visual Basic,...), platforma pe care rulează (Windows,
Linux,....) şi tipurile de proiecte (Console, Desktop,.... Pentru fiecare tip de proiect care se creaza
există posibilitatea de a selecta o machetă (template) şi astfel Visula Studio va şti ce fişiere trebuie
să genereze la crearea proiectului
• Open – este folosit pentru a deschide o soluţie sau aplicaţie existentă respectiv un fişier existent
(opţiunea File) etc.
• Add – folosit pentru adăugarea de proiecte (noi sau existente) la soluţia curentă
• Close – închide fişierul curent
• Close solution – închide soluţia curentă
• Save – salvează fişierul curent
• Save as – salvează fişierul curent sub un alt nume
• Save all – salvează toate fişierele deschise
• Page setup / Print – folosite pentru tipărire
• Recent Files / Recent Projects and solutions – lista cu ultimele fişiere şi proiecte selectate.
Figura 4 – Tipuri de proiecte în Visual Studio 2022 (template-uri)
2. Meniul View
• Solution explorer – fereastră folosită la gestionarea componentelor unei soluţii sau proiect.
• Server explorer – fereastra cu lista de conexiuni la baza de date precum şi serverele disponibile.
• Class View – fereastra cu ajutorul căreia se pot vizualiza clasele unui proiect
• Code Definition Window – afişează o fereastră cu definiţia pentru codul selectat
• Object Browser – fereastră care arată atît spaţiile de nume (namespace-urile) .NET precum şi cele
din soluţia curentă
• Error List – afişează lista de erori în urma compilării
• Output – afişează informaţiile trimise de către diferite componente ale IDE-ului (Integrated
Development Environment)
• Task List – conţine lista cu task-uri – acestea pot fi User task sau Comments, şi sunt generate în
urma inspecţiei codului sursă prin extragerea comentariilor TODO)
• Toolbox – conţine lista cu componente ce pot fi utilizate (aceasta listă se schimbă în funcţie de
fişierul curent deschis)
• Other Windows – meniu cu ferestre suplimentare
• Toolbars – afişează lista cu barele de unelete ce pot fi folosite
• Full screen – folosit pentru a mări IDE-ul pe tot ecranul
• Properties Window – fereastră cu proprietăţi (pentru toate elementele asociate unui proiect)
Figura 5: Meniul View
Visual Studio oferă posibilitatea grupării componentelor folosite (fişiere, directoare, conexiunile de baze
de date, fişiere sursă, …) utilizând proiecte. Acestea, la rândul lor, pot fi grupate folosind soluţii. Pentru
a gestiona toate componentele unui proiect se poate utiliza fereastra Solution Explorer care poate fi
deschisă selectând Solution Explorer din meniu View.
În Figura 6 este prezentată o fereastră Solution Explorer care conţine o soluţie cu 1 proiect.
De asemenea, structura de clase a unui proiect precum şi referinţele proiectului sunt vizibile cu ajutorul
ferestrei Class View (Figura 7). O altă fereastră deosebit de utilă în dezvoltarea aplicaţiilor Windows
este fereastra Toolbox (Figura 8).
Figura 7: Fereastra Class View Figura 8: Fereastra Toolbox
3. Meniul Project
• Add Class, Add New Item – deschid fereastra “Add New Item” – pentru clasă, cu template-
ul deja selectat
• Add New DataSource – permite adăugarea unei surse de date proiectului curent
• Add Existing Item – adăugă un obiect existent la proiectul curent
• Exclude From Project – elimină din proiect obiectul selectat ; acest lucru se poate realiza şi
prin meniul de contextual al obiectului respectiv (click dreapta)
• Show All Files – afişează toate fişierele şi directoarele proiectului curent
• Add Project Reference – deschide fereastra Reference Manager şi permite adăugarea unei
noi referinţe către un spaţiu de nume (namespace) în lista de referinţe a proiectului curent
• Set as StartUp Project – setează proiectul selectat ca proiect de start pentru soluţie, în caz că
soluţia conţine mai multe proiecte (mai mult de de 1 proiect)
• Properties – seteaza diferite proprietăţi ale proiectului curent
Figura 9: Adăugarea unei clase
4. Meniul Build
• Build Solution, Rebuild solution – compilează toate proiectele unei soluţii
• Clean Solution – şterge câteva din fişiere rezultate în urma compilării
• Batch Build – pentru proiectele mai mari, se pot compila doar o parte dintre proiecte folosind
meniul Batch Build.
5. Meniul Debug
Windows
Breakpoint – lista cu punctele de oprire folosit pentru a opri execuţia programului la o
anumită linie de cod.
Output – aceeaşi fereastră ca la meniul View (ieşirea programului)
Immediate – fereastră în care se poate introduce expresii pentru a fi evaluate
• Start Debugging (F5 sau opţiunea Start) – execută aplicaţia în mod depanare (debug)
• Start Without Debugging – execută aplicaţia; acest lucru se poate realiza si utilizand Start de pe
bara de unelte
• Attach to Process – deschide lista de proces de care se poate “agăţa” soluţia curentă.
• Step Into – execuţie pas cu pas: execută următoarea instrucţiune intrând în interiorul codului tuturor
funcţiilor apelate F11
• Step Over – execuţie pas cu pas: execută o funcţie ca o unitate după care trece la instrucţiunea
următoare F10
• New Breakpoint – crează un nou breakpoint; acest lucru se poate realiza si dând click în stânga
numărului liniei pe care se doreşţe să se aplice un breakpoint
6. Meniul Tools
Din acest meniu se pot lansa diferite unelte, se poate personaliza interfaţa mediului, se pot specifica
diferite opţiuni (legate de editor, de tab-urile de editare, de depanare, de compatibilitate, de compilare,
de directoare, de controlul surselor, de spaţiul de lucru, de macro-uri, de sistemul de help, de format,
etc.).
7. Meniul Window
Acest meniu conţine comenzi legate de ferestrele de editare.
8. Alte opţiuni
Pe lângă aceste meniuri, există şi altele specifice fiecărui tip de aplicaţie sau tip de fişier ce se editează.
De exemplu, atunci când edităm un cod sursă dacă apăsăm click-dreapta pe un anumit element selectat
se deschide meniul din Figura 13 care oferă opţiuni de redenumire automată (Rename) sau alte acţiuni
rapide şi refactorizări care pot fi realizate funcţie de context (Quick Actions and Refactorings).
Temă:
1. Studiaţi meniurile Visual Studio. Creaţi soluţii folosind Visual C# cu diferite machete
(template-uri – de exemplu Console application). Analizaţi structura de directoare şi fişiere
generate.
Programul va permite la final afisarea tuturor obiectelor astfel create (exemplificare pentru minim 6
studenţi); de asemenea, dacă doi studenţi îşi schimbă ulterior specializarea şi/sau universitatea, să se
realizeze aceasta modificare la nivelul obiectelor deja create si apoi să se afiseze rezutatul pentru a
evidenţia modificările realizate (se vor afişa din nou toate obiectele Student create).
Lucrarea de laborator nr. 2
class nume_clasa
{
câmpuri de date
proprietăţi
metode – inclusiv constructori şi destructor
elemente de indexare sau indexatori (indexers)
evenimente/delegaţi
operatori
alte tipuri: eventual, alte clase încuibate
}
Clasele sunt declarate utilizînd cuvîntul cheie class, urmat de numele clasei şi definiţia
acesteia. Elementele de bază ale claselor le reprezintă cîmpurile de date, proprietăţile şi
metodele.
Atunci cînd se crează o instanţă a clasei respective, cîmpurile de date, prin valorile pe care le
conţin, reprezintă starea instanţei în momentul respectiv.
Spre deosebire de cîmpurile de date, proprietǎţile oferǎ doar acces la date, dar nu reprezintǎ
datele propriu-zise. În multe situaţii, o proprietate publicǎ asigurǎ altor clase accesul la un cîmp
privat al clasei. Proprietatea are, spre deosebire de cîmp, avantajul cǎ poate face în plus şi
verificǎri de validitate. Proprietǎţile pot fi private sau publice, de tip read/write, read-only sau
write-only. În C#, proprietǎţile nu pot avea parametri. Sintaxa generalǎ a unei proprietăţi de
tipul read/write este urmǎtoarea:
modificator_acces tip_return NumeProprietate
{
get { aici se returneaza o valoare }
set { aici se atribuie o valoare }
}
Definirea unei proprietǎţi de tipul read-only respectiv write-only se poate face conform
urmǎtoarei sintaxe generale:
modificator_acces tip_return NumeProprietateReadOnly
{
get { aici se returneaza o valoare }
}
modificator_acces tip_return NumeProprietateWriteOnly
{
set { aici se atribuie o valoare }
}
Metodele oferă clasei (şi implicit obiectelor din clasa respectivă, pe lîngă stare şi o
funcţionalitate). În esenţă, definirea metodelor este asemănătoare cu cea a unei funcţii:
Dacă implementarea metodei constă dintr-o singură instrucţiune, C# furnizează aşa numitele
expression body methods, care oferă o alternativă simplificată de definire a metodelor:
Numele metodei trebuie să fie unic; prin intermediul parametrilor se transmit date metodelor
respective. În C# există următorii modificatori de acces valabili pentru membri unei clase,
inclusiv metode:
• private - elementele sunt direct accesibile numai în interiorul clasei; altfel, din exterior
accesul trebuie să se facă numai prin metode definite explicit, şi care nu sunt private
(publice sau protected, dupǎ caz). În mod automat, dacǎ nu se specificǎ nimic în acest
sens, în C# elementele respective (cîmpuri de date sau metode) se considerǎ implicit
private
• protected - reprezintă nivelul doi de acces, mai puţin restrictiv decît private, care
permite în plus faţă de private şi membrilor claselor derivate să aibă acces direct la
membri declaraţi protected. Accesul este posibil indiferent dacă clasele derivate fac
parte sau nu din cadrul aceluiaşi ansamblu.
• public - reprezintă nivelul trei de acces, în mod normal utilizat numai pentru metode
sau proprietǎţi, şi care conferă acestora proprietatea de a fi accesate în mod direct, de
oriunde din afara obiectului.
Metodele non-statice (de instanţă) definite în cadrul unei clase se apelează prin intermediul
obiectelor definite din clasa respectivǎ, prin intermediul notaţiei generale “cu punct”:
nume_obiect.nume_metoda(..parametri...)
Pe lîngă cei trei modificatori de acces definiţi mai sus mai există în C# şi modificatorii internal
şi protected internal, aceştia fiind utilizaţi în aplicaţii mai complexe: internal – elementele
sunt accesibile doar în cadrul ansamblului din care fac parte; protected internal - reprezintă o
combinaţie a celor doi modificatori adică şi protected şi internal: permite accesul din cadrul
aceluiaşi ansamblu dar şi din clase derivate care nu fac parte din acelaşi ansamblu.
Modificatorii de acces pot fi aplicaţi şi tipurilor de date (claselor) însă tipurile de date acceptă
doar doi modificatori de acces: public şi internal (implicit); internal implică accesul numai la
tipurile definite în cadrul aceluiaşi ansambl.
Membri unei clase pot de asemenea să fie de două categorii: membri de instanţă (non-statici)
sau membri statici (de clasă). Membri de instanţă aparţin unei instanţe specifice a clasei,
obţinută în momentul creării unui obiect din clasa respectivă. Membri statici aparţin clasei
respective şi nu unei instanţe particulare, putînd fi accesaţi şi utilizaţi chiar dacă nu există nici
o instanţă a clasei. În cazul în care există mai multe instanţe ale unei clase care dispun de un
membru static, acestea împart respectivul membru static. Declararea membrilor statici se
realizează utilizînd cuvîntul cheie static.
Atît cîmpurile de date cît şi proprietǎţile şi metodele pot fi declarate statice: metodele statice
sunt de regulǎ utilizate pentru a prelucra datele statice ale clasei. De fapt, proprietǎţile şi
metodele statice (inclusiv constructorii) prezintǎ dezavantajul cǎ nu pot utiliza în cadrul
implementǎrii decît cîmpurile declarate statice ale clasei din care fac parte. Aceasta categorie
de membri nu au acces la niciuna din datele instanţelor clasei respective (dacǎ existǎ vreuna).
Membri statici se caracterizeazǎ deci prin faptul cǎ aparţin clasei propriu-zise şi nu unui obiect
al unei anumite clase. O consecinţă a acestui fapt este aceea că datele statice pot fi
iniţializate/accesate prin intermediul clasei, chiar dacă nu existǎ încǎ obiecte instanţiate din
clasa respectivă; dacǎ nu sunt publice, se aplicǎ regulile generale de acces. Forma generală
pentru referirea unui membru static este urmǎtoarea:
nume_clasa.cimp_date_membru_static=valoare;
sau
nume_clasa.nume_metoda_statica(..);
Clasele, de regulă mai conţin şi nişte metode speciale numite constructori respectiv
destructori. Motivul principal pentru care este bine să avem constructori este că aceştia
furnizează un mod foarte convenabil de alocare/dealocare a memoriei dinamice. Fiecare clasă
trebuie să aibe un constructor care va fi apelat în momentul în care se crează un obiect din clasa
respectivă. Dacă programatorul nu furnizează în mod explicit cel puţin un constructor (pot
exista mai mulţi) pentru o clasă, compilatorul presupune că acesta există sub cea mai simplă
formă posibilă (constructor implicit).
Observaţie: pentru obiectele create sub forma unor structuri de tablou de obiecte trebuie să
existe un constructor fără parametri, în caz contrar semnalîndu-se eroare.
Constructori de copiere – atunci cînd se copiază un obiect într-un alt obiect, C# copiază de
fapt referinţa primului obiect în al doilea, ceea ce conduce la crearea a două referinţe către
acelaşi obiect. Dacă se doreşte însă crearea unei instanţe-copii ale unui obiect existent se poate
utiliza un constructor de copiere. Constructorul de copiere primeşte ca parametru un obiect din
clasa respectivă şi crează un al doilea obiect ca şi o copie a obiectului primit ca parametru.
public Nume_clasa(obiect_parametru)
{
instructiuni
}
Exercitiu:
Să se creeze o soluţie pentru gestionarea (adăugare, afişare, căutare) unor produse. Pentru
implementarea acesteia creaţi 2 proiecte, unul care se va ocupa cu gestionarea produselor app1,
iar cel de-al doilea va conţine entităţile folosite, entitati.
1. Din opţiunile puse la dispoziţie selectaţi Create a new project pentru a deschide fereastra
Create a new project. Această fereastră conţine tipurile de aplicaţii pe care le puteţi
realiza cu Visual Studio, pentru fiecare tip existând o serie de machete.
2. Selectaţi tipul de proiect filtrând opţiunile existente pentru limbajul C# , platforma
Windows respectiv macheta Console App, setaţi numele proiectului app1; locaţia
acestuia; precum şi numele soluţiei POS, după care apasaţi OK.
3. În fereastra Solution Explorer apăsaţi click dreapta pe soluţia POS, apoi Add // New
Project pentru a deschide fereastra Create a new project.
4. Selectaţi tipul de proiect Visual C# // Windows cu macheta Class Library (.NET),
setaţi numele proiectului entitati, după care apasaţi OK.
Creaţi o clasă:
5. În fereastra Solution Explorer apăsaţi click dreapta pe proiectul în care doriţi să creeaţi
clasa, în cazul nostru în proiectul entitati , apoi Add // Class pentru a deschide fereastra
Add New Item.
6. Selectaţi macheta Class , setaţi numele clasei Produs, după care apăsaţi OK.
9. Generaţi proprietăţi aferente câmpurilor clasei: click dreapta pe câmpul id, apoi Quick
Actions and Refactoring // Encapsulate field // OK. Rezultatul este generarea
proprietăţii Id/Nume... cu opţiunile get si set; repetaţi acelaşi lucru pentru fiecare
câmp, creînd proprietăţile Nume, CodIntern şi Producator asociate câmpurilor de
date corespunzătoare.
public uint Id { get => id; set => id = value; }
public string? Nume { get => nume; set => nume = value; }
…s.a.m.d
11. În fereastra Solution Explorer apăsaţi click dreapta pe proiectul app1, apoi Add Project
reference, în tab-ul Solution/Projects selectaţi proiectul entităţi.
12. Pentru a putea folosi clasa Produs în clasa Program trebuie să adăugam:
using entitati;
13. Modificaţi declaraţia clasei Produs astfel încât aceasta să fie accesibilă în alte proiect:
public class Produs
14. Codul care citeşte de la tastatură un număr specificat de produse, după care le afişează
este următorul:
using entitati;
Console.Write("Nr. produse:");
uint nrProduse = uint.Parse(Console.ReadLine() ?? string.Empty);
// array de produse
Produs[] produse = new Produs[100];
// citim produsele
for (int cnt = 0; cnt < nrProduse; cnt++)
{
// instantierea unui Produs
Produs prod = new Produs();
Console.WriteLine("Introdu un produs");
Console.Write("Numele:");
prod.Nume = Console.ReadLine();
Console.Write("Codul intern:");
prod.CodIntern = Console.ReadLine();
Console.Write("Producator:");
prod.Producator = Console.ReadLine();
produse[cnt] = prod;
}
// afisam produsele
Console.WriteLine("Produsele sunt:");
for (int cnt = 0; cnt < nrProduse; cnt++)
{
Produs prod = produse[cnt];
Console.WriteLine("Produs: " + prod.Nume + "[" +
prod.CodIntern + "] " + prod.Producator);
}
15. Apăsaţi F6 sau Build/Rebuild pentru a rula compila programul si apoi F5 pentru a rula
programul (sau Start).
16. Creaţi constructor cu toţi parametri necesari. Acest lucru se realizează prin introducerea
urmatoarelor linii de cod în clasa Produs:
public Produs(uint id, string? nume, string? codIntern,
string? producator)
{
Id = id;
Nume = nume;
CodIntern = codIntern;
Producator = producator;
}
17. Pentru a folosi noul constructor putem folosi următoarea secvenţă (în locul porţiunii de
cod care citeşte produsele):
// instantierea unui Produs
Console.WriteLine("Introdu un produs");
Console.Write("Numele:");
string? nume = Console.ReadLine();
Console.Write("Codul intern:");
string? codIntern = Console.ReadLine();
Console.Write("Producator:");
string? producator = Console.ReadLine();
Produs prod = new Produs((uint)cnt, nume, codIntern, producator);
produse[cnt] = prod;
18. În fereastra Solution Explorer apăsaţi click dreapta pe proiectul entitati, apoi Add New
Item/Class Diagram pentru editorul vizual.
19. Selectaţi elementele din soluţia deschisă în Solution Explorer (Produs) şi vizualizaţi-le în
editorul grafic Class Diagram prin drag-and-drop pe suprafaţa acesuia.
20. Folosind acest editor se pot realiza o mulţime de operaţii printre care: vizualizare detalii
clasă (click dreapta pe clasă Class Details), navigare prin elementele acesteia, adăugare de
noi elemente, etc. Editorul grafic este integrat cu codul aplicaţiei astfel încât modificările
realizate la nivelul acestuia se reflectă în cod şi viceversa.
Exerciții
Moştenirea reprezintă mecanismul care permite crearea unei ierarhii de obiecte cu descendenţi,
care moşteneşte accesul şi structurile de date ale strămoşilor. Prin intermediul moştenirii se pot
reutiliza şi extinde clasele existente, fără a rescrie codul original.
Mecanismul moştenirii permite ca, avînd o clasă aşa numită de bază, X, pe baza acesteia să
poată fi definită o altă clasă, Y, numită clasǎ derivată, care să moştenească toate elementele
primei clase, adăugându-i totodată altele noi. Astfel, în cadrul clasei Y, partea moştenită de la
X reprezintă totalitatea structurilor de date, metodelor, etc. lui X (Figura 3.1).
X = clasa
de baza
Partea mostenita
de la X
Y = clasa
derivata din X
Partea specifica
lui Y
Toate clasele din C# şi .NET Framework sunt derivate dintr-o clasǎ System.Object sau
dintr-o clasǎ derivatǎ din clasa Object. Astfel se poate spune de fapt cǎ toate clasele sunt
derivate din Object.
În contextul moştenirii în general, trebuie amintiţi modificatorii abstract şi sealed care obligă
respectiv se opun procesului de moştenire. Astfel, o clasă declarată abstractă trebuie neapărat
derivată, pentru că ea însăşi nu poate fi instanţiată, C# oferind practic un mecanism pentru a
restricţiona crearea de instanţe din anumite clase, prin posibilitatea de a le defini sub forma de
clase de bazǎ abstracte. Se impune declararea unei clase ca fiind abstractă dacă ea conţine cel
puţin un membru declarat abstract (metodă, proprietate).
In consecinţă, clasele abstracte nu pot fi instanţiate (adicǎ nu se pot crea obiecte din clasa
respectivǎ, care este declaratǎ ca abstractǎ); se pot, în schimb, crea referinţe cǎtre clase
abstracte. Încercările de a instanţia o clasǎ abstractǎ sunt detectate de compilator şi semnalate
ca şi eroare. Practic, o clasă abstractă furnizează un cadru, un schelet pe baza căruia se pot
construi alte clase, prin derivare. Declararea unei clase abstracte se face adǎugînd cuvântul
cheie abstract în declaraţia clasei.
Clasele abstracte pot conţine metode şi/sau proprietǎţi abstracte, implementate tot prin
adǎugarea cuvîntului cheie abstract în cadrul declaraţiei acestora. Declaraţia unui membru
abstract nu este urmatǎ de nici o implementare, cuvîntul cheie abstract impunând ca
proprietatea sau metoda sǎ fie definitǎ în oricare clasǎ derivatǎ pentru ca aceasta să poată deveni
instanţiabilă. Dacǎ cel puţin un membru a unei clase este declarat ca fiind abstract, atunci toatǎ
clasa trebuie declaratǎ ca abstractǎ. Dacǎ însǎ se declarǎ o clasǎ abstractǎ, nu este necesar ca
membri acesteia sǎ fie declaraţi abstracţi.
De asemenea, o clasă declarată ca sigilată (sealed) nu mai poate fi derivată ulterior, practic ea
trebuie văzută ca o clasă terminală din cadrul ierarhiei. Modificatorul sealed poate fi aplicat
şi metodelor, în acest context el interzicând redefinirea metodei respective în cadrul claselor
derivate.
Deoarece scopul claselor derivate este acela de a adăuga noi caracteristici claselor de bază, în
mod evident constructorii acestora sunt mai complecşi. Abordarea general utilizată în acest sens
este ca aceştia să apeleze în mod implicit sau explicit constructorii claselor de bază. Regula
este următoarea la crearea unui obiect dintr-o clasă derivată: se apelează mai întâi un constructor
ai clasei de bază, apoi se execută acţiuni specifice constructorului clasei proprii (derivate).
Apelul explicit al constructorului clasei de bază din constructorul unei clase derivate se poate
realiza utilizînd base(…):
public nume_constructor_derivat(..parametri..)
:base (..parametri_constructor_baza..)
{
Instructiuni constructor clasa derivata
}
Dacă un se realizează niciun apel la base, se va apela implicit constructorul fără parametri ai
clasei de bază (implicit, dacă un există altul).
De fapt, base poate fi utilizat pentru a apela orice metodă a clasei de bază care este redefinită
într-o clasa derivată, prefixând apelul metodei cu base:
base.nume_metoda(..parametri..);
Mutaţi câmpurile şi proprietăţile comune ale celor 2 clase (Produs şi Serviciu) în clasa
de bază ProdusAbstract. Astfel se va obţine structura din Figura 3.1. Rulaţi programul
pas cu pas pentru a vedea modul în care se realizează apelurile.
Faceţi acelaşi lucru şi pentru clasa Serviciu după care rulaţi programul pas cu pas.
Compilând soluţia în acest moment veţi constata că sunt erori de compilare datorate
neimplementării metodei abstracte Descriere în clasele derivate.
Se observă faptul că implementarea celor două metode Descriere (din clasa Produs şi
clasa Serviciu) este foarte asemănătoare deci s-ar putea crea o altă variantă a acestora prin
mutarea părţii comune a acestora în cadrul unei metode din clasa de bază ProdusAbstract.
Realizăm în acest sens o nouă variantă de metode ce urmează a fi utilizate pentru afişare -
AltaDescriere, pe care o facem de data aceasta virtuală. Astfel, în clasa
ProdusAbstract vom avea:
În clasa Produs vom apela metoda din clasa de bază utilizând base, astfel vom avea:
Creaţi clasa ProduseMgr în proiectul app1. Includeţi în cadrul clasei o structură de tablou în
care vor fi memorate obiectele Produs: adăugaţi declaraţiile pentru tabloul de produse,
precum şi o variabilă CountProduse pentru a contoriza numărul de produse:
Console.Write("Nr. produse:");
uint nrProduse = uint.Parse(Console.ReadLine() ?? string.Empty);
mgrProduse.ReadProduse(nrProduse); //citire nrProduse – cate dorim sa introducem
mgrProduse.WriteProduse(); //afisare produsele citite
Rulaţi aplicaţia pas cu pas pentru a înţelege secvenţa de apeluri. Urmăriţi unde sunt stocate
obiectele Produs şi Serviciu create.
Modificaţi codul metodelor de citire şi afişare din cadrul claselor ProduseMgr respectiv
ServiciuMgr astfel încât citirea şi afişarea să utilizeze tabloul elemente din cadrul clasei
de bază ProduseAbstractMgr. Rulaţi aplicaţia, adăugând două produse şi două servicii, şi
urmăriţi (afişaţi) rezultatul obţinut.
Modificatorul static
Rulaţi aplicaţia din nou (adăugând două produse şi două servicii). Explicaţii, analizând
rezultatul afişat, care este diferenţa faţă de rularea anterioară (ce implicaţii are adăugarea
modificatorului static).
Temă:
Obligatoriu metodele supraîncărcate trebuie să aibă același nume dar semnături diferite => lista
de argumente trebuie să fie diferită. Selecţia metodei efectiv apelatate se realizeaza funcţie de
argumentele utilizate (parametri) în momentul apelului => metodele sunt diferențiate prin
numărul și tipul parametrilor metodei. În cazul supraîncǎrcǎrii metodelor, comportarea codului
e determinata la compilare: funcţie de numărul şi/sau tipul parametrilor utilizaţi în momentul
apelului, se identifică de către compilator funcţia care va fi utilizată, încă din faza de compilare
(compile-time polimorfism). Tipul returnat poate sau nu să fie același, acesta un reprezintă
factor de deferenţiere la selecţia metodei efectiv apelate.
obj1.Nume_metoda(param1, param2);
obj2.Nume_metoda(param1, param2, param3);
Testarea egalităţii obiectelor (compararea) ar putea părea ca un concept simplu la prima vedere,
dar dacă privim mai profund, nu este. În C# obiectele pot fi comparate prin diferite modalităţi
de abordare, astfel:
• utilizând redefinirea operatorului ==
• redefinind metoda Equals(Object) moştenită de la clasa Object
• prin implementarea unor interfeţe specifice care furnnizează capabilităţi de comparare a
obiectelor, de exemplu IComparable, IEquatable<T>, etc.
Exerciții
2. Creaţi în clasele manager două metode supraîncarcate pentru căutarea unui anumit obiect
Produs/Serviciu în tabloul de produse şi servicii cu parametri diferiţi (căutare după
obiectul căutat respectiv doar după numele acestuia, de exemplu:
public bool Contine(Produs p);
public bool Contine(string? numep);
Clase generice
Utilizatorul poate sǎ-şi defineascǎ propriile clase şi metode generice; de asemenea, utilizatorul
poate, sǎ-şi defineascǎ propriile colecţii generice: implementarea acestora se bazează pe clase
generice. Astfel, o definiţie genericǎ furnizează doar formatul general al clasei sau a metodei
definite astfel, T, T1,...etc. fiind tipurile generice pe care compilatorul le va înlocui în momentul
apelului, funcţie de tipurile parametrilor actuali transmişi. Forma generală a unei clase generice
este următoarea:
Se observǎ cǎ parametrul T (sau, eventual, parametri) este utilizat în poziţiile unde în mod
normal ar apǎrea tipuri:
• tipuri ale parametrilor unei metode
• tipuri ale valorilor returnate de metode sau de proprietǎţi
• tipuri ale câmpurilor de date
Definiţia clasei în acest caz furnizează doar formatul general al acesteia în cadrul căruia T,
T1,...etc. reprezintă tipuri pe care compilatorul îl va înlocui în momentul apelului, funcţie de
tipul parametrilor actuali transmişi. Utilizarea unei astfel de clase generice impune instanţierea
clasei respective pentru anumite tipuri concrete, folosind unul din constructorii definiţi în cadrul
acesteia (de exemplu, fără parametri):
nume_clasa<tip_concret> o_instanta_concreta
= new nume_clasa<tip_concret>();
De exemplu, definirea unei liste de şiruri de caractere sau numere întregi se poate realiza foarte
simplu, particularizând tipul T la crearea obiectului List:
List<string> siruri = new List<string>();
List<int> intregi = new List<int>();
Exerciţiul 1:
Colecțiile de obiecte pot fi create pe baza unor fişiere XML existente. Pentru a putea crea
obiecte mai complexe, completaţi implementarea produselor şi serviciilor cu două câmpuri
suplimentare: pret si categorie.
În continuare creaţi un fişier XML cu informaţii despre produse cu urmǎtoarea structurǎ:
Adaptaţi exemplificările de mai sus astfel încât să poată fi utilizate în cadrul aplicaţiei pentru
citirea tabloului de elemente (atât produse şi servicii).
LINQ (Language Integrated Query) – începând cu versiunea .NET 3.5 reprezintǎ un set de
extensii .NET Framework care furnizeazǎ capabilitǎți de interogare în cadrul imbajelor C# şi
Visual Basic, extinzând sintaxa acestora cu operatori de intorogare standard care permit lucrul
cu datele independent de sursa de date (simple colectii – Linq to Objects, baze de date – Linq
to SQL, XML - Linq to XML). Se permite astfel ca accesul către diferite surse de date să poată
fi realizat prin intermediul unei sintaxe unitare. LINQ adreseazǎ interactiunea cu datele în
context obiectual (model obiectual) => interogǎrile beneficiazǎ de verificǎri la compilare şi
facilitǎți de depanare.
In ceea ce priveşte LINQ to Objects, LINQ admite ca sursǎ de date doar tipuri enumerabile
(implementeazǎ IEnumerable<T>); colecţiile reprezintă, în general, sursa de date în acest
caz. Rezultatul interogǎrii este stocat într-o variabilǎ interogare a cǎrui tip poate fi declarat sau
nu; în acest ultim caz aceasta se declarǎ folosind var şi compilatorul va detecta în mod automat
tipul acesteia.
IEnumerable<ProdusAbstract> interogare_linq =
from elem in elemente
where elem.Categorie == "Tehnologia Informatiei"
orderby elem.Nume
select elem;
sau
IEnumerable<ProdusAbstract> interogare_linq =
from elem in elemente
where elem.Categorie == "Tehnologia Informatiei" && elem.Pret <= 2000
select elem;;
Pentru interogǎri mai complexe, care returneazǎ grupuri de rezultate, pot fi necesare mai multe
bucle foreach imbricate. De asemenea, este posibilǎ utilizarea variabilei de interogare fǎrǎ
tip specificat, folosind var; în acest caz, compilatorul va detecta în mod automat tipul acesteia:
var interogare_linq =
from elem in elemente
orderby elem.Nume
group elem by elem.Categorie into gr
select gr;
foreach (var gr in interogare_linq)
{
Console.WriteLine("Categoria " + gr.Key + " :");
foreach (ProdusAbstract elem in gr)
{
Console.WriteLine(elem.AltaDescriere());
}
}
Adaptaţi exemplificările de mai sus astfel încât să realizaţi diverse tipuri de interogări asupra
tabloului elemente.
Exerciţiul 2:
1. Creaţi o clasă cu numele ListaGen. Pentru ca acesta să fie generică clasa trebuie declarată
astfel:
class ListaGen<T>
2. În interiorul acestei clase trebuie să declarăm structura noduilor listei prin intermediul clasei
încuibate (interne)Nod :
// constructor
public ListaGen()
{
Inceput = null;
Count = 0;
}
Adăugaţi funcţionalitate
6. Pentru a putea folosi lista trebuie să definim un obiect ListaGen particularizând tipul
elementelor din cadrul acesteia, de exemplu, pentru tipul int:
ListaGen<int> listagenerica = new ListaGen<int>();
7. Pentru a adăuga un nou element x in listă putem folosi una din cele 2 metode de inserţie :
listagenerica.Add(x);
Observaţie: x trebuie sǎ fie un obiect care are tipul tipului de date al listei (în cazul de mai
sus int, respectiv string, etc.); ce se întâmplǎ în caz contrar?
8. De exemplu, pentru a afişa lista de elemente cu elemente de tip int, putem folosi :
Observaţie: în exemplu de mai sus element este declarat de tip int. Acesta trebuie să fie
declarat cu acelaşi tip de date pentru care a fost instanțiatǎ lista (tipul elementelor constituente).
Temă:
Interfeţe
Interfeţele sunt deosebit de utile în dezvoltarea software deoarece codul rezultat se
caracterizează prin: cuplare redusă, programare bazată pe componente, întreţinere uşoară, grad
ridicat de reutilizare datorită decuplării implementării faţă de interfaţă. În cadrul unei interfeţe
sunt definite metode, proprietǎţi, elemente de indexare şi evenimente pe care o clasǎ care
implementeazǎ interfaţa respectivǎ trebuie sǎ le implementeze. Interfaţele nu pot conţine o stare
(ex. elemente de tipul câmpuri de date) => interfeţele descriu un comportament, ele NU
reprezintă capacitate de stocare pentru date; în schimb, poate conţine proprietăţi, deoarece
acestea sunt implementate prin metode. Definirea unei interfeţe se realizeazǎ utilizînd cuvîntul
cheie interface. Asemenea claselor, o interfaţǎ este membrǎ a unui spaţiu de nume. O interfaţǎ
poate sǎ fie derivată dintr-una una sau mai multe interfeţe de bazǎ.
Până la versiune C#8 interfeţele nu era posibil să dispună de niciun fel de implementare;
începând însă cu C#8 se pot crea anumite implementări de metode în cadrul interfeţelor.
Interfeţele pot fi implementate implicit sau explicit; varianta implicită este de preferat şi
majoritar utilizată; diferenţa constă în sintaxa redefinirii membrilor interfeţei în clasă, varianta
explicită prefixând numele membrilor redefiniţi cu numele interfeţei; de asemenea, membri
redefiniţi explicit nu pot fi publici (sunt private) şi deci nu sunt accesibili prin intermediul
obiectelor definite din clasa respective.
Începând cu C#8, membrii interfeței sunt implicit public dar sunt permişi şi alți modificatori de
acces, de exemplu private; un membru al interfeței private nu este accesibil din afara interfeței
deci nu există nicio modalitate de a oferi o implementare pentru un membru al interfeței private
în afara interfeței; aceştia sunt cu adevărat utili doar pentru a furniza implementări explicite şi
pentru a fi utilizați eventual de către alţi membri ai interfeței
În general, implementarea interfeţelor este responsabilitatea claselor care implementează
interfaţa respectivă; deoarece interfeţele trebuie în general implementate în cadrul claselor sau
structurilor derivate, ele pot fi văzute ca definind un contract prin care se stipulează
obligativitatea unei clase de a implementa membri respectivi.
interface INumeInterfata
{
tip_retur NumeProprietate
{ get; set; }
tip_retur NumeMetoda();
object this[int index]
{ get; set; }
delegate int Delegat(object obj1, object obj2);
event Delegat NumeEveniment;
……
}
O clasǎ care implementeazǎ o interfaţǎ trebuie sǎ implementeze în mod explicit toţi membri
acelei interfeţe. Accesul la membri astfel implementaţi nu se va realiza prin intermediul unei
instanţe a clasei ci prin intermediul unei referinţe la interfaţa pe care clasa o implemeneazǎ. În
acest caz, prin intermediul referinţei definite se pot accesa doar membri interfeţei; pentru a
accesa eventualii membri proprii ai clasei care implemeneazǎ interfaţa trebuie realizatǎ o
conversie explicitǎ a referinţei cǎtre o referinţa la clasa respectivǎ.
Exerciţiu:
Pentru a modela situaţia reală în care comerciaţii fac oferte la produse şi/sau servicii „ambalate”
într-un pachet vom extinde implementarea aplicaţiei dezvoltate în laboratoarele precedente prin
construirea unei clase Pachet, clasă care este derivată din ProdusAbstract. Clasa
abstractizează conceptul de pachet, care poate conţine unul sau mai multe produse şi/sau
servicii. Astfel, vom crea o interfaţă IPackageable care să marcheze faptul că un
ProdusAbstract poate sau nu să fie parte a unui pachet.
1. În fereastra Solution Explorer apăsaţi click dreapta pe proiectul (în care doriţi să
creaţi interfaţa), în cazul nostru în proiectul entitati , apoi Add // New Item pentru a
deschide fereastra Add New Item.
3. Adăugaţi metoda :
Aceastǎ metodǎ ne spune dacă un ProdusAbstract poate fi vândut (inclus) într-un pachet
sau nu (returnând true respectiv false). Implementarea acestei metode se va face în clasele care
implementează interfaţa IPackageble.
Faptul că metoda returnează true se traduce prin faptul că orice obiect Produs poate
face parte din orice pachet; acest lucru se poate însǎ modifica ulterior dacǎ se doreşte
impunerea anumitor restricții.
11. Vizualizaţi rezultatul folosind Class diagram (Figura 6.1). In cadrul diagramei, câmpul
elem_pachet al clasei Pachet este un tablou de elemente IPackageable.
Figura 6.1: Implementarea ierarhiei de clase cu interfața IPackageble
Temă:
//afiseaza pachetele
mgrPachet.Write2Console();
Adaptaţi exemplificarea de mai sus în contextul aplicaţiei de la laborator. Analizaţi rolul pe care
implementarea bazată pe interfeţe aduce un plus de generalitate problemei faţă de alte potenţiale
versiuni de implementare particulare. Analizaţi în ce masură s-ar putea introduce în cadrul
arhitecturii de clase de mai sus o filtrare după mai multe criterii (categorie şi preţ, sau alte
variante) şi realizaţi o variantă de implementare.
Lucrarea de laborator nr. 7
Serializarea
Serializarea este procesul de conversie a stării unui obiect, adică a valorilor proprietăților
acestuia, într-o formă care poate fi stocată şi, eventual transmisă între diverse aplicaţii.
Termenul de serializare se foloseşte în limbajele orientate pe obiecte în legătură cu persistenţa
obiectelor (instanţelor); pentru ca un obiect să fie persistent, el trebuie salvat pe o memorie
nevolatilă pentru a putea fi restaurat ulterior pe baza informaţiilor salvate. Datele instanţei
serializate sunt salvate în ordine, de obicei câmp cu câmp; dacă se doreşte serializarea mai
multor instanţe, salvarea datelor acestora se realizeaza în ordine, una dupa alta, secvenţial, deci
ordinea de salvare trebuie să fie aceeaşi cu ordinea de citire pentru restaurare; nu se pot accesa
înregistrări individuale, deci serializarea nu se poate folosi pentru stocarea bazelor de date.
Deserializarea reprezinta operaţia inversă serializarii prin care datele serializate în prealabil
sunt inserate într-o instanţă (sau în instanţe) ale clasei.
În procesul de serializare/deserializare, cele mai cunoscute standarde din industrie sunt bazate
pe fişierele XML (Extensible Markup Language) sau pe serializare JSON (JavaScript Object
Notation); există, dar este mai puţin actuală şi varianta de serializare binară (sub formă de fişier
bitmap). .NET pune la dispozitie clase specifice pentru operaţiile de serializare/deserializare:
Serializarea unei instanţe a unei colecţii implicǎ la rândul sǎu serializarea tuturor instanţelor
elementelor din cadrul colecţiei. Aceastǎ relaţie de dependenţǎ între clase reprezintǎ graful de
obiecte al clasei respective. Mediul de execuţie .NET parcurge recursiv graful de obiecte pentru
fiecare clasǎ în procesul de serializare şi serializeazǎ toate obiectele acestuia. Este important în
acest sens ca toate clasele componente din cadrul acestui graf sǎ fie corect definite în vederea
serializǎrii.
Faţǎ de serializarea binarǎ, în cadrul serializǎrii XML şi JSON sunt serializabile doar
proprietǎţile publice. Dacǎ datele instanţelor nu sunt accesibile din câmpurile sau proprietǎţile
publice, ele nu vor fi iniţializate la deserializarea obiectelor => acestea trebuie să aibă
modificatori publici (get/set). Pentru deserializarea XML respectiv JSON este necesar un
constructor public, fǎrǎ parametri, care este utilizat implicit în procesul de deserializare (re-
creare a obiectului).
using System.Xml;
using System.Xml.Serialization;
typeof(Serviciu)
4. Modificaţi clasa Program pentru a testa serializarea unui obiect Serviciu individual
7. Salvaţi fişierul .xml în care s-a serializat obiectul Serviciu sub un alt nume.
8. Adăugaţi namespace-urile folosite pentru serializare la clasa ProdusAbstract.
9. Adăugaţi atributul XmlRoot la clasa Serviciu astfel:
[XmlRoot("ServiciuParticularizat")]
public class Serviciu : ProdusAbstract, IPackageble
[XmlElement("Numele")]
public String Nume
[XmlElement("CodulIntern")]
public String CodIntern
11. Inspectaţi fişierul rezultat în urma rulării programului. Comparaţi fişierul obţinut cu cel
generat înainte de a folosi atributele de serializare.
2. Utilizați exemplificările precedente pentru a adapta aplicaţia realizată astfel încât aceasta să
serializeze/deserializeze o listă de obiecte Pachet, aşa cum a fost ea dezvoltată în din
cadrul Laboratorului nr. 6 (în cadrul cǎruia au fost utilizatǎ structura elemente de tip
List<T> pentru memorarea elementelor dintr-un pachet şi al pachetelor). Inspectați
fişierul generat în procesul de serializare.
Tehnologia Windows Presentation Foundation permite crearea de aplicaţii de tipul fat client,
caracterizate printr-o interfaţă grafică bogată (rich) care are la bază pe o serie de controale
cărora li se poate asocia un comportament specific ca răspuns la interacţiunea cu utilizatorul,
şi care se găsesc ȋn spaţii de nume precum System.Windows respectiv
System.Windows.Controls. Se bazează pe XAML care este un limbaj de marcare,
declarativ, şi care oferă o modalitate de a separa logica interfeţei UI de funcţionalitatea
aplicaţiei permiţand separarea interfeţei de implementarea din spate. XAML provine de la
eXtensible Markup Language și este un limbaj bazat pe XML care poate fi folosit pentru a
crea și inițializa obiecte .NET. XAML este un limbaj independent care poate fi folosit în
multe domenii diferite, dar este utilizat în principal în crearea interfețelor cu utilizatorul WPF
sau UWP. XAML se mapează la obiectele .NET și poate fi chiar creat cu diverse instrumente,
cel mai popular fiind Blend pentru Visual Studio.
Cadrul WPF este construit pentru a profita de accelerarea hardware a plăcilor grafice moderne
(rezultand performanţă), permițând randarea mai rapidă a interfeței şi făcând-o scalabilă,
independentă de rezoluție și compatibilă cu motorul de randare vectorială; se bazează pe
DirectX pentru redarea elementelor UI, care este foarte performant și este scalabil. In plus,
WPF introduce un nou mecanism de rutare a evenimentelor, în comparație cu WinForms,
numit RoutedEvents, ca modalitate traversare a arborelui vizual de către evenimente.
WPF este bazat pe o arhitectură multistrat (multi-layer), concepută pentru a fi mai sigură
(Figura 1). În partea de sus a stivei sunt plasate serviciile managed de nivel superior scrise în
limbajul C#. În al doilea rând, în stivă se află stratul de integrare media (MIL) – cod
unmanaged. Ultimul strat este reprezentat de API-urile de bază ale sistemului de operare care
ajută la gestionarea procesului aplicației WPF. Ierarhia de clase de bază ale tipurilor WPF este
următoarea:
DispatcherObject - aplicația WPF folosește modelul Single-Thread Affinity (STA) și, prin
urmare, fiecare element UI este deținut de un singur thread. Dacă alte thread-uri doresc să
acceseze DispatcherObject, atunci trebuie să apeleze serviciile Invoke sau BeginInvoke
furnizate de Dispatcher cu DispatcherObject asociat. Clasa face parte din spaţiul de nume
System.Threading.
Visual - este o altă clasă care oferă suport pentru randarea în WPF. Toate controalele interfeței
cu utilizatorul precum Button, ListBox derivă din această clasă. Clasa Visual definește toate
proprietățile necesare pentru randare, tăiere, transformare, delimitare, etc. Clasa ajută la
construirea arborelui vizual care conține valorile proprietăților de redare ale elementelor
grafice. Clasa face parte din spaţiul de nume System.Windows.Media.
UIElement - este clasa care adaugă funcţionalităţi de bază pentru layout, input, focus,
evenimente asociate elementelor UI, etc. Clasa oferă, de asemenea, servicii precum legarea
datelor (data binding), posibilitate de a realiza animații, etc. Clasa face parte din spaţiul de
nume System.Windows.
FrameworkElement - clasa extinde funcţionalitatea oferită de UIElement şi suprascrie layout-
ul pentru implementări la nivel de framework. Clasa face parte din spaţiul de nume
System.Windows.
Shapes - este clasă de bază pentru elemente precum Line, Ellipse, Polygon, Path, etc. Clasa
face parte din spaţiul de nume System.Windows.Shapes.
Controls - acest spațiu de nume conține toate elementele care ajută la interacțiunea cu
utilizatorul. Puține controale, precum Textbox, Button, Listbox, Menu, suport pentru font,
culoarea de fundal și aspect etc. sunt prezente în acest spațiu de nume.
ContentControl - este clasă de bază pentru toate controalele care acceptă conținut singular.
Controale de tip Label, Button, Windows etc., toate acceptă numai conținut singular. Clasa
face parte din spaţiul de nume System.Windows.Controls.
ItemsControl - este clasă de bază pentru toate controalele care includ conţinut multiplu, adică
o listă de item-uri, cum ar fi controale de tipul ListBox, TreeView, Menus, Toolbar, etc. Clasa
face parte din spaţiul de nume System.Windows.Controls.
Panel - este clasă de bază pentru toate elementele de tip container, cum ar fi controale de tip
Grid, Canvas, DockPanel, StackPanel, WrapPanel, etc. Clasa face parte din spaţiul de nume
System.Windows.Controls.
<Window x:Class="WpfAppEx.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppEx"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfAppEx
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
Astfel, MainWindow.xaml.cs conţine iniţial doar constructorul clasei care apelează metoda
InitializeComponent, ȋn cadrul căreia se vor iniţializa toate controalele care vor fi
adăugate ȋn cadrul ferestrei MainWindow prin intermediul designer-ului grafic.
Exerciţiu:
1. Selectaţi opţiunea Create a new project şi selectaţi tipul de proiect WPF Application (din
categoria de aplicaţii Desktop) pentru a crea un proiect .NET WPF Application. Setaţi
numele proiectului wpfapp1, locaţia acestuia, după care apasaţi OK.
În urma acestor acţiuni se va genera soluţia wpfapp1 şi proiectul wpfapp1 care va conţine
o fereastră MainWindow. Rulaţi programul şi comentaţi rezultatul.
2. Deschideţi fereastra MainWindow.xaml.cs şi vizualizaţi codul sursă care s-a creat, aferent
ferestrei MainWindow. Rezultatul este crearea a 2 fişiere :
MainWindow.xaml.cs => funcţionalitate
MainWindow.xaml => aspect
3. Daţi click dreapta pe fereastră în designer-ul grafic şi selectaţi opţiunea Properties; daţi un
nume obiectului aferent ferestrei principale (de exemplu, mainWindow) şi schimbaţi titlul
afişat în fereastra MainWindow la Fereastra principală (opţiunea Common/Title).
Observaţi cum schimbările realizate prin modificarea proprietaţilor se reflectă în fişierul
MainWindow.xaml
4. În fereastra Solution Explorer apăsaţi click dreapta pe proiectul wapp1 , apoi Add //
Window (WPF) pentru a deschide fereastra Add New Item.
5. Selectaţi macheta Window (WPF), setaţi numele ferestrei MyWindow, după care apăsaţi
Add. Rezultatul este crearea a 2 fişiere :
MyWindow.xaml.cs
MyWindow.xaml
Daţi un nume obiectului aferent noii ferestre create (de exemplu myWindow şi modificaţi titlul
ferestrei la Fereastra mea (opţiuni la Properties).
7. Din grupul de unelete All WPF Controls, folosind drag/drop adăugaţi pe fereastra
MainWindow un buton; modificaţi proprietăţile obiectului buton şi daţi un nume
obiectului aferent butonului (butMyWindow) şi afişaţi un text pe buton, de exemplu
Apasa! (proprietatea Content).
8. Apasaţi dublu click pe butonul adăugat pe fereastra MainWindow şi modificaţi codul astfel
încât acesta să arate în forma următoare:
11. Rulaţi program şi apăsaţi butonul de mai multe ori. Comentaţi rezultatul.
14. Modificaţi fiecare proprietate pe rând; dupa fiecare modificare rulând aplicaţia
17. Modificaţi titlul ferestrei printr-o atribure folosind obiectul newWindow, de exemplu:
newWindow.Title = "Titlul ferestrei schimbat la executie!";
24. Adăugaţi un handler pentru evenimentul Unloaded folosind următoarea secvenţă de cod:
newWindow.Unloaded += new RoutedEventHandler(myWindow_Unloaded);
Temă: