Programarea aplicaţiilor Windows în .NET Framework

10

Click here to load reader

description

Programarea aplicaţiilor Windows în .NET Framework

Transcript of Programarea aplicaţiilor Windows în .NET Framework

Page 1: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

Programarea aplicaţiilor Windows în .NET Framework

.NET Framework asigură şi uneltele şi tehnologiile necesare dezvoltării aplicaţiilor distribuite, atât Windows, cât şi Web, inclusiv servicii Web.

Prin arhitectura sa .NET Framework asigură suportul necesar proceselor de compilare şi rulare, necesare dezvoltării aplicaţiilor .NET.

În acest articol îmi propun să prezint aspecte legate de dezvoltarea aplicaţiilor Windows.

Tipuri de aplicaţii Windows

În .NET putem vorbi de două tipuri de aplicaţii: Console Applications şi Windows Applications.

O singură aplicaţie poate avea elemente caracteristice celor de tip consola cât şi celor Windows. De exemplu, într-o aplicaţie consolă putem să introducem o fereastră MessageBox. Compilatorul C# face diferenţa dintre cele două tipuri de aplicaţii printr-un switch numit "target" de pe linia de comandă a acestuia.

/target:exe - pentru aplicaţii consolă

/target:winexe - pentru aplicaţii Windows

Switch-ul target poate lua şi valorile, "libray" sau "module" dacă vrem să generăm module de cod.

Dacă un executabil marcat ca fiind de tip consolă şi este lansat în execuţie direct din Windows, atunci Windows-ul va crea o fereastră consolă pentru aplicaţie. Dacă aplicaţia este pornită dintr-o fereastră Windows, la lansarea în execuţie Windows nu se va deschide nici o fereastră consolă.

Hello World

Aşa ar arăta clasicul "Hello World" scris în C#, ca aplicaţie consolă:

using System; namespace ConsoleApplication { class MyClass { static void Main(string[] args) { Console.WriteLine("Hello World"); } } }

Punctul de start în orice aplicaţie .NET Framework este metoda statică Main. Dacă într-un proiect există două clase, fiecare cu câte o metodă statică Main, atunci trebuie specificat compilatorului va fi folosită ca punct de start pentru firul de execuţie principal.

MessageBox

Dacă dorim să afişăm ferestre de dialog standard, de tipul "MessageBox", putem modifica codul astfel:

using System; namespace ConsoleApplication

Page 2: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

{ class MyClass { static void Main(string[] args) { System.Windows.Forms.MessageBox.Show("Hello World"); } } }

MessageBox este o clasă din namespace-ul: System.Windows.Forms.

Metoda Show face sa apară pe ecran fereastra de dialog. Metoda a fost suprascrisă, având astfel mai multe variante, la care diferă lista de parametri.

Forme

În lumea reală, aplicaţiile Windows nu se rezumă doar la MessageBox, ci folosesc aşa numitele ferestre. În .NET ferestrele sunt implementate de către form-uri. Pentru a crea o fereastră trebuie să instanţiem o clasă "Form" sau una derivată din aceasta. Clasa form o găsim definită în namespace-ul "System.Windows.Forms". După instanţiere, o putem afişa în două moduri: prin apelul metodei "Show" sau prin setarea proprietăţii "Visible" la valoarea True.

using System; using System.Windows.Forms; public class NewForm { public static void Main() { Form form=new Form(); form.Show(); } }

Ce este cu bucla de mesaje? Este un ciclu "while" care se ocupă cu extragerea şi tratarea mesajelor din coada de mesaje, În . NET Framework un astfel de mecanism este implementat cu ajutorul clasei "Application".

public class NewForm { public static void Main() { Form form=new Form(); form.Show(); Application.Run(form); } }

Daca se doreşte terminarea aplicaţiei, se apelează metoda statică "Application.Exit()", care trimite mesajul WM_QUIT în coada de mesaje a aplicaţiei.

Deşi se pot crea forme direct din clasa "Form", este preferabil să folosim clase care o moştenesc-cazul designer-ul de forme din Visual Studio.NET.

Să creăm un proiect nou de tip "Windows Application" în C#, iar în forma creată automat, adăugăm un textbox şi un button, prin "tragerea" lor de pe ToolBox.

Page 3: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

Între directivele #region şi #endregion, găsim codul generat automat de VS.NET, la adăugarea celor două controale pe suprafaţa formei. Acolo unde începe definirea clasei, observăm declaraţiile celor două obiecte - controalele adăugate.

IDispose

