Medii de dezvoltare – curs 1- - Informatică Economică, an III –
Cristian Bologa
Introducere in .NET Framework
1
Obiective
Deprinderea principalelor concepte ale programarii in .NET Framework 4.0Programarea aplicatiilor Windows utilizand WPFProgramarea aplicatiilor Web utilizand ASP.NET Programarea accesului la date
Organizare
Laborator: 418/419/420Echipa:
Lect. Dr. Cristian Bologa, As. Dr. Alexandru Stan, Drd. Florina Covaci
2
Medii de dezvoltareCerinţe, evaluare
Probă teoretică: 40% - din care Examen scris în sesiune: 75% 2 teste scrise la finalul cursurilor: fiecare 12.5% Testele scrise: materia predata pana la momentul
testului
Proiect: 40%, examinat prin sustinere in sesiuneEvaluarea activității de laborator: 20%
Necesar: minim 5 la fiecare probă de examen
3
Bibliografie
handouts la fiecare curs – din Microsoft Official Curricula
Orice alt material la dispozitia dvs este potrivit
4
Cuprins
Introducere in .NET Framework 4.0Crearea proiectelor utilizand Visual StudioScrierea aplicatiilor in C#Documentarea aplicatiilorDebugging
5
Introducere în .NET Framework 4.0
6
Common Language Runtime (CLR)Mediul de executie a programelor in .NET Framework
Mediu robust si securizat
Gestioneaza executia programelorSimplifica procesul de dezvoltare software Furnizeaza servicii comune pentru programele executate:
Managementul memoriei Gestiunea tranzactiilor Comunicarea intre procese, multithreading Si altele
7
CLR – suport pentru mai multe limbaje de programare
Permite scrierea programelor in mai multe limbaje de programare echivalenteVisual Studio 20xx furnizează compilatoare pentru C#, C++, Visual Basic si F#Modelul de compilare in 2 faze:
Codul sursă este compilar intr-un limbaj intermediar MSIL Codul MSIL este executat de către CLR
8
Biblioteca de clase Furnizeaza clase reutilizabile care pot fi folosite de către programatoriSe asigura o fundatie comuna de functionalități care pot fi folositeDezvoltatorii nu trebuie sa re-inventeze logica unor unelte clasiceClasele din biblioteca de baza pot fi extinse prin procesul de moștenire
9
Medii de dezvoltare suportate
ASP.NET – aplicatii web server-sideWindows Presentation foundation (WPF) – aplicatii client Windows cu grafică bogatăWindows Communication foundation (WCF) – aplicatii orientate pe servicii
Vor fi abordate la disciplina Programare pe componenteWindows Workflow foundation (WWF) – aplicatii bazate pe descrieri de procese de tip workflow
Descrieri de tip workflow vor fi abordate la disciplina Sisteme pentru modelarea proceselor de afaceri
10
Obiectivele limbajului C#Este limbajul de programare dedicat pentru .NET FrameworkUtilizeaza o sintaxă similară cu C/C++ și JavaC# este standardizat prin ECMA-334 C# Language SpecificationVisual Studio furnizeaza editor de cod, compilator, template-uri pentru proiecte, wizards, debugger, si alte unelte
11
Assembly Prin compilarea codului sursa C# se generează fisiere executabile care rulează pe CLR => assemblyContin cod intermediar MSIL (Microsoft intermediate language)CLR rulează cod MSIL indiferent de limbajul sursă in care este scris programulAssembly:
sunt blocurile de bază a aplicațiilor .NET Framework Reprezinta unitatea de bază pentru deployment, controlul versiunilor
reutilizare si securitate Putem gandi un assembly ca o colecție de tipuri si resurse care
conlucrează si formează o unitate logică de functionalitate
2 tipuri de assembly: program executabil (.exe) Librarii (.dll): pentru modularizarea dezvoltării codului si
descompunerea aplicației in componente logice (reutilizabilitate)12
Assembly (II)Contin informație legată de controlul versiuniiFiecare assembly este semnat digitalIncluderea informației legate de versiune permite realizarea pașilor necesari pentru upgrade-ul aplicațieiSemnatura assemblyurilor asigura faptul că acestea nu vor fi modificate sau inlocuite de o implementare alternativă Semnatura asigura pentru fiecare assembly un “strong name”Manifest-ul assembly-ului:
Contine informatia legata de versiune si semnatură Contine metadata care descrie obiectivul (scopul) assembly-ului si
referințe la alte clase si resurse Este stocat intr-un fișier “portable executable” (.pe)
Versiunea (stocată in manifestul assembly-ului) contine: major version, minor version, build number și revision number
13
Semnatura assembly-uluiProtejeaza assembly-ul de modificari neautorizatePermite includerea unui assembly semnat in Global Assembly Cache
Astfel se pot partaja assemblyuri intre mai multe aplicații
Se garanteaza un nume unic unui assembly Pentru semnare, se foloseste Sign Tool (furnizat de Visual Studio)
14
Executia assemblyurilorCLR incarcă acele assemblyuri referite de către aplicație
ClassLoader: pentru localizarea si incarcarea assemblyurilor
Verifică și compilează assemblyurile in cod masină MSIL-to-native compiler Just-in-time compilation: codul MSIL este compilat in executabil
chiar inainte de execuție
Rulează executabilul CodeManager: incarca executabilul si executa metoda Main Garbage Collector: eliberează automat memoria obiectelor care nu
mai sunt utilizate de către aplicație Exception Manager: furnizează gestiunea excepțiilor
15
Unelte furnizate de către .NET FrameworkCode Access Security Policy Tool (Caspol.exe)
Permite utilizatorilor să modifice politicile de securitate la nivel de utilizator, masină sau enterprise.
Permite definirea unui set de permisii custom.
Certificate Creation Tool (Makecert.exe) Permite utilizatorilor să creeze certificate X.509 Aceste certificate sunt folosite pentru semnarea assemblyurilor si
definirea conexiunilor SSL
Global Assembly Cache Tool (Gacutil.exe) Permite (dez/)instalarea assemblyurilor din GAC, astfel incat mai
multe aplicatii sa le poata utiliza
Native Image generator (Ngen.exe) Permite imbunatatirea performantelor aplicațiilor .NET. prin
precompilarea assembly intr-o imagine ce contine cod masina specific procesorului respectiv
CLR pot executa acest cod precompilat in locul compilarii Just-in-time
16
Visual Studio 20xxIDE care permite dezvoltarea rapidă a aplicațiilor (RAD)
Se pot crea interfete GUI complexe in mod rapid
Access la servere si date: Server Explorer -Permite conectarea la serverele de date și explorarea
acestora
Facilitati de debugging: Furnizează o unealtă pentru executie pas-cu-pas, breakpoints, urmarirea
executiei
Gestiunea erorilor Error List Window -Fereastră de erori, acestea sunt produse pe măsura
scrierii codului si la build
Facilitați pentru help si documentare VS are help integrat Microsoft Intellisense, Code snippets
17
Template-uri de bază in VSFurnizeaza cod de start de la care se poate crea in mod rapid o aplicațieInclude pentru utilizare componentele si controalele relevante tipului de proiectConfigureaza IDE-ul pentru dezvoltarea tipului de aplicație pe care il dezvoltamAdaugă referințele către assemblyurile relevante (necesare) respectivului tip de aplicație
Console applicationWPF applicationClass LibraryWindows Forms ApplicationASP.NET Web applicationASP.NET MVC 2 ApplicationSilverlight ApplicationWCF Service application
18
Solutia VSReprezinta wrapper pentru proiectele .NETO solutie VS poate contine mai multe proiecte .NETO solutie VS poate contine tipuri diferite de proiecte .NETFisier .sln: punct de access pentru proiectele din solutieFisier .suo: user option file: setările utilizatorului pentru solutia VS
19
Clase si namespace-uri.NET Framework respectă paradigma obiectuală: claseO clasă defineste caracteristica și funcționalitatea unei entitățiUn namespace reprezinta o colecție logică de clase
Namespace-ul este echivalentul packageului
20
Structura unei aplicații consolă
21
Comentarea aplicațiilorIncepeți procedurile prin blocuri de comentariiSpargeti procedurile lungi in unităti de muncă prin blocuri de comentariiLa declararea variabilelor folositi comentarii pentru a descrie utilizarea acestor variabileLa utilizarea structurilor de decizie indicați (prin comentarii) modul de luare a deciziei si logica acesteia
22
Documentarea aplicațiilorSe folosesc comentarii XML pentru a genera documentatie HELP pentru aplicații
23
Taguri pentru documentare<summary></summary>: furnizează o descriere scurtă<remark></remark>: furnizează o descriere lungă<example></example>: furnizează un exemplu de utilizare pentru metodă, proprietare, sau alt membru al bibliotecii<code></code>: indică faptul că avem un cod sursă<returns></returns>: documentează valoarea sau tipul de return al unei metode
Csc.exe cu parametrul /doc: generează un fisier XML care are codul XML pentru documentare inclusIn fereastra properties a proiectului (in Solution Explorer) pe tabul Build se bifează XML documentation Sandcastle Help File Builder -> se folosesc sursele XML pentru a genera fisiere help .chm
24
Medii de dezvoltare – curs 2- - Informatică Economică, an III –
Cristian Bologa
Crearea interfetelor grafice in .NET Framework
25
Interfata grafică: reprezentarea vizuală a aplicațieiUtilizatorii interfațează cu aplicația prin intermediul interfeței grafice
Manipulează controalele găzduite de fereastra aplicației
Windows Forms: baza (istorică) a aplicațiilor WindowsWPF: succesorul Windows Forms
Diferenta fundamentală a WPF: Codul interfeței utilizator este separat de codul aplicației
26
Aplicatiile WPFFisiere XAML: descriu layoutul componentelor in format XMLFisiere XAML.cs: contin codul din spatele designuluiFiecare XAML are o clasă care descrie functionalitatea
Se poate folosi designerul VS pentru crearea interfeteiLa run-time, controalele se asează pe interfată Controalele pot fi create / pozitionate / modificate și la run-time
27
Controalele WPF3 tipuri de controale: individuale, item și layout
Controalele individuale: Corespund unor controale echivalente din Windows Forms: Button, Label,
TextBox etc. Au un scop individual in aplicație Content controls (controale de continut): afisează o varietate de continut
Item controls: grupează mai multe itemuri ListBox, Menu, TreeView Permit utilizatorului să selecteze un item dintr-o listă si să realizeze o actiune
pe acel item
Controale Layout: contin alte controale de orice tip Furnizează logică incorporată pentru aranjarea vizuală a acestor controale Grid, StackPanel, Canvas
28
Controale ContentDerivează din clasa ContentControlContin un singur element inglobatAcesta poate fi setat sau citit prin proprietatea ContentTipul proprietatii Content este Object -> poate fi setată la orice valoare. Pentru itemurile care nu derivă din UIElement, ele se afisează prin apelarea proprietății toStringProprietatea Content se poate seta din XAML sau din cod:
<Button Height="23" Margin="36,0,84,15" Name="button2"
VerticalAlignment="Bottom">This is the content string</Button>
button2.Content = "This is the content string";
29
Label și Mnemonic keys
Label: este un container pentru continutMnemonic key: mută focusul către un anume control la apăsarea alternativă Alt + keySpecificarea unui mnemonic key: _Caracter
Ex: _A Trebuie să se seteze proprietatea Target a controlului de tip Label
<Label Target="{Binding ElementName=TextBox1}" Height="27"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="51">_Name
</Label>
<TextBox Name="TextBox1" Margin="53,1,94,0" Height="26„ VerticalAlignment="Top">
</TextBox>
30
Controlul ButtonPermite utilizatorului să efectueze acțiunea click pentru a realiza o alegere: de ex. Sa inchidă o fereastrăUtilizatorul trebuie să scrie handler pt evenimentul ClickProprietatea isDefault: -daca este True atunci butonul este setat Default pt GUI (se generează evenimentul click la apăsarea Enter)Proprietatea isCancel: -daca este True atunci butonul este considerat Cancel pt GUI (se generează evenimentul click la apăsarea Esc)Setarea unui access key pt buton: prin folosirea _ in Button Content, la fel ca si mnemonic keys
31
Controlul CheckBoxMosteneste din clasa ButtonBasePermite setarea unei optiuni ca fiind On sau OffProprietatea isChecked de tipul bool? : permite valorile booleene si valoarea nedefinită (atunci cand fereastra este deschisă prima data)CheckBox generează evenimentul click la apăsarea click de mouse
32
Controlul RadioButtonMosteneste tot din clasa ButtonBaseButoanele Radio sunt grupate astfel incat să se permită utilizatorului selectarea unei singure optiuniLa apăsarea de mouse se generează evenimentul ClickIn mod uzual, toate butoanele radio dintr-un container sunt in acelasi grupSetarea proprietatii GroupName pentru a avea mai multe grupuri de butoane radio intr-un singur containerButoanele Radio se pot grupa prin asezarea lor in containere diferite ,de exemplu in StackPanel
33
TextBlockText care apare intr-o fereastrăPentru a seta proprietatea Text in mod programatic trebuie setată proprietatea Name
<TextBlock Name="TextBlock1">Here is some text</TextBlock>
TextBlock1.Text = "Here is the changed text";
34
ImageControlul Image reprezintă o imagine care se afiseazăProprietatea Source: programatic preia un obiect de tipul System.Windows.Media.ImageSourceIn XAML se poate furniza un identificator de tip URI (Uniform Resource Identifier)
Fisier local sau resursă web
Proprietatea ImageStrech: determină modul de afișare a imaginii
None: este afisată in dimensiunea originală Fill: imaginea umple dimensiunea controlului Uniform: imaginea este redimensionată cu păstrarea aspect ratio, nu
se face crop, insă poate apărea spațiu neumplut UniformToFill: imaginea este redimensionată cu păstrarea aspect
ratio, se face crop pentru a se umple dimensiunea controlului
35
TextBoxPentru afisare si editare de textProprietatea Text: este cea care contine textul afisat/introdusProprietatea isReadOnly: permite doar afisareProprietatea TextWrapping: pentru afisare / editare intr-un control pe mai multe liniiProprietatea VerticalScrollBarVisibility: permite afisarea unui scrollbar
36
ProgressBarSe permite afisarea progresului unei operatii mai lungiProprietatea isEnabled: daca controlul ProgressBar este activisIndeterminate: dacă controlul arată progresul real sau un progres generic. La progres real, controlul va arăta valoarea din proprietatea ValueLargeChange: mărimea de adăugat/scazut din Value atunci cand se solicită o schimbare mareMaximum: valoarea maximă a progressBar-ului. Cand Value == Maximum, progressbarul este la maximMinimum: valoarea minimă a progress baruluiOrientation: dacă controlul este orientat orizontal sau verticalSmallChange: mărimea de adăugat/scazut din Value la o schimbare micăValue: valoarea afișată de progres bar.
ProgressBar1.Value += 1;
Controlul Slider Simular cu ProgressBar, folosit pentru a seta o valoare cu mouse-ul intre un minim si un maximGenerează evenimenul ValueChanged
37
Tab Order pentru controaleControalele primesc focus pe măsură ce utilizatorul apasă tasta TabOrdinea de accesare a controalelor este ciclicaSe poate seta ordinea in care se transferă focusul (sau Tab Order) prin setarea proprietății TabIndex in XAMLControalele care nu au TabIndex stabilit primesc focusul după cele cu TabIndex definit
38
Controale item: ListBoxAfisează o listă de itemuriContinutul este o listă de controale ListboxItem – fiecare găzduieste un singur elementListBox afisează controalele vertical, si eventual pune un scroll vertical dacă lista este lungăImplicit, se poate selecta un singur item din control.
proprietatea SelectedIndex pentru indexul itemului selectat Proprietatea SelectedItem pentru a returna itemul selectat Proprietatea IsSelected: pentru a verifica dacă un item este selectat Proprietatea SelectionMode pentru a permite selecția mai multor itemuri (cu Shift pt
itemuri consecutive si cu Ctrl pt itemuri disparate)
ComboBoxSimilar cu ListBox, doar că afisarea de face in dropdown listPoate găzdui o listă de stringuriPoate fi editabil.
39
TreeViewGazduieste o listă de controale TreeViewItem care permite construirea unui continut de tip arboreUn treeViewItem are un Header care permite setarea textului care va fi afisatFiecare TreeViewItem gazduieste alte TreeViewItemPutem face expande sau collapseProprietatea SelectedItem: returneaza itemul selectat din TreeView
40
MenuPrezinta utilizatorilor o lista de controale asociate cu comenziMeniurile sunt afisate ca si liste ierarhice2 tipuri de meniuri:
Menu: care este vizibil in cadrul GUI ContextMenu: apare ca si meniu pop-up doar in anumite situatii
Menu Poate fi pus aproape oriunde in interfata. De obicei este sus, in bara de
meniu Proprietatea IsMainMenu: cauzeaza ca meniul sa fie considerat meniu
principal al ferestrei. Primeste focus cu tasta Alt sau F10 Contine o lista de controale de tip MenuItem
41
MenuItemReprezinta o suprafata pe care se poate face Click si are un text asociatMenuItem: control de tip Item, el poate contine alte elemente de tip MenuItemProprietatea Command: indică comanda asociată cu obiectul MenuItemProprietatea Header: textul afisat de meniuProprietatea Icon: icoana afisată in stanga intrării de meniu. La IsChecked setat true, icoana nu este afisataProprietatea IsChecked: permite ca un check sa fie afisat in dreptul meniuluiProprietatea IsEnabled: meniul este activ sau nuProprietatea Items: contine lista de MenuItems a meniuluiCu _ se crează un mnemonic keySe recomandă sa nu se asocieze comenzi meniurilor care au componente in lista de Items
42
ContextMenuNu au o locatie fixa, ele sunt asociate cu alte controaleUn ContextMenu se atribuie proprietătii ContextMenu a celorlalte controaleMeniul contextual este afisat la RightClick pe controlul respectiv sau la Shift+F10 cand controlul are focusContextMenu poate fi adaugat ca si resursa in Windows.Resources
43
ToolBarPrezinta o serie de controalePoate gazdui controale precum Button, ComboBox, TextBox, CheckBox si RadioButtonPoate gazdui SeparatorProprietatea OverflowMode: dacă in Toolbar se adaugă mai multe controale decât acesta poate afișa, atunci cele care nu se pot afisa sunt sterse la afisare. Ele sunt vizibile in meniul Overflow, care apare in dreapta Toolbarului la configuratia orizontală
Valori posibile: Always, AsNeeded, Never
ToolbarTrayEste un container pentru controale de tip ToolbarSe permite resize/move pentru controalele Toolbar plasate in ToolbarTray la runtime
44
StatusBarSimilar cu ToolBarUtilizat pentru a gazdui controale care afisează informație
Label , ProgressBar
45
Controale de tip LayoutPermit utilizarea unor tipuri diferite de aranjare a controalelorSe permite utilizarea unor tipuri de paneluri pentru gruparea controalelor din GUI
Proprietatea FlowDirection: setează directia in care textul sau celelalte controale se aranjeaza in cadrul controlului Layout părinteProprietatea Height/Width: inaltimea/latimea controlului. La Auto, controlul se autodefinesteHorizontalAlignment: VeritcalAlignment: caracteristici de aliniere orizontală/verticalăHorizontalContentAlignment/ VerticalContentAlignment: seteaza sau obtine caracteristicile de aliniere orizontală/verticalăMargin: seteaza distanta dintre controalele continute si marginea containeruluiMaxHeight, MaxWidth, MinHeight, MinWidth: dimeniunile max/min ale controluluiPadding: spatiul dintre un control si elementul child
46
Proprietăți attachedControalele WPF contin informație necesară pentru propria afisare si orientare in GUIUneori, un control este necesar să definească informație asupra controlului care il contineAstfel controlul container atasează controalelor continute o serie de proprietăți care pot fi setate de către controlul continut
<Button Grid.Row="1" Grid.Column="1"></Button>
47
Panelul GridControalele gazduite de un Grid sunt afisate in ordinea in care apar in codul XAML
Se pot defini coloane si linii: ColumnDefinition si RowDefinition
Controalele child se pot asigna intr-o linie si o coloană Proprietățile attached Grid.Column si Grid.Row
Se utilizează proprietățile Margin, HorizontalAlignment si VerticalAlignment a controlului child pentru afisarea acestuia
Proprietățile attached ColumnSpan si RowSpan pentru a permite afisarea unui control peste mai multe coloane/linii
Controlul GridSplitter
Permite userului sa redimensioneze liniile/coloanele unui grid la runtime
Trebuie plasat intr-o celulă a gridului
Trebuie pozitionat adiacent coltului liniei sau coloanei sau pus intr-o linie sau coloană individuală
48
UniformGridPlasează controalele intr-un grid de o mărime uniformă, Numărului de linii si coloane se autoajustează pe măsură ce se plasează controale în gridDacă se fixează numărul de linii si coloane si se adaugă mai multe controale decât poate găzdui controlul de tip UniformGrid, controalele in plus nu se vor afisa
49
StackPanelAsează controalele continute unul deasupra celuilalt, in ordinea in care sunt definite.proprietatea Orientation: pentru a seta orientarea panelului (StackPanel orizontal). Implicit e verticalProprietatea FlowDirection: pentru a seta curgerea controalelor la afisate. Implicit e LeftToRight
50
WrapPanelAsează controalele continute intr-o linie orizontală, unul langa celalalt, până se umple tot spațiul disponibilApoi se crează o linie nouă in care se adaugă controalele care nu incap in prima linie samd.Se foloseste controlul de tip WrapPanel pentru controalele care pot fi Resized la run-time prin drag-drop
51
DockPanelEste un container care permite legarea controalelor de colturi. Echivalent proprietății Dock din WindowsFormsProprietatea attached Dock: specifică modul de legare a controlului child de panel
Top, Bottom, Left, Right
Proprietatea LastChildFill –setata pe True: ultimul control va afisat de panel va umple tot spatiul paneluluiOrdinea in care controalele sunt adaugate in panel este esentială pentru afisarea controalelor continute
52
CanvasContainer care permite pozitionarea absolută a controalelor continuteProprietăți attached: Top, Bottom, Right, Left. Indică distanta dintre latura specificată și latura corespondentă a controlului continut
<Canvas>
<Button Canvas.Top="20" Canvas.Left="30">Button</Button>
</Canvas>
La resize, controalele continute isi mentin distanta setată fată de laturile controlului CanvasControalele Canvas pot contine alte paneluri in interiorul lor.Panelul definit ultimul este afisat deasupraProprietatea attached ZIndex: pentru a se seta ordinea de afisare a controalelor overlapping
Cele cu Zindex mare se afisează deasupra
53
Accesarea programatică a controalelor continute
Proprietatea Children: colectie care expune controalele continute
Button aButton;
aButton = (Button)grid1.Children[3];
Alinierea controalelorSe poate face la designTime cu utilizarea snaplines
54
Folosirea resurselorResurse: obiecte sau fișiere pe care aplicația le utilizează dar care nu au fost create in aplicație (ex: imagini, fisiere text mari)Resurse binare: folosite atat in Windows Forms cat si in WPFWPF defineste conceptul de resursă logică
Se permite definirea obiectelor care se utilizează in aplicație Se permite partajarea acestor obiecte intre elementele aplicației
55
Resurse binarePermite compilarea unor fisiere binare mari in assemblyul aplicației si apoi utilizarea acestora in aplicațiePentru a ingloba o resursă binară in aplicație:1. din meniul Project se apelează Add new Item2. se selectează fisierul care se adaugă in proiect. Se da Add3. in fereastra Properties se setează proprietatea Build Action la Resource
56
Utilizarea imaginilor ca resurseClasa Image poate lucra direct cu resurse inglobateTrebuie transmisă calea către fisierul imagine
<Image Source="myFolder/myPic.bmp" Margin="17,90,61,22"
Name="Image1" Stretch="Fill"/>
In mod general, se poate lucra cu URI:pack://<Authority>/<Folder>/<FileName>
<Authority> poate fi Aplication,,, : resursa se afla in assemblyul aplicației siteOfOrigin,,, : resursa trebuie căutată in situl de origine a
aplicației
Se pot utiliza resurse din alte assemblyuripack://application:,,,/<AssemblyName>;component/<Folder>/
<FileName>
57
Fisiere continutNu toate fisierele externe pe care le utilizam dorim să le inglobam in aplicație ca si resurseDacă aceste fisiere isi schimba continutul frecvent, atunci inglobarea ca si resurse va determina necesitatea de a recompila aplicația la fiecare modificare de continut a fisierului
Pentru a dauga fisiere continut in aplicație 1. din meniul Project se apeleaza Add new item2. se selecteaza fisierul care se adaugă in aplicație, se da Add3. In fereastra Properties se seteaza proprietatea BuildAction a fisierului la Content4. In fereastra Properties la proprietatea Copy to Output Directory se seteaza Copy Always
58
Resurse adaugate manualMetoda Application.GetResourceStreamMetoda returneaza un obiect de tipul System.Windows.Resources.StreamResourceInfo, care are 2 proprietăți
ContentType – tipul de continut UnmanagedMemoryStream – datele binare (raw) ale resursei
Resursa poate fi folosita programatic – de exemplu ca un stream de IO de unde se citeste
59
Crearea de dll-uri cu resurseSe pot crea dll-uri care să contină doar resursele compilate
1. in VS se crează un proiect cu template-ul Empty Project2. in solution explorer se dă click dreapta pe numele proiectului si
se selectează Properties , apoi Project Properties . In tabul Application se seteaza Application Type la Class Library
3. din meniul Project se adaugă resursele la proiect cu Add Existing Item
4. la resursele din proiect, din fereastra Properties, proprietatea Build Action se selectează Embedded Resource
5. in meniul Build se selecteaza Build <application>
60
Accesarea dll-ului cu resursePentru a accesa programatic dll-ul cu resurse
1. se obtine numele assembly-uluiSystem.Reflection.AssemblyName aName;
aName = System.Reflection.AssemblyName.GetAssemblyName("C:\\myAssembly.dll"));
2. Se foloseste obiectul AssemblyName pentru a incarca assemblyulSystem.Reflection.Assembly asm;
asm = System.Reflection.Assembly.Load(aName);
3. Se accesează numele resursei folosing Assembly.GetManifestResourceName si după aceea se acceseaza streamul resursei utilizand Assembly.GetManifestResourceStream
String res[] = asm.GetManifestResourceNames();
pictureBox1.Image = new
System.Drawing.Bitmap(asm.GetManifestResourceStream(res[0]));
61
Resurse logicePutem defini obiecte in XAML care nu fac parte din arborele vizual dar sunt disponibile pentru a fi utilizate in interfata GUIAvantajele definirii de obiecte in sectiunea de Resources fată de definirea unor obiecte la fiecare utilizare:
Se castiga in gradul de reutilizare Se castiga in flexibilitate prin separarea obiectelor folosite in interfata de interfata GUI.
Astfel se poate face refactoring la interfata fara a fi necesar reproiectarea acesteia –ex: colectii diferite de resurse pt aplicatii localizate
Declararea unei resurse se face prin adaugarea acesteia la colectia de resurse: - atentie la numele resursei: definit cu x:Key
<Window.Resources>
<RadialGradientBrush x:Key="myBrush">
<GradientStop Color="CornflowerBlue" Offset="0" />
<GradientStop Color="Crimson" Offset="1" />
</RadialGradientBrush>
</Window.Resources>
Resursa se poate defini doar intr-un Grid, si astfel nu e disponibilă in intreaga fereastră
62
Resurse la nivel de aplicațieSe pot defini resurse accesibile de către toate obiectele din aplicație
<Application x:Class="WpfApplication2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<SolidColorBrush x:Key="appBrush" Color="PapayaWhip" />
</Application.Resources>
</Application>
Accesarea resursei in XAML:{StaticResource myBrush}
{DynamicResource myBrush}
Diferenta: • resursele referite static sunt regasite doar o singură data si utilizate pe toata durata de
viată a resursei• Resursele referite dinamic sunt achizitionate la fiecare referire a obiectului care le
utilizează
63
Dictionare de resurseUn dictionar de resurse este o colectie de resurse care este salvata intr-un fisier XML separat si care poate fi importat in aplicatieDictionarul de resurse poate fi util pentru partajarea resurselor intre aplicațiiCrearea unui dictionar de resurse:
1. din meniul Project se selecteaza Add Resource Dictionary. Se da un nume dictionarului si se da Add
2. se adaugă resurse in dictionarul deschis in mod XAML
Concatenarea a 2 dictionare de resurseSe face prin adaugarea unei referinte catre fisierul dictionar in colectia ResourceDictionary.MergedDictionaries
Regăsirea unei referintei la o resursă:Metoda FindResource apelată cu cheia resursei (Key)Metoda poate fi invocata de la orice control care are access la resursă
64
Medii de dezvoltare – curs 3- - Informatică Economică, an III –
Cristian Bologa
Evenimente si comenzi
65Cluj-Napoca - 25 Noiembrie 2015
Arhitectura de gestiune a evenimentelor
Introdusă in Windows FormsFiecare eveniment are
un obiect (control) trimitător care aruncă (lansează) evenimentul un obiect (control) receptor care are metoda handler a evenimentului
Delegate: un obiect intermediar intre trimițător și receptorEste necesar pt ca trimițătorul nu știe ce procedură va gestiona evenimentulPrin delegate se crează metodele care sunt utilizate (delegate) să răspundă la evenimentUn delegate memorează o referință către metoda care va gestiona evenimentul
Definește numele handlerului si tipul argumentelor
Sunt multicast -> pot memora referinte către mai multe handlereFunctionează ca si un dispecer intre clasa care aruncă evenimentul prin gestionarea unei liste de handlere de evenimente
66
Lucrul cu delegates1. declararea delegate-ului
public delegate void EventHandler(object sender, EventArgs e);
2. declararea evenimentului gestionat prin delegate3. scrierea metodei care să răspundă la eveniment (in clasa controlului care răspunde la eveniment)4. legarea evenimentului de handlerul său
67
Handlere de evenimenteMetode legate de evenimenteLa aparitia evenimentului, se execută codul din handler
Argumentele handlerului Un obiect care a aruncat evenimentul (sender) Un obiect care contine informatie specifica evenimentului (de tip
EventArgs)
68
Adaugarea / stergerea de handlereIn designer:
se selecteaza controlul dorit In fereastra de events, se selecteaza evenimentul
care se doreste a fi prins
La runtime
69
Evenimente si tratarea evenimentelor
Eveniment: un mesaj trimis de către un obiect la care programul răspunde prin executarea unei bucăți de cod
Evenimentele pot fi lansate de către controale sau alte părți ale interfeței utilizator
Evenimente rutate: un eveniment creat de către un control să apară la un alt control dintre containerele in care stă controlul sursă
Se permite astfel programatorului să decidă nivelul la care va prinde evenimentul lansat in interfața grafică
Se simplifică scrierea codului si se asigură consistență la tratarea evenimentelor
Tipuri de evenimente rutate: Directe Bubbling De tip tunel
70
Evenimente directeSunt similare evenimentelor din Windows FormsEvenimentul este aruncat (si poate fi prins) doar la controlul de origine (de la care provine)Nu există șansa ca evenimentul să fie prins la un control de nivel superior
71
Evenimente bubblingSunt aruncate de către controalele unde iși au originea și apoi de către fiecare control container in care rezidă controlul de origineEvenimentele sunt prinse si tratate mai intâi la control și apoi la containerul care il conține
Evenimente de tip tunelActioneaza invers ca si evenimentele bubblingEste aruncat mai intâi de către cel mai de sus container din arborele vizual si apoi in jos de către fiecare container până la controlul de origine Permit ca evenimentele să fie prinse si tratate mai intâi la container si apoi la controlAstfel de evenimente sunt marcate cu cuvantul Preview (PreviewKeyDown, PreviewMouseDown)Evenimentele de tip tunel sunt definite in pereche cu cate un eveniment bubblingMai intâi se aruncă evenimentul de tip tunel si apoi cel bubbling
Argumentele sunt partajate intre aceste evenimente
72
RoutedEventArgs
Fiecare eveniment include o instanță a clasei RoutedEventArgs (sau o clasă care mosteneste RuotedEventArgs)Aceasta conține informație despre eveniment si sursa acestuia
Proprietăți ale RoutedEventArgsHandled: dacă evenimentul a fost tratat deja sau nu. Prin setarea la True se poate opri tratarea ulterioară a evenimentelor de tip bubbling sau tunelOriginalSource: se obtine obiectul care a aruncat prima dată evenimentul (diferit de Source la controale compozite)Source: obiectul care a aruncat evenimentulRoutedEvent: returnează evenimentul care a fost ridicat. Se foloseste atunci cand printr-un handler se gestionează mai multe evenimente si dorim sa identificam care eveniment a fost ridicat
Argumentele de evenimente mostenesc din RoutedEventArgs si astfel furnizează informație suplimentară
73
Atașarea unui handler de evenimente
Se poate face direct in codul XAML prin atasarea numelui metodei la eveniment
<Button Height="23" Margin="132,80,70,0" Name="button1"
VerticalAlignment="Top" Click="button1_Click">Button</Button>
Evenimente attached: pentru un control se poate atasa un handler unui eveniment care nu poate fi aruncat de către controlul respectiv
<Grid Button.Click="button_Click">
<Button Height="23" Margin="132,80,70,0" Name="button1"
VerticalAlignment="Top" >Button</Button>
</Grid>
Codul de mai sus defineste handler pentru toate butoanele din grid
74
Tratarea unui eveniment de tip tunel sau bubbling
Pentru a inhiba tratarea unui eveniment de tip tunel sau bubbling la un anumit nivel in ierarhie, se foloseste proprietatea Handled setata pe TrueDacă se setează Handled la un eveniment de tip tunel, atunci se consideră Handled si evenimentul bubbling pereche
Clasa EventManager - gestionează inregistrarea tuturor evenimentelor rutateGetRoutedEvents: returnează un sir de evenimente integistrate in aplicațieGetRoutedEventsForOwner: returnează un sir de evenimente inregistrate pentru un anume element din aplicațieRegisterClassHandler: inregistrează un handler de eveniment la nivel de clasăRegisterRoutedEvent: inregistrează un handler de eveniment la nivel de instanță
75
Definirea unui nou eveniment rutat1. se crează o definitie statică, read-only a evenimentuluipublic static readonly RoutedEvent SuperClickEvent;
2. se crează un wrapper pentru evenimentul rutat care il expune ca si un eveniment traditional .NET Frameworkpublic event RoutedEventHandler SuperClick
{
add
{
this.AddHandler(SuperClickEvent, value);
}
remove
{
this.RemoveHandler(SuperClickEvent, value);
}
}
76
Definirea unui nou eveniment rutat3. in constructorul clasei care agregă evenimentul, se foloseste EventManager pentru a inregistra noul eveniment.
Trebuie furnizat numele evenimentului, strategia de tratare a acestuia (direct, tunelling sau bubbling), si tipul clasei care il detine
EventManager.RegisterRoutedEvent("SuperClick",
RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Window1));
Ridicarea unui evenimentSe crează o nouă instanță de RoutedEventArgs prin utilizarea metodei RaiseEventRoutedEventArgs myEventArgs = new RoutedEventArgs(myControl.myNewEvent);
RaiseEvent(myEventArgs);
77
Crearea unui handler de eveniment la nivel de clasă
Tratează un eveniment pentru toate instantele din clasa respectivăEste invocat intotdeauna inaintea handlerelor de evenimente de la nivel de instanță1. se crează o metodă statică de tratare a evenimentului
private static void SuperClickHandlerMethod(object sender,
RoutedEventArgs e)
{
// Handle the event here
}
2. in constructorul static al clasei se crează un delegate pentru metodăRoutedEventHandler SuperClickHandler = new
RoutedEventHandler(SuperClickHandlerMethod);
3. tot in constructorul static al clasei se apelează EventManager.RegisterClassHandler
EventManager.RegisterClassHandler(typeof(Window1),
SuperClickEvent,SuperClickHandler);
78
Evenimente la nivel de aplicațieFiecare aplicație WPF este incapsulată intr-un obiect de tip Application care furnizează un set de evenimente pentru gestiunea ciclului de viață al aplicațieEvenimente la nivel de aplicație
Activated: apare cand aplicația primeste focus de la un alt program (trecem de la o alta aplicatie la programul nostru)
Deactivated: cand aplicatia lasă focusul unui alt program DispatcherUnhandledException: apare cand o excepție nu este tratată in
aplicație. Se poate gestiona o exceptie negestionată prin setarea DispatcherUnhandledExceptionEventArgs.Handled la True
Exit: apare cand aplicația este inchisă SessionEnding: cand se inchide sesiunea Windows adică la logoff sau
computer shutdown Startup: cand aplicația este pornită
Evenimentele la nivel de aplicatie sunt evenimente standard .NET Framework
79
Crearea unui handler de eveniment la nivel de aplicație1. in solution explorer, click dreapta pe App.xaml si se apelează view code2. se crează o metodă pentru a gestiona evenimentulvoid App_Startup(object sender, StartupEventArgs e)
{
// Handle the event here
}
3. In XAML, se adaugă handlerul de eveniment la declararea tagului Application<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml" Startup="App_Startup">
80
ComenziTaskuri de nivel inalt care sunt executate in aplicațieExemplu de comandă: Paste: copierea unui obiect din clipboard container Se permite crearea unei arhitecturi centralizate pentru comenzi, astfel incat să nu fie nevoie să se scrie cate un handler de eveniment pentru fiecare posibilitate de apelare a taskuluiSe pot asocia orice număr de obiecte UI sau inputuri cu o comandă astfel incat să se lege comanda de un handler care este executat atunci cand sunt activate controaleleComanda poate fi dezactivată, atunci elementul de interfată la care comanda este asociat este si el dezactivatobiectul Command: obiectul care reprezinta taskulSursa comenzii: este controlul care generează comandaHandlerul comenzii: este metoda care se executa la invocarea comenziiCommandBinding: obiectul utilizat de .NET Framework pentru a tine evidenta asocierilor dintre surse si handlere
81
Comenzi predefiniteApplicationCommandsComponentCommandsEditingCommandsMediaCommandsNavigationCommands
Fiecare din aceste clase expune o varietate de obiecte comanda statice pe care le putem utiliza in aplicatii; trebuie sa cream binding-uri si handlere pentru aceste comenzi pt a le putea utiliza in aplicatie
82
Implementarea unei comenzi1. se decide comanda care se doreste a se utiliza. Poate fi o comandă statică expusă de .NET Framework sau una custom2. se asociază comanda cu un control sau cu un input 3. se crează metoda care gestionează comanda4. se crează controlul CommandBinding care leagă obiectul Command la handlerul de comandă si optional, la o metodă care gestionează Command.CanExecute5. se adaugă CommandBinding la collectia Commands a controlului sau la controlul Window
83
Invocarea comenziiPrin asocierea ei cu un control folosind un input sau invocare direct din cod
Asocierea comenzii cu un controlMajoritatea controalelor implementează interfata ICommandSource -> se permite ca acestea să fie asociate cu o comandă care este apelată automat cand este invocat controlul
<Button Command="ApplicationCommands.Find" ...>Button</Button>
Invocarea comenzii cu un inputSe pot inregistra evenimente de mouse sau tastatură cu obiecte de tip Command care invoca comanda cand aceste evenimente apar
ApplicationCommands.Find.InputGestures.Add(new
MouseGesture(MouseAction.LeftClick, ModifierKeys.Control));
ApplicationCommands.Find.InputGestures.Add(new
KeyGesture(Key.Q, ModifierKeys.Control));
Invocarea comenzii din codPrin apelarea metodei Command.Execute
ApplicationCommands.Find.Execute(aParameter, TargetControl);
84
Handlere de comenziPentru executarea unui cod atunci cand se invoca o comandă trebuie creat un CommandBinding care leagă comanda de un handlerHandler corect al unei comenzi:
private void myCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
// Handle the command here
}
ExecutedRoutedEventArgs este derivata din RoutedEventsArgs si expune proprietatea Command care returnează obiectul Command al comenzii
Crearea CommandBinding-asociaza o comanda cu un command handlerCommandBinding abinding = new CommandBinding();
abinding.Command = ApplicationCommands.Find;
abinding.Executed += new ExecutedRoutedEventHandler(myCommandHandler);
this.CommandBindings.Add(abinding);
85
Crearea de CommandBinding in XAML<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Find"
Executed="myCommandHandler" />
</Window.CommandBindings>
86
Comenzi Bubbling Comenzile se rostogolesc către containerele din varful ierarhiei in care rezidă controlul unde se invoca comandaFiecare control are propria colecție CommandBindingSe poate opri rostogolirea procesarea comenzii prin setarea Handled=true
private void myCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
// Handle the command here
e.Handled = true;
}
87
Dezactivarea comenzilorComenzile care nu sunt asociate in CommandBinding sunt automat dezactivateFiecare control care are in proprietatea Command asignat o comandă disables devine la randul lui dezactivat Pentru a dezactiva comenzi care sunt assignate in Command si avem setat si CommandBinding se utilizează Command.CanExecute
Este un eveniment care determină dacă o comandă se poate executa
1. se crează o metodă să gestioneze evenimentul CanExecutebool canExecute;void abinding_CanExecute(object sender, CanExecuteRoutedEventArgs e){e.CanExecute = canExecute;}
2. Se setează handlerul evenimentului CanExecute a obiectului CommandBinding către această metodă
abinding.CanExecute += new CanExecuteRoutedEventHandler(abinding_CanExecute);
88
Medii de dezvoltare – curs 4- - Informatică Economică, an III –
Cristian Bologa
Controale definite de utilizator
89Cluj-Napoca - 2 Decembrie 2015
CuprinsImplementarea controalelor utilizator in Windows FormsCrearea si aplicarea template-urilor in WPFCrearea si implementarea controalelor utilizator in WPFImplementarea dependency properties
90
WPF - Controale compoziteSunt controale realizate din alte controaleMoștenesc din clasa UserControl
Au un designer asociat, deci noul control poate fi realizat in VS, folosind designerul IDE
Adaugarea unui control compozit – din meniu:1. din meniul Project, se selectează Add user control2. se da numele noului control si apoi Add
Adaugarea unui control compozit – din codSe crează o clasă care moștenește din UserControl
91
Adaugarea de metode, proprietăți, evenimente la un control
Adaugarea unei metode: se scrie o metodă nouă in clasaAdaugarea unei proprietăți: se scrie o proprietate nouă in clasă (se scriu setter si getter); valoarea va fi stocata intr-o variabila membru privatăAdaugarea unui eveniment:
Necesar să fie prezent un delegate care să specifice semnătura evenimentului
Se defineste evenimentul folosind event Evenimentul poate fi apelat (aruncat) utilizand semnătura
92
Expunerea unei proprietățiImplicit proprietățile sunt private (ex: inaccesibile claselor din alte asembly-uri)Trebuie făcute public pt a fi expuse
Configurarea unui control pentru a fi invizibil la Runtime: Setarea proprietății Visible la true
Setarea unui background transparent: Proprietatea BackColor se seteaza la Color.Transparent
93
Property attributesSpecificate intre [] inainte de clasă / proprietate / metodă / evenimentSpecifică modul in care controlul va fi interpretat de către designerul VS
Permit gruparea proprietăților noi in fereastra PropertiesPermit stabilirea valorilor defaut utilizate in design timeSe pot defini editoare custom pentru noile proprietăți
Exemple de property attributes: Browsable, Description, Category, DefaultProperty
Crearea unui Toolbox bitmap -permite specificarea unei iconite in dreptul controlului de pe Toolbox
Property attribute ToolboxBitmapAttribute Trebuie setat către un bitmap de dimensiune 16x16
[ToolboxBitmap(@"C:\myToolboxBitmap.bmp")]
class myControl : UserControl {}
94
Windows Forms - Controale extinse
Extind functionalitatea controalelor existente in .NET FrameworkSe reține funcționalitatea existentă și se pot adăuga metode și proprietăți noiSe moștenește din clasa controlului care se doreste să se extindă
Se poate furniza implementare nouă unor funcționalități existente prin suprascriere
protected override void OnClick(System.EventArgs e)
{
Clicks++;
base.OnClick(e);
}
Se poate schimba afisarea (rendering) controlului prin suprascrierea metodei onPaint
95
Windows Forms - Controale custom
Create de la zeroSe mosteneste din clasa ControlTrebuie să se suprascrie metoda OnPaintTrebuie folosit obiectul Graphics pentru a realiza desenarea controlului in OnPaint
96
WPF - Template-uri de controaleIn WPF controalele sunt “lookless”: funcționalitatea este complet separată de modul de afisare a elementuluiPutem furnizeaza o nouă afisare (appearance) a controlului prin crearea unui nou template al controlului
Template al controlului: este un document XAML care arată cum va fi afisat controlul in nivelul de prezentareReprezintă arborele vizual al controlului, părțile componente ale acestuia și afisarea acestor părțiDefinite in cadrul elementului <ControlTemplate>
<Button Height="23" Width="100" Name="Button3">
<Button.Template>
<ControlTemplate>
<Rectangle Fill="RoyalBlue" />
</ControlTemplate>
</Button.Template>
</Button>97
Template-uri pt controaleElementul <ContentPresenter>: este placeholder pt proprietatea Content a template-ului
Content este afisat in locul specificat de ContentPresenter
La elemente de tip List: <ListPresenter>: placeholder pt elementele Item
Crearea template-ului ca si o resursă:Se pune elementul <ControlTemplate> in cadrul tagului Windows.Resource
Modul de afisare poate fi aplicat mai multor controale Pt aplicare se utilizează proprietatea Template a controlului
<Button Template="{StaticResource ButtonTemplate}" Margin="112,123,91,116"
Name="Button1">Button</Button>
98
Interactivitatea controalelorControalele interactionează cu utilizatorul in diverse modalități (de exemplu la mouse rollover deasupra controlului)ControlTemplate.Triggers: o colecție de triggere a templateului<ControlTemplate TargetType="{x:Type Button}" x:Key="ButtonTemplate">
<Border Name="Bord1" BorderBrush="Chocolate" BorderThickness="3">
<Grid>
<Rectangle Name="Rect1" Fill="RoyalBlue" />
<Ellipse Name="Elli1" Fill="Red" />
<ContentPresenter HorizontalAlignment="Center“ VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Rect1" Property="Fill" Value="AliceBlue" />
<Setter TargetName="Bord1" Property="BorderBrush" Value="Red" />
<Setter TargetName="Elli1" Property="Fill" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
99
Template bindingLeagă o proprietate a unui template de o proprietate a template-ului părinte{TemplateBinding <PropertyName>}: se specifică numele proprietății din template-ul parinte de care se doreste legarea
<ControlTemplate TargetType="{x:Type Button}" x:Key="ButtonTemplate">
<Border Name="Bord1" BorderBrush="Chocolate"
BorderThickness="{TemplateBinding BorderThickness}">
....
Se va folosi Binding in loc de TemplateBinding cand proprietatea este de tip Freezable
...
<Setter TargetName="Elli1" Property="Fill" Value="{Binding
RelativeSource={RelativeSource TemplatedParent},
Path=Background}" />
100
Vizualizarea template-ului unui control1. se crează o instantă din controlul dorit
Fie vizual utilizand designerul fie din cod
2. se foloseste XamlWriter pentru a se obtine un stream de iesire unde se poate tipări template-ul
System.IO.FileStream aStream = new
System.IO.FileStream("C:\\template.xml", System.IO.FileMode.Append);
System.Windows.Markup.XamlWriter.Save(aTextBox.Template, aStream);
101
Crearea controalelor in WPF2 mari categorii:
Controale utilizator (user control): mostenite din UserControl Controale custom (custom control): mostenite din Control sau
ContentControl
Alegerea tipului potrivit de control Dacă funționalitatea unui control predefinit se potriveste in mare
măsură peste funcționalitatea dorită => un template nou cu o afisare nouă a controlului
Daca funcționalitatea dorită se realizează cu o combinație dintre un control predefinit si cod nou, => un control utilizator
Dacă nu există un control predefinit sau o combinație intre un control existent si cod nou => un control custom
102
Dependency propertiesSunt forma standard a proprietătilor in WPFPermit change notification, animation, mostenirea property values, data binding si alteleSe pot implementa doar la obiecte care derivează din clasa DependencyObject
Toate elementele WPF derivă din DependencyObject
Daca intr-o clasa vrem sa implementam Dependency properties, acea clasa va trebui sa mosteneasca din DependencyObjectSunt implementate ca si proprietăți WPF cu fucționalitate adițională
Pasi utilizati la implementarea unui DependecyProperty1. in clasa care moșteneste din DependencyObject se declară o variabilă publică, statică si
read-only (doar cu getter) de tipul DependencyPropertypublic static readonly DependencyProperty FlavorProperty;
2. se crează un constructor static care inregistrează proprietateastatic PieClass() {
FrameworkPropertyMetadata md = new FrameworkPropertyMetadata();
PieClass.FlavorProperty = DependencyProperty.Register("Flavor",
typeof(string), typeof(PieClass), md);
}
103
Dependecy properties (II)3. se crează proprietatea wrapper care permite DependencyProperty să fie accesată in codpublic string Flavor
{
get {
return (string)GetValue(PieClass.FlavorProperty);
}
set {
SetValue(PieClass.FlavorProperty, value);
}
}
Se utilizeaza GetValue si SetValue pt setarea valorii proprietății si nu in mod obisnuit
104
Dependecy properties (III)Se poate furniza o metodă callback care să se execute cand valoarea proprietății se schimbă
static PieClass()
{
FrameworkPropertyMetadata md = new FrameworkPropertyMetadata(new
PropertyChangedCallback(FlavorPropertyChanged));
PieClass.FlavorProperty = DependencyProperty.Register("Flavor",
typeof(string), typeof(PieClass), md);
}
private static void FlavorPropertyChanged(DependencyObject o,
DependencyPropertyChangedEventArgs e)
{
// Implementation omitted
}
105
Crearea controalelor utilizator1. se crează un proiect de tipul WPF User control library2. se crează interfata noului control prin drag&drop de pe toolbox sau prin utilizarea XAML3. se adaugă functionalitatea nouă. Se pot implementa dependecy properties sau routed events
106
Crearea controalelor customLa crearea unui custom control, se crează un folder Theme care contine fisierul Generic.xaml – va contine template-ul default pt control – care poate fi alterat pt a crea noul template1. se crează un proiect nou de tipul WPF Custom Control library2. in solution explorer se editeaza Generic.xaml din Theme3. in xaml putem crea template-ul pt control3. se poate adauga functionalitatea dorită. Putem implementa proprrietati, dependecy properties si routed events.
107
Utilizarea controalelor utilizator/custom1. in solution explorer, se da right-click pe proiect si apoi Add reference2. Se face browse si se selecteaza dll-ul care contine controlul utilizat3. in xaml se face referire la assemblyul nou adaugat
xmlns:cc="clr-namespace:WpfCustomControlLibrary1;
assembly=WpfCustomControlLibrary1"
4. in xaml se adaugă noul control<cc:CustomControl1 />
5. se face build
108
ThemePentru controale custom – acestea se afisează consistent cu tema aleasăClasele SystemColors, SystemFonts, SystemParameters – se furnizează unelte pentru construirea/customizarea temeiCand utilizatorul schimba tema, culorile, fonturile si parametrii sistem sunt update-uiti automat la cele din tema aleasă Aceste setări se pot accesa din sectiunea de resurse:
<Label Background ="{DynamicResource {x:Static
SystemColors.ControlBrushKey}}" Content="Hello World" />
Sau din cod:label1.Background = SystemColors.ControlBrush;
109
Medii de dezvoltare – curs 5- - Informatică Economică, an III –
Cristian Bologa
Accesul la date in .NET Framework ADO.NET modelul de bază
Cluj-Napoca - 7 Decembrie 2015
ADO.NETFramework flexibil prin care se realizează accesul aplicațiilor .NET Framework la date
Aplicatii Windows Aplicatii web
Tipuri de date suportate Baze de date relationale si non-relationale Depozite de date de tip XML Date provenind de la aplicații
Reprezintă fundamentul pentru tehnologii noi de acces la dateCodul de access la date este strâns legat de date
Dacă se schimbă structura datelor => schimbări in codul sursă .NET Se lucrează la nivelul modelului logic al datelor
Se furnizează clase de access la SQL Server, XML, OleDB, ODBC
Modele de access la date in ADO.NET
Accesul la date in ADO.NETClase din namespace-ul System.Data
Obiecte de tip Connection:-Obiecte de tip SqlConnection => pt lucrul cu date provenind de pe
SQL Server-Obiecte de tip OleDbConnection => pt lucrul cu date de pe alte
servere relaționale
Obiecte de tip Command –utilizeaza comenzi SQL sau proceduri stocate. Rezulta niste streamuri care pot fi citite prin DataReader-e sau incarcate in obiecte de tip DataSet. Avem 2 clase:
-Command.System.Data.SqlClient.SqlCommand -System.Data.OleDb.OleDbCommand
Ce este un DataReader?
Lucrul in mod conectatObiectele connection gestioneaza conexiunea cu serverul de dateObiectele Command sunt wrappere pentru comenzi SqlDataAdapter contin obiecte de tip CommandSelectCommand aduce date in DataReader – care poate fi iterat
Modelul deconectat de acces la dateAccess deconectat: in aplicație se mentine un obiect care reprezinta un cache local de date (DataSet)Obiectele de tip DataAdapter folosite pentru a realiza comunicarea intre obiectul DataSet (local) si serverul de date
DataSetReprezintă o copie locală a bazei de dateFurnizează un mediu relațional de programare, prezentând o vedere relațională asupra datelorStochează date similar cu stocarea datelor intr-o bază de date relationalăEste compus din obiecte de tip DataTableProprietatea Tables: colecție cuprinzând tabelele din DataSetProprietatea Relation: colectie a relatiilor ce leaga tabeleleDataSet tipizat (typed):
mediul de programare a construit clase pentru DataSet si pentru fiecare tabelă a datasetului
Tabelele pot fi accesate prin numeObiectDataSet.numeTabelă Datele din tabele pot fi accesare prin numeObiectDataTable.numeColoana
DataSet netipizat (untyped): Se folosesc clasele standard (DataSet, DataTable, DataRow etc) Tabelele se accesează prin numeObiectDataSet.Tables[“NumeTabela”] Datele se accesează prin numeObiectDataTable.Rows[“numeColoană”]
DataTableDataTable: o tabelă a unui BD, conținând randuri (DataRow), coloane (DataColumn) si constrângeri La un moment dat, un obiect de tip DataTable conține o copie locală a datelor dintr-o tabelă din sursa de dateproprietatea Rows: o colecție de obiecte de tip DataRow, conține datele tabeleiProprietatea Columns: o colecție de obiecte de tip DataColumn, conține metadatele tabelei
DataAdapterFolosit ca și o punte pentru a muta datele intre obiectul DataSet si sursa de dateAsigură operațiile de transfer de date între sursa de date și obiectul DataSet
Modificarea datelor din DataSetObiectele DataTable pot contine date in 3 versiuni:
Original, curent si proposed
La incarcarea datelor in DataTable datele sunt in starea currentOperatia BeginEdit: pune linia in mod edit iar datele modificate devin versiunea Proposed;Operatia EndEdit: versiunea Current devine Original, versiunea Proposed devine CurrentA 2-a operatie BeginEdit: versiunea Current devine ProposedLa o nouă operatie EndEdit: versiunea Proposed devine CurrentEtcMetoda AcceptChanges: resetează starea unui DataRow la unchangedAcceptChanges se apelează după un update a datelor către serverul de dateRejectChanges: face roll-back la date sau la momentul crearii sau la ultimul apel a lui AcceptChanges -> se copiază inapoi datele din versiunea Original
Viziunea asupra unui DataSetEste o BD relatională in memorie – cached dataNu furnizează proprietăți tranzacționale: atomicitate, consistență, izolare și durabilitateContine colecții de DataTable si DataRelationDataTable contine chei unice si străine pentru integritatea datelorSe poate crea un DataSet in mod programatic sau prin furnizarea unei scheme XML – .xsdDataSet editor: se permite crearea si editarea grafica a unui fisier xsd pe baza caruia se crează clase DataSet tipizate
In meniul Project , Add new item, se selectează DataSet
Entity Data ModelsModelul fizic: modul de stocare a datelor in BD
Modelul logic: Construit pe baza modelului fizic Descrie modul in care datele sunt salvate in tabele – studiat la disciplina
BDE
Modelul conceptual: Mapat pe modelul logic O vedere business asupra datelor astfel incat să se evite operații join
complexe
Entity data model: modelul conceptual definit in .NET Entity FrameworkEntity framework: convertește functionalitatea de business in comenzi compatibile la nivelul sursei de date
Strategii de proiectare a modelelor1. Database design first
Prima dată se crează BD-ul, apoi se proiectează entitățile din aplicație Este strategia preferată de administratorii de BD, poate limita
flexibilitatea aplicației pe termen lung
2. Model design first Mai intâi se proiectează entitățile aplicației apoi se crează BD-ul in jurul
acestora Este strategia preferată de programatori
3. Code-design only Modelul este generat doar la run-time
1 si 2 suportate in .NET Framework
Entity designerEntity data model wizard: generarea modelelor, update pt modele existente, crearea BD-urilor
Mapping details Model browser
Medii de dezvoltare – curs 6- - Informatică Economică, an III –
Cristian Bologa
Data binding
124Cluj-Napoca - 9 Decembrie
2015
Data bindingLegarea proprietăților unor controale de dateSe poate orice proprietate a unui element de orice obiect, proprietate, colecție sau sursă de dateData binding: procesul de creare a dependenței dintre valoarea unei proprietăți (target property) de valoarea unei alte proprietăți (source property)
Modificarea valorii proprietății sursă se poate transmite imediat (sau nu) proprietății țintă
Modificarea valorii proprietății țintă se poate transmite imediat (sau nu) proprietății sursă
125
Clasa BindingDescrie relația dintre proprietățile țintă si sursă
Proprietăți ale clasei Binding:ElementName: setter sau getter pentru elementul sursăFallbackValue: valoarea care va fi utilizată atunci când legarea nu poate produce o valoare clarăMode: direcția fluxului de date intre țintă și sursăNotifyOnSourceUpdate: indică dacă evenimentul SourceUpdated să fie lansat atunci cand se transferă o valoare de la țintă la sursăNotifyOnTargetUpdate: indică dacă evenimentul TargetUpdated să fie lansat atunci când se transferă o valoare de la sursă la țintăPath: calea către proprietatea sursă a obiectului sursă a BindinguluiRelativeSource: sursa relativă a bindingului, in funcție de poziția elementului tintă. Source: obiectul care va fi folosit ca si sursă a legăturii. Utilizat doar când ținta nu este un obiect WPFTargetNullValue: valoarea folosită la țintă atunci când valoarea sursei este Null
!Nu exista o proprietate in clasa Binding care sa specifice obiectul target sau proprietatea target. Nu se specifică obiectul țintă. Binding-ul automat va transmite valoarea obtinuta de la proprietatea sursa la proprietatea destinatie.
126
Legarea unei proprietăți a unui element WPF de o altă proprietate a unui alt element
<Label Content="{Binding ElementName=Slider1, Path=Value}" Height="25" Width="100/>
sau<Label Height="25" Width="100">
<Label.Content>
<Binding ElementName="Slider1" Path="Value" />
</Label.Content>
</Label>
sauBinding aBinding = new Binding();
aBinding.ElementName = "Slider1";
aBinding.Path = new System.Windows.PropertyPath("Value");
Label1.SetBinding(ContentProperty, aBinding);
BindingOperations.ClearBinding(this.Label1, ContentProperty);
127
Legarea către un obiectSe foloseste Source pentru a indica obiectul sursă
Poate fi orice obiect accesibil in XAML Dacă se face legare către obiecte non-WPF, un exemplu este legarea
către obiecte statice precum culoare si fonturile system<Button Background="{Binding Source={x:Static SystemColors.WindowColor}}"
Height="23" Width="75">Button</Button>
128
Legarea către un obiect – resursă logică
Legarea către o proprietate din clasa aplicației<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:aClass x:Key="theObject" />
</Window.Resources>
<Grid>
<Button Content="{Binding Source={StaticResource theObject},
Path=myProperty}" />
</Grid>
</Window>
- Importa namespace-ul WpfApplication1- Crează obiectul theObject din clasa aClass- Leagă proproprietatea Content a butonului de proprietatea myProperty a obiectului
129
Proprietatea DataContextNu este absolut necesar să setăm proprietatea Source pentru a crea un Data Binding. Putem utiliza DataContext pentru pentru a lega ținta de un element (obiect) sau un container din arborele vizualWPF verifică proprietatea DataContext in cazul in care proprietățile Source, RelativeSource sau ElementName nu sunt setateLa interpretarea DataContext se incepe cu elementul specificat, iar dacă acesta este null, se continuă cu inspectarea ascendentă a arborelui vizual până la identificarea unui element nenulObiectul specificat de către DataContext va reprezenta obiectul sursă pentru toate legările din arborele vizual care care nu au setat un Source, ElementName sau RelativeSource
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Window.Resources> <local:myDataClass x:Key="aDataObject" /> </Window.Resources>
<Grid DataContext="{StaticResource aDataObject}">
<Label Content="{Binding Path=myTitle}" />
</Grid>
</Window> 130
Utilizarea DataContextSe setează DataContext in cod cu un obiect sursă de date (de exemplu ADO.NET)
myDataClass aDataObject = new myDataClass();
Grid1.DataContext = aDataObject;
Se setează bindingul pentru pentru diverse controale de pe interfată la proprietăți ale obiectului sursă de date
<Grid Name="Grid1">
<Label Content="{Binding Path=myTitle}" />
</Grid>
Controlul va afișa valoarea sursă de date doar la setarea acesteia in cod
131
Binding ModeDetermină cum se comportă controalele la schimbări ale valorilor in sursă / țintăDefault: obiectul Binding folosește modul implicit al proprietății țintăOneTime: obiectul Binding trebuie să reimprospăteze proprietatea ținta când se pornește aplicația sau când se schimbă data contextul, dar nu se reimprospătează la alte modificări ulterioareOneWay: se modifică proprietatea țintă atunci cand sursa se modifică
Pentru afișări de informații
OneWayToSource: se modifică proprietatea sursă cand proprietatea tintă se modifică. Schimbări in sursă nu au efect la schimbarea proprietății țintăTwoWay: orice modificare in sursă se reflectă în țintă și invers
Pentru editări de informații
132
Binding la o valoare nullSe poate furniza o valoare implicită prin setarea proprietății TargetNullValue – in caz că valoarea sursă este null
UpdateSourceTrigger Controlează modul in care proprietatea sursă este actualizatăDacă proprietatea Binding.Mode este setată la TwoWay sau OneWayToSource, schimbările in target se reflectă in sursăUpdateSourceTrigger controlează frecvența acestor transferuriDefault: proprietatea sursă se modifică in concordanță cu valoarea implicită a proprietății țintă.
Valoarea implicită PropertyChanged: sursa se modifică dacă tinta se modificăExplicit: proprietatea sursă este modificată doar la apelul Binding.UpdateSource()LostFocus: sursa este modificată la LostFocus pe controlul tintă.
Este folosit la proprietățile susceptibile a fi editatePropertyChanged: proprietatea sursă este modificată la orice modificare a tintei
133
Conversia datelorImplementarea IValueConverter
Metoda Convert: converteste inputul la tipul output ConvertBack: conversia inversă
Clasa care implementează IValueConverter trebuie adnotată cu atributul ValueConversion care specifică tipurile intre care are loc conversia
[ValueConversion(typeof(int), typeof(string))]
134
Formatarea datelorSe utilizează converteri
Formatarea ca si o valută:aString = aDouble.ToString("C");
Se poate insera această formatare intr-un converterSe utilizează proprietatea culture pt a insera tipul potrivit de valută
Formatarea datelord/D – dată scurtă/lungă, f/F – dată lungă si timp scurt/lung G - generalM – lună si zi
135
Converteri pentru localizareParametrul culture: se poate examina pentru a returna date localizate
string aString = (string)value;
switch(culture.ToString())
{
case "de-DE":
return myTranslator.EnglishToGerman(aString);
case "fr-FR":
return myTranslator.EnglishToFrench(aString);
default:
return aString;
}
136
Validarea datelorValidarea: presupune asigurarea faptului că datele din control sunt conforme cu specificările tipuluiObiectul Binding expune colecția ValidationRulesTrebuie specificata o clasă care să implementeze regula de validare
<TextBox>
<TextBox.Text>
<Binding Path="CandyBars">
<Binding.ValidationRules>
<local:CandyBarValidationRule />
<local:SweetTreatsValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
137
validareDacă regulile de validare sunt violate:
Elementul supus validării este prezentat cu rosu Proprietatea Validation.HasError este true Se crează obiect de tipul ValidationError care este adaugat in
colectia Validation.Errors Daca Binding.NotifyOnValidationError este setat la True si se
aruncă evenimentul Validation.Error atasat evenimentului Sursa de Data binding nu se modifică (valoarea ce nu satisface
regulile de validare nu actualizeaza sursa data binding-ului).
Daca setam ExceptionValidationRule: toate exceptiile aruncate in procesul de data binding sunt raportate ca si erori de validare
Astfel, o exceptie netratata nu va opri executia programului ci va creea o eroare de validare
138
Implementarea unei reguli de validare
Se creeaza o clasa care mosteneste clasa abstractă ValidationRuleSe suprascrie metoda Validate –primeste ca si parametru un obiect care reprezinta valoarea care trebuie evaluataReturnează un obiect ValidationResult care conține proprietățile
IsValid – true daca valoarea este validă. Avem false daca valoarea nu este validă si se creaza un obiect ValidationError
ErrorCondition – textul de eroare in cazul in care IsValid este false
139
Tratarea erorilor de validareElementul tintă a erorii se marchează cu rosuApare evenimentul Validation.Error cu argumente
Proprietatea Action: dacă eroarea este nouă sau este o eroare veche Error: eroarea efectivă
Evenimentul Validation.Error se aruncă doar dacă proprietatea NotifyOnValidationError este setată la trueValidation.Error este un bubbling event
140
Legarea la o listă2 situații:
Legarea unui singur element la o listă de obiecte și facilitarea navigării in lista de obiecte
Legarea unei colecții (precum elementele unui ListBox) la o listă de obiecte astfel incat toate elementele listei sunt afisate
Legarea proprietății Item la o listă de obiecteDisplayMemberPath: proprietatea colecției sursă care va fi utilizată pentru a crea textul care se afișează pentru fiecare elementIsSynchronizedWithCurrentItem: daca itemul sursă selectat este tinut sincronizat cu proprietatea CurrentItem din colectia ItemItemsSource: reprezintă colecția sursă ItemTemplate: template-ul folosit pentru vizualizarea datelor
In cod se seteaza DataContext la numele listei sursă de obiecteIn XAML prin DisplayMemberPath se selectează proprietatea sursei care să se afiseze
141
Legarea unei proprietăți la o listă sursă
Se setează DataContext-ul in codul sursăSe foloseste Binding Path pentru specificarea proprietății care să se afiseze
La legarea unei colecții sursă de un element tintă singular, se crează in spate un obiect de tipul ICollectionView
Memorează starea curentă (de navigare) in colecție, vederi, grupări si sortări ale elementelor
CurrentItem: proprietatea returneaza itemul curentCurrentPosition: pozitia curentă – numerică a elementului curentIsCurrentAfterLast: dacă itemul curent este după ultimul item din colecțieIsCurrentBeforeFirst: itemul curent este inaintea primului din colecțieMoveCurrentTo / MoveCurrentToLast / MoveCurrentToFirst / MoveCurrentToNext / MoveCurrentToPrevious: setarea itemului curent
System.ComponentModel.ICollectionView myView;
myView = CollectionViewSource.GetDefaultView (myCollection);
142
Legare de obiecte ADO.NETNavigarea intr-o tabela prin controale din GUI
Se setează DataContext la obiectul DataTable Se setează obiectul Binding la nimic Se setează DisplayMemberPath la proprietatea care se afisează –
pentru controalele de tip lista Se setează proprietatea Path pentru controalele individuale
Dacă se setează DataContext la obiectul DataSet, trebuie să se seteze proprietatea Path la obiectul DataTable corespunzător
Fereastra DataSource din VS permite drag&drop la campuri din sursele de date
Se defineste automat obiectul de tip CollectionViewSource
143
Legare către tabele legate prin DataRelation
Obiecte DataRelation: chei straine care exprimă relatii dintre 2 tabeleleRealizarea unui Binding către:
ParentTable reprezintă tabela părinte Relation reprezintă o relatie de la tabela parinte ParentTable Relation2 reprezintă o relatie de la tabela copil a tabelei
ParentTable{Binding Path=ParentTable/Relation/Relation2}
144
Legare prin ObjectDataProviderPermite legarea unui element sau proprietăți la o metodă apelată pe un obiect
Proprietăți ale ObjectDataProviderConstructorParameters: lista parametrilor transmisi la contructorIsAsynchronous: daca crearea obiectelor sau apelul metodelor se face in threadul curent sau unul in backgroundMethodName: numele metodei obiectului sursă care va fi apelataMethodParameters: lista parametrilor transmisi metodeiObjectInstance: obiectul utilizat ca si sursăObjectType: tipul obiectului sursă
145
DataTemplateDescrie cum vor fi afisate datele sursă legate de un control tintăPoate contine elemente care sunt legate (fiecare) de date sursăPoate contine elemente de layout, culoare sau alte aspecte legate de afisarePentru controalele care au proprietatea Content: ContentTemplatePentru controalele care au proprietatea Item: ItemsTemplateDisplayMemberPath si ItemsTemplate se exclud mutualDe obicei, DataTemplate se defineste ca si o resursă
146
Medii de dezvoltare – curs 7- - Informatică Economică, an III –
Cristian Bologa
Accesul la date in .NET Framework - LINQ
147Cluj-Napoca - 14 Decembrie
2015
LINQProbleme la transferul de date între aplicație si sursa de date
Modul de tratate (diferit) al valorilor Null (impedance mismatch) Modul de transmitere a comenzilor către serverul de date: string in ghilimele. Daca
apare eroare serverul de date arunca o exceptie
LINQ: language integrated queryPermite să creem operatii de tip interogare, update si transformări in sintaxa limbajului de programareLucrează cu colecții de tip IEnumerable -> au metoda GetEnumerator
IEnumerable<string> results = from c in colors
where c.StartsWith("B")
orderby c
select c;
Deffered execution O interogare LINQ este un obiect generic de tipul Ienumerable variabila la care rezultatul e asignat (results) este un range variable nu este o colectie populată, LINQ nu accesează sursa de date decât la utilizarea
obiectului care lucrează cu results –e cunoscuta sub numele de deffered execution
148
LINQ providersLINQ: middle tier intre locul de stocare a datelor si aplicațiePentru a crea un LINQ provider trebuie implementata interfata IQueryable
149
Initializarea obiectelorObject initializer:Se execută default constructorul generat de compilator si apoi se asignează proprietățile cu valori
Car c = new Car() { VIN = "ABC123", Make = "Ford",
Model = "F-250", Year = 2000 };
Similar se pot initializa colecțiile, ca si elemente de tip ListCollection initializer:
List<Car> lc = new List<Car>
{
new Car {VIN = "ABC123",Make = "Ford", Model = "F-250", Year = 2000},
new Car {VIN = "DEF123",Make = "BMW", Model = "Z-3", Year = 2005}
}
150
ProiectiiProjection: transformare asupra datelor astfel incat in urma unui select LINQ să obtinem outputul in tipul dorit
string[] colors = {“Red”, “Brown”, … }
IEnumerable<Car> fords = from c in colors where c.Length == 5
orderby c
select new Car() {
Make = "Ford",
Color = c
};
foreach (Car car in fords)
{ txtLog.AppendText(String.Format("Car: Make:{0} Color:{1}"
+ Environment.NewLine, car.Make, car.Color));
}
151
Declararea variabilelor locale cu tip implicitvar cars = GetCars();
Se interogheaza compilatorul asupra tipului variabilei cars și acest tip se asignează implicit
Nu putem avea valoarea null in dreapta operatorului de atribuireDupă momentul in care compilatorul decide tipul variabilei cars,
acest tip nu mai poate fi schimbatVariabile cu tip implicit pot fi doar variabile locale, nicidecum tip de
argumente de metode
152
Tipuri anonimevar x = new {Make = "VW", Model = "Bug"};
txtLog.AppendText(x.Make + ", " + x.Model);
IntelliSense stie ca tipul lui x are proprietățile Make si ModelLINQ foloseste tipuri anonime pentru a implementa proiectii
var carData = from c in GetCars()
where c.Year >= 2000
orderby c.Year
select new
{
c.VIN,
MakeAndModel = c.Make + " " + c.Model
};
dgResults.DataSource = carData.ToList();
153
Expresii lambda (I)Reprezintă un soi de metode anonime cu sintaxa abreviată
Ex: metoda Find a clasei List<T>: accepta ca si parametru un delegate Predicate Tipul acestui delegate: referintă la o metodă care acceptă la intrare un argument
de tipul T si returnează un boolean Find iterează pe colecție, aplică metoda din Predicate pe toate elementele si
returnează doar acele elemente pe care metoda returnează true Problemă: tipul predicatului trebuie să fie identic cu tipul colecției
int yearToFind = 2000;private void toolStripMenuItem_Click(object sender, EventArgs e) { var cars = GetCars(); yearToFind = 2000; var found = cars.Find(ByYear);txtLog.AppendText(string.Format("Car VIN:{0} Make:{1} Year{2}" + Environment.NewLine, found.VIN, found.Make, found.Year));}private bool ByYear(Car c) { return c.Year == yearToFind; }
154
Expresii lambda (II)private void lambdaExpressionsToolStripMenuItem_Click(object sender, EventArgs e) {
var cars = GetCars();
var theYear = 2000;
var found = cars.Find(c => c.Year == theYear);
txtLog.AppendText(string.Format("Car VIN:{0} Make:{1} Year{2}" + Environment.NewLine,
found.VIN, found.Make, found.Year));
}
Partea stanga declară parametrii, separați prin ,După semnul => avem expresia care se evalueazăExpresia poate fi compusă din mai multe instructiuni
var found = cars.Find(c =>{ int x; x = theYear; return c.Year == x;});
155
Metode extensiiPutem adăuga metode unui tip chiar dacă nu avem codul sursă pentru tipul respectivProblemă: să adaugăm o metodă isNumeric clasei stringSoluție clasică: creem o clasă StringHelper care să conțină toate metodele noi pe care dorim să le adăugăm iar aceste metode să preia o valoare de tip string ca și prim parametru
public static class StringHelper {
public static bool IsNumeric(string str) {
double val;
return double.TryParse(str, out val);
} }
Avantaj al acestei soluții: nu trebuie să instanțiem un obiect de tip string pt a folosi metoda IsNumeric (metoda e statică)Dezavantaj: trebuie să știm că clasa StringHelper există
156
Metode extensiiExtension method: putem crea o clasă public static iar metoda nouă să o facem membră a acestei claseSe foloseste cuvantul cheie this inaintea primului parametru pentru a se indica faptul că metoda este o extensie a acestuia
public static class StringHelper {
public static bool IsNumeric(this string str)
{
double val;
return double.TryParse(str, out val);
}
}
string s = "abc123";
txtLog.AppendText(s.IsNumeric() + Environment.NewLine);
Metodele extinse sunt arătate de către IntelliSense
157
Metode extensii pentru regăsire Se pot adăuga metode extensii pentru interfețe
string[] colors = {"Red", "Brown", "Orange", "Yellow", "Black"}
IEnumerable<string> colorEnumerable = colors;
colorEnumerable are toate metodele interfeței Ienumerable (query extension methods)
158
LINQ keywordsfrom: specifică sursa de date sau variabila de tip rangewhere: filtreaza elementele sursă pe baza unei/unor expresii booleeneselect: specifică tipul elementelor returnate la execuția interogăriigroup: grupează elementele rezultat in funcție de o cheie specificatăinto: furnizează un identificator care poate fi utilizat ca si o referință către rezultatele unui join, group sau selectorderby: sortează rezultatele interogăriijoin: unește 2 surse de date pe baza egalității dintre 2 criterii specificatelet: introduce o variabilă pentru a salva rezultatul unei subexpresiiin: folosit in join sau from, pentru a specifica sursa de dateon: folosit in join pentru a specifica clauza (criteriul) de joinequals: folosit in join pentru a specifica egalitateaby: folosit in group by, pentru a specifica clauza de grupareAscending/descending: folosite in orderby
159
Proiecții si letSe poate utiliza let pentru a crea o variabilă temporară in interiorul unei interogări
var vinsAndMakes = from c in cars
let makeModel = c.Make + " " + c.Model
where makeModel.Contains('B')
select new { c.VIN, MakeModel=makeModel };
160
whereClauza where se mapează direct pe o metodă extensie Where care realizează filtrareaSe poate specifica un predicat (expresie ce se evalueaza la o valoare booleana) pentru a determina elementele ce vor fi returnate
int yearRange = 2000;
var cars = GetCars();
var oldCars = from c in cars
where c.Year < yearRange
select c;
orderbyPermite sortare crescător / descrescătorSe poate sorta pe mai multe proprietăți
var sorted = from c in cars
orderby c.Make ascending, c.Model descending
select c;
161
PaginareEste necesară atunci cand interogările returnează o colecție mare de dateMetodele extensie Skip si Take
int pageSize = 10;
//create 5 copies of the cars - total 25 rows
var cars = Enumerable.Range(1,5).SelectMany(i=>GetCars()
.Select(c=>(new {BatchNumber=i, c.VIN, c.Make, c.Model, c.Year})));
//calculate page count
int pageCount = (cars.Count() / pageSize);
if (pageCount * pageSize < cars.Count()) pageCount++;
for(int i=0; i < pageCount; i++) {
txtLog.WriteLine("-----Printing Page {0}------", i);
var currentPage = cars.Skip(i * pageSize).Take(pageSize);
foreach (var myCar in currentPage) {
txtLog.WriteLine("#{0} Car VIN:{1}, Make:{2}, Model:{3} Year:{4}",
mCar.BatchNumber, myCar.VIN, myCar.Make, myCar.Model, myCar.Year);
}
}
162
JoinPermite realizarea operatiei de Join pe 2 colecții de tip IenumerableSunt 3 tipuri de join
Inner join Outer join Cross join – produs cartezian intre cele 2 multimi
163
Inner joinSimilar cu join-ul din SQLProduce rezultat doar dacă este o potrivire de chei intre ambele surse de joinSe foloseste equals si nu semnul =
var cars = GetCars();var repairs = GetRepairs();var carsWithRepairs = from c in cars join r in repairs on c.VIN equals r.VIN // nu = orderby c.VIN, r.Cost select new { c.VIN, c.Make, r.Desc, r.Cost };
164
Outer joinProduce rezultat pentru fiecare element din colectia outer chiar daca pe colectia inner nu se identifica o potrivire de cheiSe foloseste clauza into pentru a specifica o referinta la rezultatul joinului
var cars = GetCars();var repairs = GetRepairs();var carsWithRepairs = from c in cars join r in repairs on c.VIN equals r.VIN into g from r in g.DefaultIfEmpty() orderby c.VIN, r==null?0:r.Cost select new { c.VIN, c.Make,Desc = r==null?"***No Repairs***":r.Desc,Cost = r==null?0:r.Cost };
165
Cross joinProdus cartezian intre 2 elemente sursa Se foloseste clauza from de mai multe ori
var carsWithRepairs = from car in cars
from color in colors
orderby car.VIN, color
select new
{
car.VIN,
car.Make,
car.Model,
Color=color
};
166
LINQ to SQLPermite gestionarea BD relationale ca si obiecteObject-relational model (ORM) tool, permite interogări, update, insert, delete
Generarea unui model LINQ to SQL dintr-o BD existentă Add new item -> LINQ to SQL classes -> se crează un fișier dbmlSe poate face drag & drop pt adaugarea de tabele la modelSe pot adauga proceduri stocate prin drag&drop
Acestea devin metode ale modelului
167
Examinarea modeluluiLa adaugarea unui tabele se vizualizează (pe fereastra modelului) o clasă cu o inregistrare din tabelă
Designerul face din plural singular in mod implicit (dar tabela movies -> clasa movy)
Se poate schimba numele clasei din fereastra properties proprietatea Name (clasa movie)
Se generează metode la runtime pentru insert, update si delete Acestea pot fi setate din properties către o procedură stocată
Designerul a importat si relatiile dintre tabeleProcedurile stocate vor putea fi folosite ca si metode in modelul LINQ to SQL
Uneori, designerul nu stie sa interpreteze corect tipul de return al procedurii stocate
Daca procedura stocata returneaza un anume tip din model, se poate face drag&drop pe clasa respectiva in model
Se crează o clasă cu numele numeStoredProcedureResult pentru a identifica tipul de rezultat al procedurii stocate
168
Clasa DataContextE responsabilă cu mutarea datelor intre obiectele din program si baza de dateSe utilizează o instantă din clasa derivată din DataContext pentru a folosi proprietățile si metodele care furnizează accesul la baza de dateObiectul mappingSource agregat de clasa DataContext mentine potrivirea (mapping) intre clasele din model si baza de datePentru conectarea la un SQL Server, DataContext foloseste obiect de tipul SQLConnection
Proprietatea Connection
Exemplu de lucru cu obiectul DataContextvar ctx = new NorthwindDataContext();
var employees = from emp in ctx.Employees
where emp.LastName.StartsWith("D")
select emp;
dg.ItemsSource = employees;
Proprietatea Log a obiectului DataContext: se loghează toate comenzile trimise către BDSe poate atasa un StringWriter
169
Interogari folosind LINQ to SQLObiectul DataContext furnizează cate o proprietate pt fiecare tabelăAcestea sunt vazute ca si colecții .NET=> se pot folosi toate facilitățile LINQ descrise la inceputul cursuluiSe pot folosi inner/outer/cross join, agregare (GROUP) sau sortare etcSe pot folosi projectionSe pot folosi expresii lambda
170
Gestiunea modificarilor in obiecteSimilar cu Java, numele de variabile reprezintă referință către obiectAliasing functioneazăObiectul DataContext gestionează identitatea obiectelor din BD:
Inregistrările regăsite din tabele sunt automat logate in tabela de identități (internă obiectului DataContext) cu ajutorul cheii primare
Dacă același rând este regăsit incă o dată prin intermediul aceluiasi obiect DataContext, acesta returnează instanța originală a rândului
Aplicația vede starea rândului Deci nu se văd modificări asupra inregistrării realizate de către alte
obiecte DataContext
Metoda SubmitChanges: trimite modificările către BD
171
Ciclul de viață al unei entitățiModificarile realizate intr-o entitate rămân persistente (salvate in baza de date) doar la apelul SubmitChanges (din obiectul de tip DataContext)Obiectul DataContext memorează informație despre obiectele entitate
Identity tracking service
172
Stări ale unui obiect entitateUntracked: obiectul nu este tracked de către LINQ to SQL in următoarele cazuri
Obiectul este instantiat de către programator Obiectul a fost creat prin deserializare Obiectul a fost regăsit printr-un alt obiect DataContext
Unchanged: obiectul a fost regăsit prin obiectul DataContext si nu a fost modificatPossiblyModified: obiectul este atașat unui DataContext si va fi in această stare până când se specifică altfelToBeInserted: obiectul nu a fost regăsit prin intermediul DataContext curent si urmează să fie inserat prin insertToBeUpdated: obiectul a fost modificat de la ultima regăsire și DataContext urmează să trimită un updateToBeDeleted: obiectul a fost marcat pt delete, si DataContext urmează să trimită un deleteDeleted: obiectul a fost sters (delete) din Bd, este marcat ca si final, nu se mai pot face modificări pe el
173