Programare Visual Studio .NET

Programare Visual Studio .

NET - LABORATOR
Project no. Document no. PVS 2008 Product name: Version no.: Programare Visual Studio 0.1 CR no.: Date: Author: Feb - 2010 Lucian Nita

Programare Microsoft Visual Studio .NET
Lucrari de laborator

Version no.: 1

Page 1 of 46

Programare Visual Studio .NET - LABORATOR
Project no. Document no. PVS 2008 Product name: Version no.: Programare Visual Studio 0.1 CR no.: Date: Author: Feb - 2010 Lucian Nita

Cuprins

1 2

INTRODUCERE .................................................................................................................................................... 4 PREZENTAREA MEDIULUI DE PROGRAMARE VISUAL STUDIO .NET ............................................... 5 2.1 2.2 PRINCIPALELE FERESTRE DE LUCRU DIN VISUAL STUDIO .................................................................................. 7 COMENZILE DE LUCRU UTILIZATE IN VS ........................................................................................................... 7

3

DEFINIREA CLASELOR IN OOP ...................................................................................................................... 9 3.1 3.2 3.3 PROPRIETATI, CONSTRUCTORI. TIPUL ENUM SI DATETIME ............................................................................... 9 INSTANTIEREA CLASELOR................................................................................................................................ 10 CONSTRUCTORI PRIVATI. OBIECTELE TIMER SI RANDOM ................................................................................ 11

4

PREZENTAREA DATELOR ............................................................................................................................. 15 4.1 SOLUTII CU PROIECTE MULTIPLE. IERARHIZAREA PROIECTELOR ...................................................................... 15 4.2 FEREASTRA OUTPUT ....................................................................................................................................... 16 4.3 PROGRAMARE BAZATA PE EVENIMENTE. OBIECTELE "DELEGATE" SI "EVENT" ............................................... 17 4.4 PREZENTAREA DATELOR IN DATAGRID ........................................................................................................... 19 4.4.1 Controalele de tip GUI nu sunt thread-safe ........................................................................................... 21 4.5 CONTROALE VIZUALE: CHECKBOX, TEXTBOX. CLASA DICTIONARY .............................................................. 23

5

SALVAREA INFORMATIILOR IN BAZA DE DATE ................................................................................... 30 5.1 CREAREA BAZEI DE DATE SQLITE ................................................................................................................... 30 5.2 DATA ACQUISITION LAYER : INTERFATA INTRE BAZA DE DATE SI APLICATIA GUI .......................................... 31 5.2.1 Definirea string-ului de conectare la baza de date in pagina de proprietati a proiectului .................... 32 5.3 CLASA DE INTERFATA CU BAZA DE DATE ......................................................................................................... 33 5.3.1 Salvarea informatiilor in baza de date ................................................................................................... 33 5.3.2 Citirea informatiilor din baza de date .................................................................................................... 36

6

TRANSMITEREA DATELOR INTRE APLICATII. SOCKET TCP/IP ....................................................... 40 6.1 OBIECTUL TCPCOMMCLIENT ......................................................................................................................... 41 6.1.1 Impachetarea datelor pentru transmisie ................................................................................................. 42 6.1.2 Crearea unui nou fir de executie pentru fiecare dialog cu serverul ....................................................... 43 6.1.3 Trimiterea datelor catre server............................................................................................................... 44 6.1.4 Functia Dispose inchide firele de executie suspendate........................................................................... 45 6.2 OBICETUL TCPCOMMSERVER ........................................................................................................................ 46

Version no.: 1

Page 2 of 46

Programare Visual Studio .NET - LABORATOR
Project no. Document no. PVS 2008 Product name: Version no.: Programare Visual Studio 0.1 CR no.: Date: Author: Feb - 2010 Lucian Nita

Lista de figuri
Figura 1: Visual Studio apare ca devenv.exe in lista de procese din Task Manager ....................................... 5 Figura 2: Crearea unui nou proiect de tip "Console Application" in Visual Studio .NET .................................. 6 Figura 3: Principalele ferestre de lucru ale mediului Visual Studio .................................................................. 7 Figura 4: Clasa "SensorBase" si enumerarea "SensorType" ........................................................................... 9 Figura 5: Constructorii clasei SensorBase ..................................................................................................... 10 Figura 6: Selectarea unei valori dintr-o enumerare ........................................................................................ 10 Figura 7: Instantierea clasei "SensorBase" folosind constructorul implicit ..................................................... 11 Figura 8: Constructorii clasei PumpSensorValues ......................................................................................... 12 Figura 9: Functia de generare si afisare a valorile aleatoare pentru senzori ................................................. 13 Figura 10: Intantierea clasei "PumpSensorValues" si pornirea ceasului ....................................................... 13 Figura 11: Selectarea unui proiect ca referinta pentru proiectul curent ......................................................... 15 Figura 12: Lansarea in executie a functiei de simulare a senzorilor .............................................................. 16 Figura 13: Fereastra Output afiseaza mesajele trimise la consola ................................................................ 16 Figura 14: atasarea functiei "bTest_Click" la evenimentul "bTest.Click" ........................................................ 17 Figura 15: Definirea obiectelor de tip delegate si event in clasa de generare a datelor de masurare ........... 17 Figura 16: Lansarea evenimentului "newSensorValueEvent" ........................................................................ 18 Figura 17:Atasarea functiei "OnNewSensorValueHandler" la evenimentul "newSensorValueEvent" ........... 18 Figura 18:Valorile primite prin eveniment de la clasa "PumpSensorValue" sunt afisate in MessageBox ..... 19 Figura 19: Controlul DataGridView din ToolBox ............................................................................................. 19 Figura 20:Setarea sursei de date pentru gridul de afisare ............................................................................. 20 Figura 21: Popularea listei sensorValueList si setarea ei ca DataSource pentru grid ................................... 21 Figura 22: Eroare: un alt thread acceseaza datagridul .................................................................................. 21 Figura 23: Fereastra principala de prezentare a datelor cu datagrid-ul legat la lista de valori ...................... 23 Figura 24: Adaugarea codului de pacient in clasa cu valorile senzorilor ....................................................... 24 Figura 25: Patient code trebuie adaugat si in clasa PumpSensorValues ...................................................... 24 Figura 26: Evenimentul "newSensorValueEvent" include si codul de pacient ............................................... 24 Figura 27: Adaugarea coloanei PatientCode in datagrid................................................................................ 25 Figura 28: Fereastra DataPresentation cu butoanele de startare si oprire a monitorizarii ............................. 25 Figura 29: Enumerarea ce include codurile de pacienti ................................................................................. 26 Figura 30: Atasarea unei enumerari la un CheckBox..................................................................................... 26 Figura 31: Codul aferent butonului "Start Monitoring" .................................................................................... 26 Figura 32: Functia StartPumping cu parametrii cod pacient si perioada de timp ........................................... 27 Figura 33: Oprirea monitorizarii pentru un pacient si eliminarea lui din dictionarul pacientilor activi ............. 28 Figura 34: Crearea bazei de date “PatientData” in SQLite Administrator ...................................................... 30 Figura 35: Crearea tabelului “PatientData” pentru salvarea datelor ce vin de la pacienti .............................. 31 Figura 36: Adaugarea proiectului “DataStore” de tip “Class Library” la solutie .............................................. 32 Figura 37: Definirea string-ului de conectare la baza de date SQLite in pagina de proprietati a proiectului . 33 Figura 38: Functia de inserare a unei valori de masurare in baza de date .................................................... 34 Figura 39: Tratarea evenimentului “newSensorValueEvent”: salvare in baza si afisare in datagrid .............. 35 Figura 40: Comanda SQL de vizualizare a datelor din tabela PatientData .................................................... 35 Figura 41: Vizualizarea datelor din baza in SQLite Administrator .................................................................. 35 Figura 42: Fereastra DataPresentation dupa ce s-a adaugat sectiunea de filtrare ...................................... 36 Figura 43: Functia de citire din baza de date a datelor de masurare pentru un pacient si o zi stabilita ........ 37 Figura 44: Proiectul “CommonReferences” contine toate definitiile particulare ale tipurilor de date ............. 38 Figura 45: Afisarea valorilor din baza de date ................................................................................................ 39 Figura 46: Functia handler pentru butonul “Display Received Data” ............................................................. 39

Version no.: 1

Page 3 of 46

Programare Visual Studio .NET - LABORATOR
Project no. Document no. PVS 2008 Product name: Version no.: Programare Visual Studio 0.1 CR no.: Date: Author: Feb - 2010 Lucian Nita