Înainte de a continua, fac o mică paranteză. Metoda "Dispose" este declarată în interfaţa "IDispose". În C# avem operatorul "new", dar nu avem complementarul său "delete". Asta deoarece cu dealocările în .NET Framework se ocupă "Garbage Collector". Prin urmare nu avem un control strict când anume şi în ce ordine vor fi dealocate obiectele la care nu mai există nici o referinţă sau au ieşit din domeniul lor de vizibilitate. .NET Framework, pune la dispoziţie o interfaţă "IDispose", care poate fi folosită în mecanismul de moştenire, prin metoda "Dispose". Când un obiect urmează a fi dealocat, "Garbage Collector" verifică dacă acel obiect suportă interfaţa "IDispose" şi dacă da, atunci apelează metoda "Dispose".

"Anchor" şi "Dock"

Toate controale, au în .NET două proprietăţi, ceva cu totul nou faţă de cum erau obişnuiţi programatorii în Visual Basic 6.0, care scutesc de o grămadă de efort: anchor - permite unui control să păstreze distanţa absolută faţă de una sau mai multe margini ale containerului în care se află, prin redimensionarea sa; dock - un control este efectiv, lipit de una din marginile containerului său, modificându-şi şi dimensiunea. Folosind această proprietate putem zice că un control capătă comportamentul unui ToolBar.

Tratarea evenimentelor

Un control sau o formă devin mai utile când putem să şi captăm evenimentele generate de acestea. Dacă vrem să tratăm evenimentul "Click" pe butonul din formă, se selectează tab-ul events din fereastra de proprietăţi a butonului şi se dă dublu-clic pe evenimentul "Click". În acel moment VS.NET generează codul necesar captării evenimentului. Sau am putea scrie manual codul respectiv. Se adaugă o metoda care va trata evenimentul generat de acţiunea de clic pe buton:

private void button1_Click(object sender, System.EventArgs e) { MessageBox.Show("Button"); }

Iar pentru cuplarea acestei metode la evenimentul click trebuie executată următoarea secvenţă:

this.button1.Click += new System.EventHandler(this.button1_Click);

Să zicem că la un moment nu mai vrem să captăm evenimentele de clic pe buton. Pentru aceasta trebuie executată următoarea secvenţă:

this.button1.Click -= new

System.EventHandler(this.button1_Click);

Moştenirea formelor

Sa zicem că avem de dezvoltat o aplicaţie în care există mai multe forme de introducere a datelor. Unele seamănă între ele, singura diferenţă fiind un control nou sau un set nou de butoane. În .NET Framework, o formă este descrisă de o clasă. Prin urmare, formele se pot moşteni. Pentru aceasta, creăm o formă care ar reprezenta intersecţia formelor finale, după care creăm celelalte forme pe baza acesteia. Plecând de la forma pe care tocmai am creat-o să creăm una nouă care mai are doar un

Page 4: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

buton în plus. Mai întâi trebuie dat un "Build" la soluţia noastră ca să avem generat un assembly pe baza căruia se va genera noua formă. Într-un assembly, o formă se găseşte ca metadate. Astfel putem să moştenim o formă în C# care a fost creată în VB sau în Cobol.

Se selectează din meniul "Project", "Add Inherited Form…", după care va apărea o fereastră (vezi figura de sus), unde putem să schimbăm numele fişierului. După ce apăsăm ok, din următoarea fereastră de dialog trebuie să selectăm forma şi assembly-ul în care se găseşte forma pe care vrem să o moştenim. Mai adăugăm aici un buton cu proprietatea "Test" la valoarea "Afişează":

Se observă aici că avem cele două controale moştenite. Proprietăţile acestora apar în culoarea gri şi sunt read-only, deoarece cele două controale au fost implementate în forma de bază ca proprietăţi de tip "private". Puteam opta şi pentru "protected"sau "public".

Ferestre de dialog

Ferestrele de dialog sunt tot nişte forme, dar care sunt afişate "modal", adică până la închiderea casetei de dialog, execuţia programului nu poate continua cu o alta formă.

Crearea formelor modale, pe partea de design nu presupune nimic în plus faţă de crearea formelor obişnuite. Diferenţa apare la modul în care se vor afişa. La cele nemodale, afişarea se face prin apelul metodei "Show" sau prin setarea proprietăţii "Visible" pe true. În cazul celor modale, vom apela metoda

Page 5: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

"ShowDialog()". Aceasta întoarce o valoare de tip enumeraţie, "DialogResult", la fel ca-n cazul clasei "MessageBox".