1 Introducere
Scopul lucrarilor de laborator prezentate in acest document este de familiariza studentul cu mediul de programare Visual Studio .NET si aplicarea practica a cunostintelor prezentate la curs. In acest scop, se propune in cele ce urmeaza realizarea unei miniaplicatii numite "HealthMonitor" care sa monitorizeze de la distanta starea unui pacient cu probleme de sanatate, in sensul ca pacientul poate sa ramana acasa purtand cu el diversi senzori de masurare a bio-parametrilor (temperatura, ritm cardiac, glicemie, etc) si aceste valori sunt trimise prin internet la cabinetul doctorului care urmareste astfel starea pacientului si se deplaseaza numai la aparitia unei alarme. Ce presupune aceasta monitorizare? Citirea parametrilor bio Salvarea valorilor masurate intr-o baza de date locala Transmisia valorilor la aplicatia ce ruleaza in cabinetul doctorului Afisarea acestor valori sub forma grafica sau text pentru ca doctorul sa poata trage concluziile corecte referitoare la starea de sanatate a pacientului

Prin implementarea acestor taskuri, studentul va trebui sa-si insuseasca si sa lucreze cu urmatoarele concepte: Definirea claselor in OOP Instantierea claselor Mostenire Controale grafice Salvarea datelor in baza de date Comunicatii TCP/IP Multithreading Programare bazata pe evenimente ... Evident ca aceste concepte nu pot fi acoperite in totalitate intr-un numar atat de mic de ore, dar acest exemplu poate reprezenta un punct de plecare pentru dezvoltarea de alte aplicatii serioase si aprofundarea cunostintelor legate de programare obiect si Visual Studio .NET.

Version no.: 1

Page 4 of 46

exe" deoarece de multe ori este utila sa deschidem aplicatia "Task Manager" din Windows si sa analizam modul de ocupare a memoriei si a microprocesorului in timpul rularii unui program.Programare Visual Studio .exe in lista de procese din Task Manager Dupa lansarea VS.") Version no.1 CR no.: Date: Author: Feb . sau putem crea un nou proiect (meniul File/New/Project.LABORATOR Project no. primul pas este de a deschide un proiect deja existent pe dicul local. Figura 1: Visual Studio apare ca devenv.: 1 Page 5 of 46 . PVS 2008 Product name: Version no..: Programare Visual Studio 0. Trebuie retinut numele programului "devenv.exe".exe" in capul listei din tab-ul "Processes" cu o portiune mare de memorie utilizata.NET .2010 Lucian Nita 2 Prezentarea mediului de programare Visual Studio . inseamna de multe ori ca programul a ramas agatat pe un fir de executie infinit si trebuie oprit din TaskManager.NET Mediul Visual Studio se deschide prin lansarea in executie a programului "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\devenv. Faptul ca apare "devenv. Document no.

Librariile sunt salvate pe disc sub forma de fisiere DLL ce trebuie importate in spatiul de lucru al proiecteor ce vor face apel la ele. WPF lucreaza cu limbajul XAML prin care se pot descrie imagine grafice de pe ecran. De exemplu.LABORATOR Project no. WPF Application: dezvolta acelasi tip de aplicatii de tip GUI. este foarte util in testarea rapida a unor concepte de tip OOP. dar bazate pe noua tehnologie WPF (Windows Presentation Foundation) ce expune posibilitati mult mai largi de desenare grafica a interfetelor utilizator.: 1 Page 6 of 46 . Serviciile sunt acele aplicatii care pornesc automat la deschiderea calculatorului si ofera suport in background pentru diverse functionalitati ale sistemului.NET . baza de date Oracle lucreaza ca un serviciu. PVS 2008 Product name: Version no. Document no. Folosind acest limbaj. Windows Service: dezvoltarea unui serviciu Windows. nu pot fi pornite direct pentru ca nu contin functia "Main". Proiecte de tip "Library": nu au interfata cu utilizatorul. dupa cum urmeaza: Windows Form application: este pentru dezvoltarea de aplicatii de tip GUI. bazate pe ferestre.2010 Lucian Nita Figura 2: Crearea unui nou proiect de tip "Console Application" in Visual Studio .Programare Visual Studio . utilizatorul are posibilitatea sa deseneze interfata grafica intr-o aplicatie specifica de desenare.1 CR no. Console Application: cel mai simplu proiect. exporta imaginea in format XAML si aceasta se importa in Visual Studio unde i se poate atasa evenimente si logica necesara aplicatiei. porneste odata cu sistemul si deschide un "Listener" ce asculta in mod permanent la un port pentru a raspunde eventualelor comenzi SQL trimise de un client.NET Putem alege din mai multe tipuri de proiecte. Ele sunt folosite doar pentru crearea diverselor functii de biblioteca ce vor fi utilizate in programele de tip "application".: Date: Author: Feb . nu are interfata grafica. etc. Version no.: Programare Visual Studio 0. controale grafice.

etc.Programare Visual Studio . Fereastra de editare a codului de program: aici se introduce efectiv codul sursa al programului Fereastra "Solution Explorer" afiseaza structura solutiei: proiectele ce apartin de aceasta solutie. proprietatile fiecarui proiect in parte. Visual Studio afiseaza un ecran de lucru ce cuprinde urmatoarele ferestre utile: Figura 3: Principalele ferestre de lucru ale mediului Visual Studio Fereastra "Toolbox": contine majoritatea controalelor utilizate in crearea aplicatiilor: butoane. grid-uri. dar pot fi adaugate de asemenea alte controale din diverse librarii sau instalari de aplicatii.1 Principalele ferestre de lucru din Visual Studio Dupa deschiderea unui proiect.LABORATOR Project no.: 1 Page 7 of 46 . TextBox-uri.NET .2010 Lucian Nita 2.1 CR no. Document no. conexiuni. PVS 2008 Product name: Version no. Properties: este fereastra ce afiseaza proprietatile si evenimentele asociate obiectului curent selectat in pagina de lucru Error List: listeaza erorile aparute la compilarea sau executia programului 2. Sunt foarte multe controale implicite ale mediului VS.2 Comenzile de lucru utilizate in VS Comenzile des folosite in editarea si rularea unui program sunt: F5: compileaza si lanseaza in executie programul curent (in modul Debug) CTRL+S: salveaza fisierele de lucru Version no. fisierele ce compun proiectul.: Date: Author: Feb .: Programare Visual Studio 0.

PVS 2008 Product name: Version no.2010 Lucian Nita F6 (Build solution): compileaza solutia SHIFT+F5: opreste executia programului din modul Debug F10: executie pas cu pas (functia apelata se considera a fi un pas) F11: executie pas cu pas cu intrarea in functia apelata F9: defineste sau sterge un breakpoint in linia curenta Version no.: Date: Author: Feb .NET .1 CR no.: 1 Page 8 of 46 .LABORATOR Project no.Programare Visual Studio .: Programare Visual Studio 0. Document no.

In cadrul acestei clase se definesc urmatoarele componente: Membri privati: type.public SensorBase(SensorType type. Value.2010 Lucian Nita 3 Definirea claselor in OOP 3. timeStamp Proprietatile publice Type.: Date: Author: Feb . value. double value. Se creeaza un nou folder in cadrul proiectului numit "Sensor" si in acest folder se defineste o noua clasa numita "SensorBase". DateTime timeStamp) .NET . Constructori.Programare Visual Studio .1 Proprietati.Implicit .public SensorBase(SensorType type. double value. Tipul Enum si DateTime Se deschide mediul VS si creaza un nou proiect de tip "Console Application" numit "Test OOP".1 CR no.: 1 Page 9 of 46 .: Programare Visual Studio 0.LABORATOR Project no. PVS 2008 Product name: Version no. string timeStamp) Figura 4: Clasa "SensorBase" si enumerarea "SensorType" Version no. TimeStamp Constructorii: . Document no.

Aceasta functie primeste doi parametri: Version no.2 Instantierea claselor Se deschide fereastra programului principal (Program.2010 Lucian Nita Figura 5: Constructorii clasei SensorBase Lista de senzori potentiali cu care poate lucra programul este tinuta de o enumerare publica numita "SensorType". De exemplu.CultureInfo.InvariantCulture) 3.Programare Visual Studio . PVS 2008 Product name: Version no. Alegerea unei valori din enum se face simplu.: Date: Author: Feb .: Programare Visual Studio 0. Conversia inversa se face cu functia statica a clasei DateTime numita ParseExact : DateTime.: 1 Page 10 of 46 . Enumerarile sunt constructii simple in care se pot da nume sugestive pentru numerele naturale. Mai mult.LABORATOR Project no.NET .cs) si se scrie codul pentru instantierea clasei SensorBase folosind constructorul implicit. chiar daca acum acel parametru are valoarea 1. este mult mai sugestiv sa primesti un parametru numit "HeartRate" decat numarul 2 cat reprezinta acel parametru.1 CR no. "dd-MMM-yy HH:mm". in continuare functia va primi parametrul "HeartRate". TimeStamp si Value). daca se sterge sau se adauga un termen din enum.ParseExact(value. programul nu se modifica cu nimic. iar a doua varianta primeste un string si converteste acel string intr-o structura DateTime.ToString("dd-MMM-yy HH:mm") ). se scrie numele enum-ului si se alege valoarea corespunzatoare: Figura 6: Selectarea unei valori dintr-o enumerare Se observa ca in lista de proprietati a clasei proprietatea TimeStamp (timpul la care s-a facut masurarea) apare de doua ori. Dupa crearea obiectului "sensor1" se folosesc proprietatile acestuia pentru introducerea valorile de masurare (Type. Prima varianta TimeStamp primeste si returneaza o clasa de tip DateTime. Conversia unei date in string se face cu metoda ToString (timeStamp. metoda ce primeste ca parametru stringul de formatare a datei calendaristice. Document no. Toate aceste valori se afiseaza apoi la consola prin apelul functiei DisplaySensorValue.

Obiectele Timer si Random Cum nu avem senzorii in mod efectiv. Intrebare: de ce a fost necesar sa se declare functia "DisplaySensorValue()" de tip static? Stergeti atributul "static" din definitia functiei si observati rezultatul. Aceasta clasa va trebui sa instantieze in mod aleatoriu un senzor din lista "SensorType" si apoi sa genereze o valoare aleatoare intr-un domeniu specific acelui senzor: Temperatura poate varia intre 36 si 40 de grade Glicemia intre 80 si 300 mg/dl Pulsul inimii intre 30 si 200 Functia de simulare trebuie sa creeze aceasta valoare aleatoare in mod continuu cu o frecventa data de functia principala Main.NET .2010 Lucian Nita o o un string numit "headerText" care va fi afisat in capul listei de valori o instanta a clasei "SensorBase" care contine informatiile de afisat Figura 7: Instantierea clasei "SensorBase" folosind constructorul implicit    Sa se defineasca un alt obiect de tip "SensorBase".Programare Visual Studio . 3.: Programare Visual Studio 0. Document no.1 CR no.: 1 Page 11 of 46 .: Date: Author: Feb . dar utilizand de data aceasta constructorul cu parametri Sa se afiseze valorile acestui obiect prin apelul functiei "DisplaySensorValue()". PVS 2008 Product name: Version no. va trebui sa construim o clasa care sa simuleze functionarea reala a acestor senzori.LABORATOR Project no.3 Constructori privati. Version no.

Version no. Document no.: 1 Page 12 of 46 . Acest obiect lucreaza ca un ceas ce poate fi programat sa apeleze o functie periodic la un interval de timp dat. Generarea numarului aleator se face prin apelul functiei Next cu cele doua variante: Next(intMax): genereaza un intreg aleator mai mic decat intMax Next(intMin. Figura 8: Constructorii clasei PumpSensorValues Constructorul implicit va fi declarat privat pentru a nu permite instantierea unei clase fara sa se stabileasca perioada intre doua valori.2010 Lucian Nita In folderul "Sensor" se creeaza o noua clasa numita "PumpSensorValues".Timer. Se instantiaza o singura data la intrarea in constructor si se poate apela oriunde in program pentru a obtine un numar aleator intre doua limite date. Functia ce va fi apelata la fiecare tact al timerului este "timerBase_Elapsed". In aceasta functie trebuie sa selectam in mod aleator un tip de senzor si sa-i dam o valoare. Prima clasa instantiata este de tipul Random.Programare Visual Studio .Elapsed += new ElapsedEventHandler(timerBase_Elapsed). apoi sa afisam proprietatile senzorului la consola.: Programare Visual Studio 0. timerul va genera un eveniment "Elapsed" la care noi trebuie sa ne abonam ca sa-l interceptam in mometul emiterii: timerBase. PVS 2008 Product name: Version no. De fapt.LABORATOR Project no. cel ce primeste numarul de secunde intre doua valori ale senzorilor.: Date: Author: Feb .Timers.NET . intMax): numarul aleator este cuprins intre intMin si intMax. Aceasta va avea doar un singur constructor public. la sfarsitul fiecarui interval de timp. Acesta clasa este folosita pentru generarea numerelor aleatoare.1 CR no. Al doilea obiect utilizat este de tipul System.  Incercati sa creati un obiect de tipul "PumpSensorValues" prin constructorul implicit si observati eroarea generata de VS In constructorul clasei sunt create doua obiecte de uz general.

LABORATOR Project no.: 1 Page 13 of 46 . este sa instantiem clasa PumpSensorValues si sa pornim ceasul din clasa respectiva: Figura 10: Intantierea clasei "PumpSensorValues" si pornirea ceasului Nu trebuie uitat la iesirea din program sa se opreasca ceasul pentru a nu mai trimite evenimente pe care sa nu le intercepteze nimeni.Programare Visual Studio .2010 Lucian Nita Figura 9: Functia de generare si afisare a valorile aleatoare pentru senzori Tot ce mai trebuie facut ca sa apara valorile la consola.1 CR no.: Programare Visual Studio 0. PVS 2008 Product name: Version no.NET . Document no.: Date: Author: Feb .  Intrebare: de ce am putut apela functia "DisplaySensorValues" in clasa "PumpSensorValues" fara sa am vreo instanta la clasa "Program" ? Version no.

: 1 Page 14 of 46 . "StopPumping" trebuie apelata la sfarsitul programului pentru a opri ceasul sa mai trimita evenimente. Document no.Programare Visual Studio .: Date: Author: Feb . } In functia "StartPumping()" pornesc ceasul timerBase si acesta imi va trimite evenimente la fiecare "Interval" de timp.LABORATOR Project no.NET .: Programare Visual Studio 0. PVS 2008 Product name: Version no. Version no.2010 Lucian Nita Functiile StartPumping si StopPumping sunt urmatoarele: public void StartPumping() { timerBase.Stop().Start().1 CR no. } public void StopPumping() { timerBase.

Includerea unui proiect copil in cadrul ierarhiei se face prin adaugarea acelui proiect la referintele proiectului tata. sau din tab-ul "COM" ce contine controale particularizate. in care un proiect poate face apel la clasele dintr-un alt proiect aflat pe o ramura inferioara in cadrul ierarhiei.LABORATOR Project no. sa-i fie semnalate alarme in cazul unei valori ce depaseste anumite limite. Deci ne propunem o solutie pentru monitorizarea starii de sanatate a pacientului. Cand o solutie contine mai multe proiecte trebuie ales proiectul de pornire. De aceea.trebuie alcatuita o ierarhie de proiecte. Totusi.Programare Visual Studio . Doctorul ar avea nevoie de un ecran care sa-i afiseze valorile sosite continuu de la senzor. iar proiectul TestOOP se redenumeste "SensorInput".: Programare Visual Studio 0.: 1 Page 15 of 46 .NET unde se gasesc majoritatea bibliotecilor de programe utile.1 CR no. Version no. Se deschide un nou proiect in cadrul solutiei pentru prezentarea datelor venite de la senzori. Dar acest tip de afisare nu este convenabila pentru doctor. Se face click dreapta pe "References" la proiectul "DataPresentation" si se alege Add Reference: Figura 11: Selectarea unui proiect ca referinta pentru proiectul curent Referintele pot fi adaugate din universul . iar in cadrul acestei solutii proiectul deja construit are rol de a simula functionarea reala a senzorilor.NET . In acest scop vom dezvolta un nou proiect de tip Windows Form Application care va avea drept scop afisarea intr-o maniera grafica a rezultatelor de masurare. sa le poata sorta dupa tipul de senzor.: Date: Author: Feb .1 Solutii cu proiecte multiple. Ierarhizarea proiectelor Pana acum am reusit sa generam date pentru senzorii de masurare si sa le afisam in fereastra de tip consola. Document no. proiectele sunt independente si nu se pot apela in mod direct functii dintr-un proiect in altul. Acest nou proiect se denumeste "DataPresentation" si se alege sa fie proeictul de pornire a solutiei.2010 Lucian Nita 4 Prezentarea datelor 4. se redenumeste solutia in "HealthMonitor" (click dreapta pe numele solutiei si alegem meniul "Rename"). cel ce va lansa functia Main(). Mai intai. sau "Projects" unde sunt listate toate proiectele curente ale solutiei curente. PVS 2008 Product name: Version no. Acest nou proiect trebuie sa afiseze datele furnizate de celalalt proiect (SensorInput).

: 1 Page 16 of 46 .: Date: Author: Feb .Programare Visual Studio . Aceasta fereastra se deschide in timpul executiei programului si afiseaza mesajele de consola ale aplicatiei: Figura 13: Fereastra Output afiseaza mesajele trimise la consola Version no. din moment ce functia de simulare trimite valorile generate la consola. putem vedea toate mesajele trimise la consola in timpul executiei unui proiect daca se activeaza fereastra "Output" (meniul View/Output din VS).1 CR no. Totusi. Document no.LABORATOR Project no. in fereastra "DataPresentation" nu se vede nimic.NET .2 Fereastra Output Se modifica constructorul proiectului "DataPresentation" pentru a lansa in executie functia "StartPumping" din clasa "PumpSensorValues": Figura 12: Lansarea in executie a functiei de simulare a senzorilor Chiar daca functia de simulare a senzorilor a pornit. 4.: Programare Visual Studio 0. Nici nu are cum. PVS 2008 Product name: Version no. Iar acum consola nu este vizibila pentru ca proiectul curent "DataPresentation" este de tip "Windows Form Application" si nu afiseaza consola. Din acest moment proiectul "DataPresentation" poate instantia si utiliza toate clasele publice declarate in proiectul "SensorInput".2010 Lucian Nita Se alege tab-ul "Projects" si se selecteaza proiectul "SensorInput" pentru a se adauga la referintele proiectului curent.

cea care il contine. butonul nu stie nimic despre clasa container. Evenimentul se declara in interiorul clasei si trebuie sa fie public pentru a fi cunoscut si in afara clasei. Obiectele "Delegate" si "Event" Am vazut ca clasa "PumpSensorValues" afiseaza datele doar la consola.NET si este instantiat in mii de aplicatii de tipul "Windows Form".3 Programare bazata pe evenimente. "PumpSensorValues" nu are nici o informatie despre clasa container in care va fi utilizata. In schimb. in clasa ce pompeaza date definim delegatul si evenimentul: Figura 15: Definirea obiectelor de tip delegate si event in clasa de generare a datelor de masurare Intai se defineste delegatul in afara oricarei clase. Lansarea evenimentului Prinderea evenimentului de functia "handler" Toate aceste actiuni se fac automat cand se face double-click pe un buton in fereastra de design. nu stie unde va pazi si cine-l va asculta. Tot ce poate sa faca un buton in momentul cand user-ul face "click" este sa lanseze evenimentul "Click". Pentru a putea lansa si prinde evenimente.VS-ul introduce cod pentru legarea evenimentului la functie: Figura 14: atasarea functiei "bTest_Click" la evenimentul "bTest. Se poate face o asemanare cu actiunile unui catel de paza. Definirea obiectulului "Event": este evenimentul propriu-zis. daca nu. VS-ul creeaza automat o functie (handler) care sa trateze evenimentul trimis de buton si tot ce avem noi de facut este sa introducem cod in acea functie.1 CR no.NET . Lansarea acestuia se face simplu. observam ca in acel fisier . noi am dori ca aceste date sa fie afisate de fereastra "DataPresentation".LABORATOR Project no. trebuie realizate cateva actiuni: Definirea obiectulului "Delegate": reprezinta amprenta functiei care trebuie sa prinda acel eveniment. tot ce poate el este sa faca galagie. Catelul de paza (ca si butonul) cand se naste. acesta ar trebui sa execute o actiune in clasa container. In acest fel se defineste amprenta functiei care trebuie sa prinda evenimentul. Daca este cineva sa-l asculte bine. Dar evident. adica sa emita evenimente (in cazul de fata evenimentul "Thief_Inside"). Document no.: Date: Author: Feb .: 1 Page 17 of 46 . este ca un apel de functie: Version no. PVS 2008 Product name: Version no. Daca este cineva sa-l asculte (adica s-a scris o functie care sa prinda evenimentul) atunci actiunea click va avea afect.Programare Visual Studio . Este aceeasi problema pe care o are obiectul "Button" dintr-o forma oarecare.cs). deci nu are acces la nici un obiect din aceasta clasa.: Programare Visual Studio 0.Click" Revenim la aplicatia noastra si sa parcurgem pasii pentru lansarea si prinderea evenimentului ce anunta o noua valoare de la senzori. altfel evenimentul se pierde in eter.2010 Lucian Nita 4. Daca ne uitam in background (Designer. Si totusi. numai ca i se pune in fata termenul "delegate". Daca este pus sa pazeasca o vie de exemplu. el este un obiect din biblioteca . Mai intai. evenimentele se pierd. In momentul cand utilizatorul face click pe buton. Este ca orice definitie de functie.

: Programare Visual Studio 0. Daca nu are atasat nici un handler care sa-l intercepteze. Pentru moment. in fereastra clasei "DataPresentation" va aparea la fiecare 3 secunde un mesaj cu valorile primite in argument. de aceea VS-ul il mentine nul. Version no.LABORATOR Project no. nu are sens sa se trimita evenimentul. inainte de lansare trebuie verificat daca evenimentul este diferit de null. La fiecare 3 secunde functia "StartPumping" va genera un eveniment avand valorile senzorului ca argument care in final va fi tratat in handler. handler-ul doar afiseaza un "MessageBox" cu valorile senzorului.Programare Visual Studio .2010 Lucian Nita Figura 16: Lansarea evenimentului "newSensorValueEvent" Intotdeauna.: 1 Page 18 of 46 . Un eveniment este nul pana in momentul cand se ataseaza un handler la el. Atasarea handler-ului la eveniment se face in clasa container "DataPresentation": Figura 17:Atasarea functiei "OnNewSensorValueHandler" la evenimentul "newSensorValueEvent" In constructorul clasei "DataPresentation" se instantiaza clasa "PumpServerValues(3)". Dupa lansarea in executie a proiectului.NET . Document no. PVS 2008 Product name: Version no.1 CR no.: Date: Author: Feb . se porneste functia de generare a datelor (StartPumping) si se ataseaza handlerul la eveniment.

Proiectul "DataPresentation" este de tip "Windows Form Application".4 Prezentarea datelor in DataGrid Scopul final al proiectului e sa prezentam datele nu prin mesaje.: 1 Page 19 of 46 .: Programare Visual Studio 0.Programare Visual Studio .2010 Lucian Nita Figura 18:Valorile primite prin eveniment de la clasa "PumpSensorValue" sunt afisate in MessageBox Stop 15 Martie 2010 4.1 CR no.: Date: Author: Feb . ci folosind un grid care sa se populeze cu datele venite de la senzori. Document no.NET .LABORATOR Project no. PVS 2008 Product name: Version no. Putem gasi la sectiunea "Data" un control de vizualizare de tip grid: Figura 19: Controlul DataGridView din ToolBox Version no. deci in cadrul lui avem acces la controalele vizuale din ToolBox.

Version no. Se alege apoi data source de tip Object unde regasim toate clasele definite de noi si care pot juca rolul de sursa pentru grid. Din namespace-ul "SensorInput" alegem clasa "SensorBase" drept sursa pentru grid.components). Se alege SensorBase ca DataSource pentru acest BindingSource: this. El va fi instantiat automat in functia "InitializeComponents" a formei.DataSource = this.sensorBaseBindingSource = new Forms.SensorBase). VS-ul creeaza automat un obiect de legatura intre grid si clasa sursa. Se poate modifica modul de prezentare a datelor (coloanele afisate.". Si totusi. Se populeaza gridul cu date numai daca ii dam ca sursa o lista de obiecte de tip SensorBase. noi trebuie doar sa-i setam proprietatile in stilul dorit. ea nu are efectiv date in ea. headere si multe altele) din fereastra de proprietati a gridului.sensorBaseBindingSource.1 CR no.2010 Lucian Nita Selectam acest control si facem drag-and-drop in fereastra principala a proiectului. nu are nici o linie de date inclusa.DataSource = typeof(SensorInput. Se ataseaza BindingSource la datagrid: this. Document no.BindingSource(this.sensorBaseBindingSource.Si asta deoarece clasa "SensorBase" este doar o definitie. PVS 2008 Product name: Version no.: Date: Author: Feb . adica sursa de unde gridul isi va lua datele ca sa le afiseze: Figura 20:Setarea sursei de date pentru gridul de afisare Se pune numele "dgSensorValueList" iar pentru DataSource se merge pe butonul de rulare in jos si se alege din fereastra aparuta linkul "Add project data source.Programare Visual Studio . Dupa aceasta bindare gridul va avea coloanele setate dupa proprietatile publice din SensorBase.dgSensorValueList. Odata selectata sursa. Daca ne uitam in functia "InitializeComponents" putem gasi codul scris in mod automat pentru legarea gridului la BindingSource si BindingSource la SensorBase: Se creeaza un obiect de tipul BindingSource: this..LABORATOR Project no.: 1 Page 20 of 46 .NET . Dar in primul rand trebuie setate numele gridului si "DataSource".: Programare Visual Studio 0. Acest obiect este de tipul "BindingSource" si apare automat in partea de jos a ferestrei de design. fontul dorit. Dupa setarea tuturor proprietatilor pentru datagrid se ruleaza programul si se observa ca gridul apare in fereastra cu toate coloanele stabilite in design. fiecare obiect avand valorile date de clasa PumpSensorValues.

: Date: Author: Feb . apare o eroare foarte interesanta la executie: Figura 22: Eroare: un alt thread acceseaza datagridul Care este problema de fapt? Eroare spune ca un alt thread (fir de executie) decat cel care l-a creat. Document no.LABORATOR Project no. comentam linia cu MessageBox-ul (nu mai vreau sa afisez informatia prin mesaj) si inserez linia: this. Iar in handler-ul de tratare a evenimentului primit de la sensor.NET .BeginInvoke(new VoidFunctionDelegate(BindDataGridToListOfValues)). acceseaza datagridul.1 CR no.: 1 Page 21 of 46 . Dar daca facem asa ceva. Pentru ficare aplicatie cand e pornita.2010 Lucian Nita Figura 21: Popularea listei sensorValueList si setarea ei ca DataSource pentru grid Definim in clasa DataPresentation o lista de tipul SensorBase List<SensorBase> sensorValueList = new List<SensorBase>(). Ce sunt thread-urile sau firele de executie.1 Controalele de tip GUI nu sunt thread-safe In loc de linia cu BeginInvoke. Se stie ca Windows-ul poate lansa mai multe aplicatii simultan.4. as fi vrut sa apelez direct functia BindDataGridToListOfValues().: Programare Visual Studio 0. PVS 2008 Product name: Version no. Windows-ul creeaza un nou fir de executie Version no. 4.Programare Visual Studio .

In functie de prioritatea lor. Cam asa lucreaza si Timer-ul. Fiind executata de thread-ul principal. Tehnica programarii de tip multithreading este foarte utila atunci cand trebuie indeplinite taskuri mari consumatoare de timp: download-area unui fisier mare de pe internet. Adica programul nu mai raspunde la nici o actiune a utilizatorului deoarece este captiv in acel task lung. deschiderea de fisiere mari. se paote umbla la controlul datagrid si sa-i setam DataSource pe lista de valori obtinuta in celalalt thread. iar threadul principal sa ramana activ pentru a raspunde la comenzile utilizatorului. sa trimita un eveniment catre threadul principal. Ce culoare ar trebui sa aiba controlul la sfarsit? De aceea s-a hotarat ca toate controalele vizuale nu lucreaza multithreading si nu accepta controlul decat de la threadul care l-a instantiat. Nici nu au cum daca ne gandim ca threadurile lucreaza intretesut. acesta este prins intr-o functie si acea functie vrea sa acceseze datagrid-ul (sau orice alt control vizual din fereastra).: 1 Page 22 of 46 . El isi deschide un thread separat de unde trimite din cand in cand evenimente de tip "Time_Elapsed".DataSource = sensorValueList. apelam functia BeginInvoke. noi adaugam in lista acea valoare si reconectam lista la datagrid pentru afisare. Este aceeasi functie "BindDataGridToListOfValues". Document no. care pune in coada de mesaje al threadului principal functia ce trebuie executata. PVS 2008 Product name: Version no.2010 Lucian Nita pentru acea aplicatie si-i da drumul sa ruleze.Start(). Deci microprocesorul porneste un thread. In acel moment apare eroarea descrisa mai sus. } Deci. Windows-ul le acorda la fiecare un timp microprocesor in care acel thread sa-si faca treaba. dgSensorValueList. si cand threadul secundar se termina. dar prin apelul BeginInvoke eu o trimit spre executie thread-ului principal.NET . toate cerand timp microprocesor pentru executie. accesul la o baza de date. apoi la altul. Toate bune si frumoase pana cand threadul secundar arunca un eveniment. adica nu lucreaza bine pe mai multe fire de executie. Daca aceste taskuri s-ar executa in acelasi fir de executie cu cel pricipal ce raspunde de interfata cu utilizatorul. atunci aceasta interfata ar fi inghetata (froozen) pe timpul rularii lor. Acelasi multithreading se intampla si-n aplicatia noastra. apoi il opreste si da microprocesorul la alt thread. la fiecare eveniment primit de la celalalt thread. deoarece controalele vizuale nu sunt "thread-safe". Version no. etc. adica se intrerup unul pe altul in mod permanent. De aceea se prefera ca acel task se porneasca pe un alt thread. el ruleaza pe un thread secundar de unde trimite evenimente catre threadul nostru principal: cel ce afiseaza fereastra si raspunde la butoane. In acest fel se aduna mai multe fire de executie.1 CR no.LABORATOR Project no.: Date: Author: Feb . private void BindDataGridToListOfValues() { dgSensorValueList. } Aceasta functie aparent nevinovata de fapt creeaza un alt thread in care va lucra ceasul.: Programare Visual Studio 0.Programare Visual Studio .DataSource = null. apoi se intoarce iar la primul si tot asa. Ceasul este un obiect ce lucreaza in background si nu are sens sa ocupe din threadul curent de executie. eveniment ce vine dupa el cu o noua valoare de senzor. Si se pot intampla situatii cand un thread modifica culoarea la un control in verde de exemplu si este intrerupt in acest timp de un alt thread care modifica in rosu. Clasa PumpSensorValues are o functie de pornire a ceasului: public void StartPumping() { timerBase. Pentru a sari in threadul principal din threadul secundar.

Document no.: Date: Author: Feb . Clasa Dictionary In constructorul clasei de prezentare a datelor se starteaza o singura instanta a clasei PumpSensorValues. PVS 2008 Product name: Version no. Version no.NET .: 1 Page 23 of 46 . In realitate sunt mai multi pacienti conectati la aplicatia de monitorizare ce ruleaza pe calculatorul doctorului. TextBox.1 CR no.Programare Visual Studio .2010 Lucian Nita Figura 23: Fereastra principala de prezentare a datelor cu datagrid-ul legat la lista de valori 4. In afara de valorile de masurare. In acest scop se modifica clasa "SensorBase" sa contina si codul pacientului pentru care trimite valorile.: Programare Visual Studio 0.LABORATOR Project no.5 Controale vizuale: CheckBox. gridul de vizualizare a datelor trebuie sa afiseze si codul pacientului de la care provin datele.

: 1 Page 24 of 46 . PVS 2008 Product name: Version no.LABORATOR Project no. cat si intervalul de timp intre doua masurari succesive.1 CR no.2010 Lucian Nita Figura 24: Adaugarea codului de pacient in clasa cu valorile senzorilor Constructorul clasei "PumpSensorValues" se modifica pentru a primi ca parametri codul pacientului pentru care trimite valori. Document no. Se deschide fereastra de proprietati a gridului si sa da click pe Add pentru a adauga noua coloana "PatientCode" definita in clasa "SensorBase" folosita ca sursa de date pentru grid: Version no. Figura 25: Patient code trebuie adaugat si in clasa PumpSensorValues Iar cand se trimite evenimentul "newSensorValueEvent" acesta trebuie sa contina in argument si codul de pacient: Figura 26: Evenimentul "newSensorValueEvent" include si codul de pacient Ramane ca si in gridul de prezentare a datelor sa se adauge o coloana de afisare a codului de pacient.: Programare Visual Studio 0.Programare Visual Studio .: Date: Author: Feb .NET .

: Programare Visual Studio 0.Programare Visual Studio .2010 Lucian Nita Figura 27: Adaugarea coloanei PatientCode in datagrid Acum ca avem si codul de pacient in SensorBase. intervaulul de timp dintre doua masuratori succesive se citeste dintr-un textBox: Figura 28: Fereastra DataPresentation cu butoanele de startare si oprire a monitorizarii CheckBox-ul de selectare a pacientilor are ca DataSource o enumerare unde se introduc toate codurile de pacienti.LABORATOR Project no. putem construi o interfata ce ne permite sa startam un pacient nou.: Date: Author: Feb . Version no. sau sa oprim trimiterea datelor de la un pacient deja pornit. PVS 2008 Product name: Version no.1 CR no.: 1 Page 25 of 46 . Document no. Vom introduce in fereastra "DataPresentation" doua butoane "Start Pumping" si "Stop Pumping" care sa starteze un pacient selectat dintr-un comboBox.NET . De asemenea.

NET . De exemplu. Prinderea acestei situatii se face printr-o constructie de tip try-catch.2010 Lucian Nita Figura 29: Enumerarea ce include codurile de pacienti Iar aceasta enumerare se pune ca sursa de date pentru checkBox: Figura 30: Atasarea unei enumerari la un CheckBox Butonul "Start Monitoring" trebuie sa porneasca monitorizarea pentru pacientul selectat in checkBox avand ca interval de timp valoarea din textBox-ul aferent: Figura 31: Codul aferent butonului "Start Monitoring" Functia trebuie sa verifice ca checkBox-ul are un pacient selectat si ca textBox-ul pentru numarul de secunde contine un numar intreg valid. Document no.: Programare Visual Studio 0. acest text nu poate fi convertit la un intreg si trebuie afisat mesj de eroare. Se scrie o functie "startPumping" care primeste ca parametri codul pacientului si numarul de secunde intre doua masurari pentru acel pacient si aceasta functie trebuie sa starteze monitorizarea pentru acel pacient: Version no.: Date: Author: Feb .1 CR no.LABORATOR Project no. daca utilizatorul introduce numarul "12ax". PVS 2008 Product name: Version no.: 1 Page 26 of 46 .Programare Visual Studio .

PumpSensorValues>().: Programare Visual Studio 0.: 1 Page 27 of 46 .: Date: Author: Feb . primul obiect din pereche avand semnificatia unei kei. Document no. Dupa startarea unui nou pacient.1 CR no. Inainte de startare se cauta in dictionar daca nu cumva acest pacient este deja activ.Programare Visual Studio .Add(patCodeEnum. Perechile de obiecte se adauaga in dictionar foarte simplu prin comanda Add si apoi sa poate cauta o anumita pereche daca se da keia pentru acea pereche: Se defineste o noua instanta a clasei Dictionary pentru perechea de obiecte: PatientCodeEnum si PumpSensorValues: Dictionary<PatientCodeEnum. PVS 2008 Product name: Version no. PumpSensorValues> dictPatientPump = new Dictionary<PatientCodeEnum.ContainsKey(patCodeEnum)) { MessageBox. return.NET . Putem indrepta aceasta greseala daca construim un dictionar care sa includa toti pacientii activi impreuna cu obiectul "SensorBase" atasat. sensorValuesPump).2010 Lucian Nita Figura 32: Functia StartPumping cu parametrii cod pacient si perioada de timp Problema care apare in momentul cand se lucreaza cu mai multi pacienti este ca putem din greseala sa pornim acelasi pacient de mai multe ori si am primi de la acelasi cod de pacient seturi de date diferite. In caz adevarat se da mesaj de eroare: if (dictPatientPump. } Functia aferenta butonului "Stop Monitoring" trebuie sa opreasca monitorizarea pentru acel pacient si apoi sa elimine pacientul din dictionarul cu pacientii activi: Version no. perechea pacient-pumpSensorValue se adauga in dictionar: dictPatientPump.LABORATOR Project no. Clasa "Dictionary" lucreaza ca o colectie de perechi de obiecte.Show("The selected patient has the pump already started").

un grid care se incarca periodic cu o noua linie ce afiseaza ultima masuratoare obtinuta de la senzori aferenti unui pacient activ..: 1 Page 28 of 46 .: Programare Visual Studio 0... Totusi treaba nu e gata. deci pe calculatoare diferite).LABORATOR Project no. etc) cat si alte taskuri ramase in aer: Salvarea datelor intr-o baza de date (ce ne facem daca doctorul vrea sa vada valorile de acum o saptamana si noi am pierdut lista de valori?) Comunicare TCP/IP intre PumpSensorValues si datagrid (sa nu uitam ca in principiu. pe cand DataPresentation ruleaza la doctor in cabinet. Document no. PVS 2008 Product name: Version no.. mai trebuie lucrat la interfata (butoane de filtrare a informatiei.: Date: Author: Feb . pacientul sta acasa si PumpSensorValues ruleaza la pacient acasa.NET .1 CR no. Version no. Si altele. putem de asemenea starta sau stopa monitorizarea unui pacient cu o perioada de timp programabila.Programare Visual Studio .2010 Lucian Nita Figura 33: Oprirea monitorizarii pentru un pacient si eliminarea lui din dictionarul pacientilor activi In sfarsit am obtinut ceva. alarme.

PVS 2008 Product name: Version no.LABORATOR Project no.: 1 Page 29 of 46 .Programare Visual Studio .1 CR no.: Programare Visual Studio 0. Document no.2010 Lucian Nita Version no.: Date: Author: Feb .NET .

deoarece nu sunt foarte multe date si foarte complexe de salvat si nu are sens sa ocupam memoria cu motorul bazei de date. daca doctorul doreste sa faca o examinare a pacientului si are nevoie de istoricul datelor de masurare. Nu este suficient sa afisam datele.NET . e posibil ca aceasta aplicatie sa ruleze pe un telefon mobil ce are constrangeri evidente de memorie disponibila.62. 5. o baza de date mult mai mica si fara sa necesite instalari complexe.: Date: Author: Feb . Totusi.: 1 Page 30 of 46 .1 CR no. Figura 34: Crearea bazei de date “PatientData” in SQLite Administrator Se deschide apoi baza de date si se creeaza un table pentru salvarea datelor ce vin de la pacient: Version no. aplicatia cu care administram baza de date SQLite si se creeaza o noua baza de date (butonul ). De aceea vom utiliza SQLite.exe”.2010 Lucian Nita 5 Salvarea informatiilor in baza de date Pana in acest moment. Acest SQLite este un simplu DLL care se salveaza odata cu aplicatia si poate fi apelat in orice moment pentru accesarea bazei de date ce este formata dintr-un singur fisier.exe”. Se deschide apoi “sqliteadmin. Document no. doctorul nu are nici o posibilitate sa analizeze o informatie din trecut.1 Crearea bazei de date SQLite Mai intai se instaleaza SQLite database prin rularea aplicatiei “SQLite-1.LABORATOR Project no. de citire a informatiilor din baza pentru perioade de timp stabilite si un pacient dat. In acest capitol vom rezolva problema salvarii datelor intr-o baza de date si problema inversa. trebuie ca aceste date sa fie salvate pe un suport permanent si sa poata fi restaurate la un moment dat.0.: Programare Visual Studio 0. Mai ales ca. nu vom folosi o baza de date foarte mare gen Oracle. Daca se inchide aplicatia. atunci toate informatiile primite se vor pierde. datele ce vin de la pacient sunt puse intr-o lista dinamica si afisate in datagrid.0-setup. PVS 2008 Product name: Version no.Programare Visual Studio .

Document no. dar de data aceasta de tip “Class Library” (deci un simplu fisier DLL. [timestamp] DATE NULL. PVS 2008 Product name: Version no. fara nici o interfata cu utilizatorul). trebuie sa fie create pe un nivel intermediar. [value] NUMERIC NULL ) 5. de sine statator si care va fi apelat de clasa superioara de tip GUI pentru orice accesare a bazei de date.: 1 Page 31 of 46 . [sensor_type] VARCHAR(20) NULL. Tabelul se mai poate crea si prin instructiunea SQL specifica: CREATE TABLE [PatientData] ( [id] VARCHAR(16) PRIMARY KEY NULL.Programare Visual Studio .: Date: Author: Feb . pe care-l denumim “DataStore”: Version no. Adaugam un nou proiect la solutie. Conexiunea la baza de date. functiile SQL.LABORATOR Project no.2010 Lucian Nita Figura 35: Crearea tabelului “PatientData” pentru salvarea datelor ce vin de la pacienti In afara de cele patru campuri de valori ce vin de la pacient se mai adauga un camp numit id de tip varchar si care va fi coloana de tip “primary key” pentru acest tabel.2 Data Acquisition Layer : interfata intre baza de date si aplicatia GUI Nu este indicat sa se acceseze direct baza de date din functiile ce apartin de clasa GUI.1 CR no.: Programare Visual Studio 0.NET . [patient_code] VARCHAR(10) NULL.

2010 Lucian Nita Figura 36: Adaugarea proiectului “DataStore” de tip “Class Library” la solutie Dorim sa utilizam SQLite ca baza de date pentru acest proiect.NET . sectiunea “Projects”). deci va trebui adaugata si aceasta referinta (add reference. In cadrul proiectului vom utiliza si clasa “SensorBase” definita in proiectul “SensorInput”.Data.: 1 Page 32 of 46 . acesta informatie se salveaza o singura data in pagina de proprietati a proiectului si va fi citita din pagina ori de cate ori este nevoie de ea.1 CR no. deci trebuie adaugate la proiect referintele System. Pagina de proprietati este o modalitate de gestionare simpla si rapida a resurselor comune proiectului.2.: Date: Author: Feb .Programare Visual Studio .SQLite. Document no. 5.1 Definirea string-ului de conectare la baza de date in pagina de proprietati a proiectului String-ul de conectare la baza de date (unde se gaseste baza de date si modul de conectare la ea) reprezinta o informatie care este accesata ori de cate ori trebuie sa lucram cu baza de date. PVS 2008 Product name: Version no. O resursa (cum este acest string de conectare) se salveaza o singura data in pagina de proprietati si apoi va fi vizibila pe tot cuprinsul proiectului.: Programare Visual Studio 0.Data si System.LABORATOR Project no. Se deschide pagina de proprietati a proiectului si se defineste la sectiunea “Settings” stringul de conectare la baza de date SQLite: Version no. De aceea.

LABORATOR Project no.NET . iar la “DataBase” se merge cu butonul “Browse” si se selecteaza fisierul creat pentru baza de date.3.: Programare Visual Studio 0. se alege la “Type” tipul resursei “Connection String”.NET Framework Data Provider for SQLite”.3 Clasa de interfata cu baza de date 5. iar la “value” se da click pe butonul pentru a defini conexiunea cu ajutorul Wizard-ului.1 CR no.: 1 Page 33 of 46 . putem construi functia de adaugare a unei valori de masurare (o instanta de SensorBase) in baza de date. La sfarsit se poate face si un test de verificare daca conexiunea este setata corect (butonul “test Connection”).: Date: Author: Feb .Programare Visual Studio . 5. Document no.2010 Lucian Nita Figura 37: Definirea string-ului de conectare la baza de date SQLite in pagina de proprietati a proiectului Se pune numele proprietatii “ConnStringSQLite”. Se deschide Wizard-ul si se selecteaza la “DataSource” driver-ul “.1 Salvarea informatiilor in baza de date Odata ce am definit conexiunea cu baza de date. PVS 2008 Product name: Version no. Adaugam o noua clasa la proiectul “DataStore” numita “DAL_PatientData” : Version no.

Tot ce mai ramane de facut este de a apela functia de salvare in baza de date in momentul cand proiectul “DataPresentation” primeste o noua valoare de masurare prin evenimentul “newSensorValueEvent”: Version no.NET .: 1 Page 34 of 46 .2010 Lucian Nita Figura 38: Functia de inserare a unei valori de masurare in baza de date Etapele ce trebuie parcurse pentru salvarea valorilor de masurare in baza de date sunt urmatoarele: Se defineste un obiect de tipul “SQLiteConnection” cu care putem sa ne conectam la baza de date.Default. Deschidem conexiunea la baza de date si executam comanda SQL Inchidem conexiunea la baza de date Trebuie observat ca accesul la baza de date s-a facut prin constructia try-catch-finally pentru a ne asigura ca tratam eroarea aparuta in cazul cand baza de date nu raspunde.LABORATOR Project no. Se defineste obiectul SQLiteCommand cu care vom executa instructiunea SQL de inserare in baza de date Setam instructiunea SQL ce trebuie executata de SQLiteCommand Setam parametrii ce trebuie trimisi la SQLiteCommand cu valorile de masurare primite prin obiectul sensorData.ConnStringSQLite).Programare Visual Studio . Document no. PVS 2008 Product name: Version no.: Date: Author: Feb .: Programare Visual Studio 0. String-ul de conectare se citeste din fisierul de proprietati ale proiectului (Properties.Settings.1 CR no.

In sfarsit.LABORATOR Project no.: 1 Page 35 of 46 . startam pacientul 0101 si dupa catva timp ne uitam in baza de date cu ajutorul programului SQLite Adminstrator.1 CR no.NET .: Programare Visual Studio 0. Document no. pornim aplicatia cu F5. PVS 2008 Product name: Version no.2010 Lucian Nita Figura 39: Tratarea evenimentului “newSensorValueEvent”: salvare in baza si afisare in datagrid Nu trebuie sa uitam sa adaugam referinta la proiectul “DataStore” in cadrul proiectului “DataPresentation”. Deschidem o fereastra de comenzi SQL si introducem comanda SQL de vizualizare a tabelei “PatientData”: Figura 40: Comanda SQL de vizualizare a datelor din tabela PatientData Executam comanda SQL cu tasta F9 si ar trebui sa observam datele salvate in tabela de aplicatia “Health Monitor”: Figura 41: Vizualizarea datelor din baza in SQLite Administrator Version no. putem verifica daca totul lucreaza OK.Programare Visual Studio .: Date: Author: Feb .

Document no.2010 Lucian Nita 5. PVS 2008 Product name: Version no. Figura 42: Fereastra DataPresentation dupa ce s-a adaugat sectiunea de filtrare Dupa selectia pacientului si a zilei de vizualizare.NET .1 CR no. utilizatorul face click pe butonul “Display Data” si in acel moment trebuie citita din baza de date lista tuturor masuratorile salvate in acea zi pentru respectivul pacient. In acest scop. Se adauga un fereastra “DataPresentation” un control de tip GroupBox ce contine doua controle de fi ltrare: comboBox pentru selectia pacientului monthCalendar ce selecteaza ziua pentru care se doreste a fi vizualizate datele buton pentru efectuarea filtrarii: “Display Selected data”.: Date: Author: Feb .Programare Visual Studio .2 Citirea informatiilor din baza de date Stocarea informatiilor in baza de date permite doctorului in orice moment sa analizeze datele din trecut pentru un pacient dat.: 1 Page 36 of 46 . In primul rand trebuie creata o sectiune de filtrare a datelor unde doctorul sa-si selecteze pacientul pe care vrea sa-l analizeze si intervalul de timp pentru care vrea sa vada datele.3.LABORATOR Project no.: Programare Visual Studio 0. clasa “DAL_PatientData” trebuie sa fie completata cu o functie de citire a informatiilor din baza de date: Version no.

1 CR no. se face conversia datelor aduse de fraza select la tipul SensorBase si se adauga noul item la lista de valori. Ar trebui ca proiectul “DataPresentation” sa fie adaugat in lista de referinte a proiectului Version no.2010 Lucian Nita Figura 43: Functia de citire din baza de date a datelor de masurare pentru un pacient si o zi stabilita Functia de citire din baza de date are urmatoarea structura: se creeaza o noua lista “sensorValueList” unde vor fi salvate informatiilor gasite in baza se defineste un nou obiect de tip SQLiteConnection si un obiect SQLiteCommand se scrie instructiunea SQL de selectie din baza de date si se ataseaza obiectului SQLiteCommand se adauga parametrii de filtrare: patient_code. Se parcurge reader-ul linie cu linie. Totusi avem o mica problema: proiectul “DataStore” nu cunoaste tipul de date “ PatientCodeEnum ” cu care trebuie sa lucreze functia “GetData” pentru ca aceasta enumerare este definita in proiectul “DataPresentation”.). PVS 2008 Product name: Version no. Document no.: Date: Author: Feb .: Programare Visual Studio 0.ExecuteReader().: 1 Page 37 of 46 .NET . reader-ul si se returneaza lista de valori.Programare Visual Studio .LABORATOR Project no. minTime si maxTime se deschide un SQLiteReader in care se salveaza toate liniile aduse din baza de date de fraza select (reader = cmd. La sfarsit se inchide conexiunea.

2010 Lucian Nita “DataStore”. Figura 44: Proiectul “CommonReferences” contine toate definitiile particulare ale tipurilor de date Am mutat definitiile “PatientCodeEnum” si “SensorType” in “CommonReferences” astfel incat acestea sa fie vizibile in toata solutia fara probleme de referinta circulara. Document no. ca acest proiect nu trebuie sa faca referire la nici un alt proiect din solutie.: Programare Visual Studio 0. Evident. Dar acest lucru nu este posibil pentru ca. PVS 2008 Product name: Version no.1 CR no.NET . Acest proiect va fi adaugat ca referinta la toate proiectele ce lucreaza cu acele tipuri de date.: Date: Author: Feb . deja proiectul “DataStore” este referinta la proiectul “DataPresentation” si ar rezulta o referinta circulara. Tot ce mai ramane pentru vizualizarea datelor din baza de date e sa implementam codul pentru butonul “Display selected Data”: Version no. Deci nu se poate sa un proiect sa fie tata la alt proiect si in acelasi timp sa fie fie si copil la acelasi proiect. Nu este posibil ca un proiect P1 se fie referinta la alt proiect P2 si in acelasi timp proiectul P2 sa fie referinta la P1.LABORATOR Project no.: 1 Page 38 of 46 .Programare Visual Studio . se creeaza un nou proiect numit “CommonReferences” care va contine doar un fisier unde vor fi definite toate tipurile de obiecte comune celorlalte proiecte. Din acest motiv.

Totusi.1 CR no. folosind acelasi grid pentru afisarea ambelor tipuri de valori.: 1 Page 39 of 46 .2010 Lucian Nita Figura 45: Afisarea valorilor din baza de date Afisarea se face in acelasi datagrid. atat cele primite online de la patientii activi. trebuie definita a variabila logica care sa specifice tipul de date ce trebuie vizualizate: private bool displayTheReceivingData = true. Iar aceasta variabila va fi setata corespunzator pe cele doua butoane “Display Selected Data” si “Display Received Data”: Figura 46: Functia handler pentru butonul “Display Received Data” Version no.LABORATOR Project no. Document no.GetData().NET .Programare Visual Studio .: Programare Visual Studio 0. trebuie doar sa schimbam proprietatea “dataSource” pentru acest grid pe lista de valori adusa de functia DAL_PatientData. cat si cele aduse din baza de date. PVS 2008 Product name: Version no.: Date: Author: Feb .

iar receptorul ruleaza la medic in cabinet. Se deschide un server TCP/IP care ruleaza un listener ce asculta la un port dat cererile de conectare de la diversi clienti TCP/IP din retea. Tehnologia Socket lucreaza pe arhitectura client-server.: Programare Visual Studio 0. In acest capitol vom analiza modul de conectare a celor doua aplicatii printro legatura de tip Socket TCP/IP.NET . in acelasi calculator si atunci evenimentele trimise de furnizorul de date pot fi receptionate de consumatorul de date.: 1 Page 40 of 46 . Intre ele exista o legatura internet sau intranet prin care trebuie transmise datele. realitatea sta un pic altfel: furnizorul de date ruleaza la pacient acasa. Cand soseste o cerere de conectare. Se modifica proiectul "DataPresentation" prin adaugarea unor radio butoane care sa selecteze modul de transmitere a datelor: prin TCP/IP la un calculator dat de o adresa IP direct la calculatorul curent Figura 47: Proiectul Data Presentation cu posibilitatea de a alege canalul de comunicare a datelor Version no. PVS 2008 Product name: Version no.Programare Visual Studio . se deschide un canal de comunicatii intre cele doua aplicatii prin care pot fi transferate date in ambele sensuri. cat si proiectul care consuma datele (DataPresentation). Socket TCP/IP Pana acum.: Date: Author: Feb .1 CR no. ruleaza sub aceeasi solutie. atat proiectul care producea date (SensorInput).LABORATOR Project no. Si totusi. Document no.2010 Lucian Nita 6 Transmiterea datelor intre aplicatii.

2010 Lucian Nita Pentru a realiza o comunicatie TCP/IP trebuie construite urmatoarele obiecte: TcpClient ce primeste datele de masurare de la sensor.Programare Visual Studio . le impacheteaza intr-un format text si le transmite la server TcpServer care deschide listenerul si accepta cererile de conexiune sosite de la client. il despacheteaza in format SensorBase si-l trimite mai departe la "DataPresentation" Evenimentul prin care serverul sa transmita la interfata DataPresentation valorile primite de la client Se creeaza un nou proiect in cadrul solutiei numit "TCPCommunication".: 1 Page 41 of 46 .LABORATOR Project no.1 CR no.: Date: Author: Feb . proiect ce include doua clase: TCPCommClient si TCPCommServer: Figura 48:Solutia "HealthMonitor" cu toate proiectele componente 6. Document no.1 Obiectul TCPCommClient In continuare se prezinta clasa "TCPCommClient" cu urmatoarele functionalitati: Primeste data de tip "SensorBase" pentru a fi trimisa la server Porneste un nou fir de execuie (thread) care sa se ocupe separat de deschiderea conexiunii si trimiterea datelor Impachetarea clasei "SensorBase" intr-un text dupa un anumit format standard Inchiderea firelor de executie ramase suspendate daca serverul refuza sa raspunda la cererea de dialog Sa luam aceste functii pe rand: Version no.: Programare Visual Studio 0.NET . PVS 2008 Product name: Version no. primeste textul de la client.

2010 Lucian Nita 6. In acest fel ne asiguram ca toti clientii TCP creati vor avea setata adresa IP a serverului cu care trebuie sa dialogheze. Document no.1. Version no. adica sa se creeze o instanta fara a da si adresa IP a serverului la care trebuie sa se conecteze clientul pentru a trimite date.: Programare Visual Studio 0.LABORATOR Project no.1 CR no.1 Impachetarea datelor pentru transmisie Clasa TCPCommClient afiseaza urmatoarele functii publice: Constructorul clasei Figura 49: Constructorii clasei TCPCommClient Se observa ca constructorul implicit al clasei a fost declarat privat astfel incat sa nu poata fi posibila o instantiere a clasei de forma "new TCPCommClient()". PVS 2008 Product name: Version no.: Date: Author: Feb .Programare Visual Studio . "SendSignalData" ce primeste cele patru valori din clasa SensorBase in scopul trimiterii lor catre server.: 1 Page 42 of 46 .NET . Singurul constructor disponibil din exterior este cel ce primeste ca parametru adresa IP a serverului.

Document no.: Date: Author: Feb .  Se adauga thread-ul format in lista de thread-uri a clasei Version no.LABORATOR Project no.Ordinea de impachetare este urmatoarea: SensorType.: 1 Page 43 of 46 .Threading.2 Crearea unui nou fir de executie pentru fiecare dialog cu serverul Functia ce trimite efectiv mesajul text catre server este listata in continuare: Figura 51: Startarea unui nou thread pentru trimiterea datelor Crearea unui nou fir de executie pentru trimiterea textului la server se face prin apelul constructorului clasei "Thread" din namespace-ul "using System. Value.Programare Visual Studio . totul e sa se stabileasca formatul de impachetare care sa fie respectat de ambele parti. Concatenarea acestor string-uri in mesajul de trimis se face cu jutorul functiei "Append" din cadrul clasei "StringBuilder". 6.Simbolul "#" semnifica inceputul si sfarsitul mesajului . sender-ul si receiver-ul pot avea structuri de date diferite.NET . Este mai avantajoasa trimiterea sub forma de text a datelor pentru ca pot fi procesate cu ajutorul functiilor de tip string si in plus.Simbolul ". dupa care face apel catre functia de trimitere a textului.: Programare Visual Studio 0. PatientCode. TimeStamp.2010 Lucian Nita Figura 50: Functiile de primire si impachetare a datelor ce trebuie trimise la server Functia ce primeste datele pentru transmisie apeleaza mai intai functia de impachetare a datelor in format text. S-a decis asupra urmatorului format: ." separa campurile de date specifice clasei "SensorBase" .1.":  Se creeaza instanta clasei "Thread": Thread newThread = new Thread(new ParameterizedThreadStart(SendSignalTextNewThread)). PVS 2008 Product name: Version no.1 CR no.

Aceats functie urmeaza urmatorii pasi: se obtine o instanta a clasei de biblioteca TcpClient cu parametrii: _serverIP si _port.NET . se obtine un obiect de tip "NetworkStream" pe care-l returneaza acest TcpClient.Programare Visual Studio . Acest stream poate trimite octetii unul dupa altul pe canalul deschis intre client si server  despachetam mesajul de tip text intr-un sir de octeti ce pot fi trimisi pe canalul de comunicatie: ASCIIEncoding encoding = new ASCIIEncoding().3 Trimiterea datelor catre server Trimiterea efectiva a textului catre server se face in functia ce ruleaza in firul de executie nou creat. Document no. PVS 2008 Product name: Version no.: Date: Author: Feb .: Programare Visual Studio 0.: 1 Page 44 of 46 .GetBytes(signalText).Add(newThread).LABORATOR Project no. La sfarsit lista de thread-uri a clasei va fi initializata cu noua lista. De aceea trebuie facuta curatenie din cand in cand: Figura 52: Inchiderea firelor de executie inactive Se creeaza o noua lista de thread-uri in care sa vor salva toate firele de executie care sunt inca active. aceste fire de executie raman suspendate si ocupa memoria in mod abuziv. sunt mii de thread-uri ramase in suspensie.  se porneste noul fir de executie avand ca parametru textul ce trebuie trimis la server: newThread.1 CR no. Daca thread-ul nu este activ se inchide prin apelul functiei Abort(). Daca sunt mii de date de trimis si in tot acest timp serverul nu raspunde. Dar mai intai se inchid toate thread-urile ramase in suspensie de la vechile incercari de dialog cu serverul. Daca serverul nu raspunde in timp util.Start(signalText).2010 Lucian Nita myThreadList. 6. fiind alcatuita numai din firele de executie active. byte[] buffer = encoding.   Version no.1.

in mod automat VS-ul te obliga sa implementezi functia Dispose(): Version no.Programare Visual Studio .Write pentru a trimite datele.: Programare Visual Studio 0. Aceasta functie "Write" lucreaza ca si cum am scrie intr-un fisier. PVS 2008 Product name: Version no. Pentru a nu uita ca trebuie sa scrim aceasta functie.1 CR no. Document no.: Date: Author: Feb . Figura 53: Dialogul cu serverul 6.NET .4 Functia Dispose inchide firele de executie suspendate Daca utilizatorul inchide brusc aplicatia (cand inca sunt active fire de executie ce trimit date catre server) atunci trebuie apelata o functie pe evenimentul "DataPresentation_FormClosing" (deci cand fereastra este pe punctul de a se inchide) care sa inchida toate resursele aferente acestei aplicatii.: 1 Page 45 of 46 .1. Figura 54: Tratarea evenimentului "FormClosing" in clasa "DataPresentation" Functia apelata la inchiderea aplicatiei pentru inchiderea tuturor firelor de executie aferente clientului este "Dispose()". am mostenit clasa "TCPCommClient" din interfata "Idisposable" si astfel.LABORATOR Project no.2010 Lucian Nita  Apelam functia stream. problemele hardware de low level de transmitere efective a datelor fiind transparente pentru noi ca utilizatori.

Version no. sa receptioneze mesajele.NET .2 Obicetul TCPCommServer Acest obiect trebuie sa deschida un listener care sa receptioneze cererile de conectare de la clienti. sa deschida canalele de comunicatie.2010 Lucian Nita Figura 55: Componentele interne ale clasei "TCPCommClient" Figura 56: Inchiderea firelor de executie la terminarea programului 6.: Programare Visual Studio 0.Programare Visual Studio . sa despacheteze aceste mesaje si sa trimita valorile primite mai departe la "DataPresentation". Document no.LABORATOR Project no.1 CR no. PVS 2008 Product name: Version no.: 1 Page 46 of 46 .: Date: Author: Feb .

Sign up to vote on this title
UsefulNot useful