Dacă dorim ca un buton să aibă comportamentul butonului "OK", atunci trebuie să atribuim proprietăţii "AcceptButton" o referinţă către butonul respectiv:

this.AcceptButton=button1;

În cazul butonului "Cancel", trebuie să atribuim proprietăţii "CancelButton" o referinţă către butonul respectiv:

this.CancelButton=button2;

Ferestre de dialog standard

Aproape toate aplicaţiile Windows afişează pe ecran o fereastră de dialog standard "OPEN", implementată în Windows, şi care poate fi folosită de orice aplicaţie. În .NET Framework avem la dispoziţie un set de clase care ne facilitează accesul la ferestrele de dialog standard din Windows. Acestea sunt:

OpenFileDialog Folosită în cazul deschiderii de fişiere, "Open" din meniul "File".

SaveFileDialog Folosită pentru a selecta un nume şi o cale unde se doreşte să se salveze fişierul.

ColorDialog Folosită pentru selectarea unei culori dintr-o paletă de culori.

FontDialog Folosită pentru selectarea unui font.PrintDialog Folosită pentru a selecta imprimanta pe care

urmează a se efectua tipărirea.PageSetupDialog Folosită pentru a modifica setările imprimantei.PrintPreviewDialog Folosită pentru pre-vizualizarea documentelor care

se doresc a fi tipărite.

Validarea datelor şi controlul ErrorProvider

Mecanismul de validare a datelor este asemănător cu cel din Visual Basic 6. Toate controalele folosite la preluarea datelor de la utilizator au un eveniment numit "Validating", lista de parametri pentru acest eveniment (mai exact a lui delegate şi nu a evenimentului ca atare) este:

(object sender, System.ComponentModel.CancelEventArgs e)

Dacă într-un control datele introduse sunt eronate atunci în metoda de tratare a evenimentului "Validating" pentru acel control, putem executa:

e.Cancel=true;

În urma acestei execuţii controlul nu-şi mai pierde focusul, obligând utilizatorul să introducă o alta valoare.

Evenimentul "Validating" se declanşează când se cere schimbarea focusului pe alt control, dar numai dacă următorul control are proprietatea "CauseValidation" setată pe true.

Page 6: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

În cazul aplicaţiilor Web a devenit o modă ca dacă se introduce o valoare greşită într-un control dintr-un formular, în urma validării să se afişeze un mic semn (ceva cu roşu). În .NET Framework avem la dispoziţie un control care face acelaşi lucru, dar pentru aplicaţiile Windows. Acest control este "ErrorProvider" şi este o alternativă la "MessageBox". Printre proprietăţile lui putem enumera:

-ContainerControl: reprezintă o referinţă către containerul său. Implicit se referă la forma care conţine controlul;

-DataSource: un ErrorProvider este capabil să afişeze şi erorile care se găsesc într-un DataSet. Vom seta această proprietate doar dacă vrem sa o folosim cu un DataSet;

-Icon: Iconul implicit în caz de eroare este o mica bulină roşie cu semnul exclamării alb în interior. Poate fi schimbat printr-o referinţă către un nou obiect de tip Icon.

Acest control expune şi o metodă, care face să apară sau să dispară semnul de eroare.

De exemplu, errorProvider1.SetError(textBox1,"Not an integer value") face ca în partea dreaptă a controlului "textBox1" să apară un icon care indică o eroare, iar dacă poziţionăm mouse-ul deasupra icoanei, va apărea sub formă de "ToolTip" mesajul "Not an integer value".

Crearea controalelor

În .NET Framework controalele Windows Forms sunt componente reutilizabile care încapsulează o funcţionalitate user-interface şi sunt folosite în aplicaţii client-ceva similar cu ActiveX.

Când construim un control avem la dispoziţie trei variante:

Extinderea unui control existent

Dacă se doreşte ca plecând de la un control de tip "TextBox", să creăm un control similar cu un "TextBox", dar care acceptă numai valori numerice.

public class NumericTextBox : System.Windows.Forms.TextBox

În C# constructorii nu sunt moşteniţi. Din această cauză când implementăm constructorul noii clase, trebuie să apelăm constructorul clasei de bază:

public NumericTextBox():base() { ...

Fiind derivată din TextBox, clasa noastră va avea acces la toate proprietăţile, metodele şi evenimentele clasei "TextBox". În cazul nostru suntem interesaţi doar de captarea intrării de la utilizator şi de filtrarea acesteia ca să eliminăm tot ce este alfabetic, adică trebuie să rescriem metoda OnKeyPress:

protected override void OnKeyPress(KeyPressEventArgs e) { int asciiInteger=Convert.ToInt32(e.KeyChar); if(asciiInteger>=47 && asciiInteger<=57) { e.Handled=false; return; } if(asciiInteger==8) {

Page 7: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

e.Handled=false; return; } e.Handled=true; }

Controale compuse

Este situaţia în care controlul este un container pentru alte controale. Clasa acestui control trebuie derivata din: System.Windows.Forms.UserControl

Pentru această categorie avem suport şi din partea designerului existent în VS.NET. Cu el, dezvoltarea unui control compus este similară cu dezvoltarea unei forme.

Custom Contols

Aici discutăm despre controalele care nu moştenesc alte controale şi care se desenează singure prin apeluri directe către GDI+. Clasa acestor controale trebuie derivată din: System.Windows.Forms.Control.

Proprietăţi cu atribute

Pentru fiecare proprietate sau eveniment al unui control sau pentru clasa controlului putem specifica următoarele atribute:

Browsable Indică dacă proprietatea sau evenimentul va fi afişat în fereastra de proprietăţi

Category Afişează proprietatea respectivă într-o anumită categorie în fereastra de proprietăţi

Description Afişează o scurtă descriere în fereastra de proprietăţi când este selectată proprietatea respectivă

DefaultProperty Specifică la nivelul clasei care este proprietatea implicită. La un "TextBox", implicită este proprietatea "Text"

DefaultValue Specifică o valoare implicită pentru proprietateTypeConverter Specifică ce convertor să se folosească la citirea şi

afişarea informaţiilor în fereastra de proprietăţi.Editor Specifică editorul folosit în fereastra de proprietăţi

pentru o anumită proprietate.RefreshProperties Specifică designerului cum şi când să facă refresh-

ul proprietăţii

Data Binding

Nu voi face o prezentare a ceea ce este ADO.Net şi cum anume se foloseşte, ci am să prezint mecanismul în care controalele se pot cupla la sursele de date.

.Net Framework permite cuplarea (binding) nu numai la surse de date de tip ADO ci la aproape toate structurile care conţin date. De exemplu se poate face bind la: colecţii, şiruri, proprietăţi ale altor controale, precum şi la obiecte ADO.Net, cum ar fi coloane din tabele şi view-uri. Mai exact, prin procesul de binding, un control care are o proprietate legată la o sursă de date, la modificarea

Page 8: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

proprietăţii, controlul va cere permisiunea sursei de date, sursa de date controlând valorile pe care le pe poate avea proprietatea legată. Bind-ul poate fi de două feluri:

-Simplu: prin care o proprietate este legată la un singur câmp al sursei de date.

-Complex: când un control este ataşat la o întreagă tabelă de date: cazul în care ataşăm un "DataGrid" la un "DataTable" dintr-un "DataSet".

Sincronizarea dintre controale şi sursa de date este făcută de un obiect numit "CurrencyManager", fiecare sursă de date având ataşată câte o instanţă de CurrencyManager:

Fiecare formă are o proprietate numită "BindingContext" care este o colecţie ce asigură accesul la toate obiectele "CurrencyManager":

Localizarea aplicaţiilor

Când creăm aplicaţii care se adresează unor utilizatori din ţări diferite, se pune problema scrierii interfeţelor grafice în mai multe limbi, precum şi afişarea corespunzătoare a datelor în formatul limbii respective, cum este cazul datei calendaristice. Pentru astfel de aplicaţii trebuie ajut în vedere:

-globalizarea: nucleul aplicaţiei care asigură funcţionalitatea de bază a aplicaţiei, trebuie construit fără modulele care trebuie localizate;

-localizarea: care se realizează prin traducerea modulelor resursă folosite de aplicaţie şi în alte limbi.

Suportul pentru localizare în .NET Framework este asigurat de către clasa "CultureInfo", care conţine informaţii despre limba, ţara, calendarul, convenţiile culturale. Această clasă asigura existenţa unui singur nume pentru fiecare cultură. Dar cel mai bine să facem o aplicaţie ca exemplu.

Creăm un nou proiect de tip Windows Application în C#, pe care-l vom numi "LocalizedApp". Deoarece versiunea mea de Windows 2000 are suport pentru limba româna (la Regional Options în Control Panel) voi alege următoarea politică de localizare: dacă aplicaţia va rula pe un calculator cu setările regionale setate pe română, toate informaţiile vor fi afişate în română, iar pentru orice altă limbă se va folosi limba implicită, limba engleză.

Page 9: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

În fereastra de proprietăţi a formei setez proprietatea "Localizable" pe true, pentru a activa suportul pentru localizare, iar proprietatea language o las pe "Default". Adaug un control "Label" , un edit box lângă acea etichetă şi mai adaug un buton. Schimb proprietatea "Text" a etichetei în "First Name" iar pe cea a butonului în "Show". Să zicem că forma noastră este completă. Acum să facem şi versiunea în română. Din fereastra de proprietăţi a formei pentru proprietatea "Language" selectam "Romanian", după care schimbăm textul celor două controale în "Nume" şi respectiv a butonului în "Mostră".

Dacă în fereastra "Solution Explorer" apăsăm pe butonul "Show All Files" observăm că la forma noastră s-a mai adăugat un fişier cu extensia "resx", în care se vor stoca datele ce ţin de localizarea pentru cea de-a doua limbă, româna. Acum trebuie să facem următoarele modificări în codul formei.

Adăugăm următoarele clauze, Pentru a putea folosi clasele necesare accesării proprietăţilor firelor de execuţie şi "Globalization" pentru a putea folosi clasa "CultureInfo":

using System.Threading;

using System.Globalization;

Iar în constructorul formei adăugăm următoarea secvenţă de cod înainte de apelul lui "InitializeComponents()":

Thread.CurrentThread.CurrentUICulture= Thread.CurrentThread.CurrentCulture;

CurrentThread este o proprietate statică a clasei Thread şi conţine o referinţă către firul de execuţie principal. Fiecare fir de execuţie (thread) are două proprietăţi, "CurrentUICulture" şi "CurrentCulture". Prima este o referinţă către un obiect "CultureInfo" folosit pentru afişarea interfeţei utilizator, iar cea de a doua este o referinţă către un obiect "CultureInfo", creat pe baza informaţiilor luate din "Control Panel - Regional Options".

Compilaţi aplicaţia şi rulati-o. Veţi observa că toate informaţiile sunt în engleză. În "Regional Options" din "Control Panel", în fişa "General", schimbaţi, "Your locale(location)" pe Romanian. Rulaţi din nou aplicaţia. Toate informaţiile se vor afişa în română.

Daca ne uităm în directorul unde compilatorul a depus executabilul, observăm că se mai găseşte un subdirector "ro" ce conţine fişierul "LocalizedApp.resources.dll" - forma localizată în limba română. Versiunea pentru limba implicită - engleza, este inclusă în fişierul executabil. Pentru încărcarea unei resurse se foloseşte un obiect numit "ResourceManager". Vom folosi şi noi un astfel de obiect în secţiunea care urmează.

Localizarea resurselor

Să vedem cum localizăm şi alte tipuri de resurse, cum ar fi şirurile de caractere, utilizând resource manager.

Pentru a folosi clasa "ResourceManager" şi clasa "Assembly" în aplicaţia noastră adăugăm următoarele clauze:

using System.Resources;

using System.Reflection;

Adăugăm proiectului două fişiere de tip resursă. Din meniul "Project" selectăm "Add New Item …", în fereastra de dialog care urmează selectăm ca tip "Assembly Resource File", pe care îl vom numi "MyResource.resx". Acest fişier de resurse îl deschidem pentru editare şi adăugăm un nou articol cu

Page 10: Programarea aplicaţiilor Windows în .NET Framework

www.cartiaz.ro – Carti si articole online gratuite de la A la Z

numele "msg1" şi cu valoarea "The name is:". Mai adăugăm un fişier de tip "Assembly Resource File" pe care-l vom numi "MyResource.ro.resx". Observăm că am inclus indicativul de limbă ca şi cum ar fi o extensie. În acest fişier adăugăm un articol tot cu numele "msg1", dar cu valoarea "Numele:". Adăugăm un handler pentru evenimentul de clic pe butonul din formă şi în acest handler scriem următoarea secvenţă de cod:

ResourceManager rm=new ResourceManager("LocalizedApp.MyResource",

Assembly.GetExecutingAssembly()); MessageBox.Show(rm.GetString("msg1")+" "+textBox1.Text);

Compilaţi şi rulaţi, pentru limbile română şi engleză. ResourceManager ştie să încarce resursa în funcţie de limba setată. Când creăm un fişier resursă pentru o anumită limbă, specificarea limbii se face în numele fişierului.

Concluzii

Sper că în aceste pagini am reuşit să vă fac o scurtă descriere a ceea ce înseamnă dezvoltarea aplicaţiilor Windows pentru .NET Framework. Oricum, cele mai multe lucruri le veţi învăţa prin practică şi citind multă documentaţie.