Video Library Manager Ce Utilizeaza Tehnologiile .net Framework Si Sqlite

Listă figuri

Figura 1: Structura unui proiect în C# 7

Figura 2: Pachetele NuGet 11

Figura 3: Pagina Index 14

Figura 4 : Tabelul Resources.resw 15

Figura 5 : Pagina NewTvShow 19

Figura 6: Text de avertizare 20

Figura 7 : Afișarea comenzilor ascunse 20

Figura 8: Butoanele din AppBar pentru NewTvShow 22

Figura 9: Butoanele principale și secundare ale listei cu seriale TV 30

Figura 10: Meniul de confirmare a ștergerii listei de seriale TV 31

Figura 11: Sortarea din meniul Flyout 37

Figura 12: Avertisment – termen de căutare invalid 40

Figura 13: Pagina Film Nou 42

Figura 14: Text de avertizare 43

Figura 15 : Afișarea comenzilor ascunse 43

Figura 16: Butoanele din AppBar pentru NewMovie 44

Figura 17: Butoanele principale și secundare ale listei cu filme 52

Figura 18: Meniul de confirmare a ștergerii listei de seriale TV 53

Figura 19: Sortarea din meniul Flyout 59

Figura 20: Avertisment – termen de căutare invalid 62

Introducere

Aplicația dezvoltată pentru acest proiect oferă posibilitatea de a salva informații despre biblioteca de filme pe platforma Windows Phone utilizând .NET Framework. Windows Phone este sistemul de operare mobil dezvoltat de către Microsoft – fiind încă în stadiul de dezvoltare, acesta nu are gama largă de aplicații disponibilă pe sistemele de operare mobile iOS și Android.

Motivul alegerii acestei teme îl constituie nevoia de o aplicație simplă, rapidă și ușoară pe resursele telefonului în care utilizatorul să își poată gestiona librăria de filme. Am ales să dezvolt aplicația în C# și .NET Framework deoarece acestea sunt produse și suportate de către Microsoft, cu librării dedicate. Java nu este o alternativă, iar C++ este un limbaj vechi fără gestiune automată de memorie. C# este un limbaj similar cu C++cu gestiune automată de memorie și nu este nevoie de pointeri, ceea ce face dezvoltarea mai productivă. Pe Windows Phone se pot dezvolta aplicații în Visual Basic, Visual C#, Visual C++, Silverlight și JavaScript. C++ poate fi alegerea bună în unele cazuri, dar nu voi scrie o aplicație care să necesite gestiune manuală de memorie, așa că voi rămâne la C#.

SQLite este o librărie în proces care implementează o bază de date SQL fără server, fără configurare, tranzacțională și independentă. Codul pentru SQLite este un domeniu public, astfel disponibil pentru oricine și cu utilizare în orice scop, comercial sau privat. SQLite este cea mai utilizată bază de date din lume, cu un număr nenumărabil de aplicații, inclusiv unele proiecte de calibru înalt, precum Adobe (în Photoshop Lightroom, Adobe Integrated Runtime (AIR) și Acrobat Reader), Airbus (în software-ul de zbor din familia de avioane A350 XWB), Apple (în multe funcții din Max OS X, inclusiv Apple Mail, Safari și aperturi, dar și în iPhone, iPod Touch și iTunes), Dropbox (pentru arhivare și serviciul de sincronizare din mașina client), Google (în Desktop for Mac, Google Gears, Android și Chrome Web Browser), Microsoft (în Windows 10), limbajul de programare Python și multe alte servicii bine cunoscute. []

Tehnologii utilizate

C#

C# este un limbaj de programare orientat pe obiect care permite dezvoltatorilor să construiască o varietate de aplicații securizate și robuste care rulează pe .NET Framework. C# poate fi utilizat la dezvoltarea aplicațiilor Windows, servicii web XML, componente distribuite, aplicații client-server, aplicații de baze de date și multe altele. Visual C# oferă un editor de cod avansat, designeri de interfață convenabili, debugger integrat, și multe alte unelte ce fac dezvoltarea aplicațiilor bazate pe C# și .NET Framework mai ușoară.

Sintaxa C# este expresivă, dar, de asemenea, simplă și relativ ușor de învățat. Sintaxa cu acolade este instant recognoscibilă oricui este familiar cu C, C++ sau Java. Dezvoltatorii care cunosc oricare din aceste limbaje sunt, în mod tipic, capabili să lucreze productiv în C# într-o perioadă scurtă de timp. Sintaxa C# simplifică multe complexități ale limbajului C++ și oferă facilități importante, precum tipuri de valori nule, enumerații, delegări, expresii lambda și acces direct la memorie, care nu sunt disponibile în Java. C# suportă metode și tipuri generice, ce oferă siguranță de scriere și performanță crescută, și iteratori, care permit implementarea claselor de colecție pentru a defini comportamente individuale de iterație, care sunt ușor de utilizat de codul client. Expresiile în Language-Integrated Query (LINQ) fac interogarea strong-typed (un limbaj strong-typed nu permite asignarea unui tip de date un altul, spre exemplu, nu permite stocarea unui char în int) un construct de limbaj first-class, cu alte cuvinte, acesta rulează pe CLR (Common Language Runtime).

Ca limbaj de programare orientat pe obiect, C# suportă conceptele de încapsulare, moștenire, și polimorfism. Tote variabilele și metodele, inclusiv metoda Main și punctele de intrare ale aplicației sunt încapsulate în definiții de clase. O clasă poate moșteni direct de la o clasă părinte, dar poate implementa orice număr de interfețe. Metodele care suprascriu metodele virtuale dintr-o clasă părinte necesită atributul override ca o modalitate de a evita redefinirea accidentală. În C#, o structură este ca o clasă de categorie ușoară; este un tip alocat în stivă care poate implementa interfețe, dar nu suportă moștenirea.

Pe lângă aceste principii de bază de orientare pe obiect, C# face ușoară dezvoltarea de componente software prin unele construcții inovative de limbaj, inclusiv următoarele:

Semnături de metode încapsulate denumite delegați, care permit notificări pentru evenimentele type-safe (evenimente ce descurajează erorile de scriere).

Proprietăți, care servesc ca accesorii pentru variabilele membrilor privați.

Atribute, care oferă metadata declarativă despre tipuri în timpul rulării.

Comentarii de documentație XML în linie.

Language-Integrated Query (LINQ), care oferă capabilități de interogare peste o mulțime de tipuri de surse de date.

Dacă interacțiunile cu alte produse software Windows, cum ar fi obiecte COM sau DLL-uri native Win32, poți face asta în C# printr-un proces denumit „interop”. Interop permite programelor C# să facă orice poate o aplicație C++ nativă. C# suportă pointeri și conceptul de cod „nesigur” pentru cazurile în care accesul direct la memorie este absolut critical.

Procesul de construcție C# este simplu în comparație cu cel în C sau C++ și mai flexibil decât în Java. Nu sunt fișiere header separate, și nu este necesar ca metodele să fie declarate într-o anumită ordine. Un fișier sursă C# poate defini orice număr de clase, structuri, interfețe și event-uri.

NET Framework

Programele scrise în C# rulează pe platforma .NET, un component integral al sistemului de operare Windows, care include o execuție virtuală denumită „common language runtime (CLR)” și un set unificat de librării de clase. CLR este implementarea comercială a limbajelor comune de infrastructură a lui Microsoft („common language infrastructure” (CLI)), un standard internațional care stă baza creării mediilor de execuție și dezvoltare în care limbajele și librăriile conlucrează.

Codul sursă scris în C# este compilat într-un limbaj intermediat („intermediate language”(IL)) care este conform specificațiilor CLI. Codul IL și resursele, cum ar fi bitmap-uri și șiruri de caractere, sunt stocate pe disc într-un fișier executabil denumit „assembly”, care în mod normal are extensia .exe sau .dll. Un assembly conține un manifest care oferă informații despre tipul de assembly, versiune, cultură și cerințele de securitate.

Atunci când un program C# este executat, assembly-ul este încărcat în CLR, care poate lua diferite acțiuni în funcție de informațiile din manifest. După aceea, dacă cerințele de securitate sunt respectate, CLR efectuează compilarea „just in time” (JIT) pentru a converti codul IL în limbaj mașină. CLR oferă și alte servicii legate de „garbage collection” automat”, tratarea excepțiilor, și managementul de resurse. Codul executat de CLR este uneori menționat ca și „cod gestionat” („managed code”), în contrast cu „codul negestionat” („unmanaged code”), care este compilat în limbaj mașină, care vizează un sistem specific.

Figura 1: Structura unui proiect în C#

Figura 1 ilustrează structura unui proiect C#: proiectul este compilat, iar compilatorul creează assembly-ul gestionat și metadata MSIL, iar metadata IL și referințele sunt încărcate de către CLR, după care este convertit în limbaj mașină.

Interoperabilitatea limbajului este o facilitate cheie a .NET Framework. Codul IL este produs de către compilatorul C# și respectă specificațiile de tip comun („common type specification” (TLS)),așa că poate interacționa cu cel generat de .NET în Visual Basic, Visual C++, sau oricare alt limbaj din cele 20 de compilante CTS.

Pe lângă serviciile run time (din timpul rulării programului), .NET Framework include o librărie cuprinzătoare cu peste 4000 de clase organizate în namespace-uri ce oferă o varietate largă de funcționalitate pentru orice, de la citire și scriere în fișiere, la manipulare de șiruri de caractere, la parsare XML, la controale pentru Windows Forms. []

SQLite

SQLite este un motor de bază de date încorporat. Spre deosebire de alte baze de date SQL, SQLite nu are un proces separat de server. SQLite citește și scrie direct în fișiere normale de pe disc. O bază de date SQL completă cu multiple tabele, indice, triggere și vizualizări este ținută într-un singur fișier. Formatul fișierului bazei de date poate fi citit de diferite platforme – se poate copia fără probleme o bază de date de pe un sistem de 32-bit pe unul 64-bit. Această facilitate face SQLite o alegere populară de format de extensie de fișier („Application File Format”).

SQLite este o librărie compactă. Cu toate facilitățile activate, dimensiunea bibliotecii poate fi sub 500KiB, în funcție de platforma țintă și de setările de optimizare ale compilatorului. Codul pe 64-bit este mai mare, iar unele opțiuni de optimizare pe compilatoare, cum ar fi funcțiile agresive de plasare în linie și derularea ciclărilor pot cauza codul de obiect să devină mult mai mare. Dacă se omit funcțiile opționale, dimensiunea bibliotecii SQLite poate fi redusă la sub 300KiB. SQLite poate fi rulat în spațiu minimal de stivă (4KiB) și coadă foarte mică (100KiB), ceea ce face SQLite un motor de bază de date popular când dispozitivul pe care rulează are constrângeri de memorie, cum ar fi telefoane, PDA-uri și MP3 playere. Există un compromis între utilizarea memoriei și viteză. SQLite rulează, în general, mai rapid cu cât are mai multă memorie la dispoziție. Cu toate acestea, performanța este, în general, suficient de bună chiar și în medii cu puțină memorie la dispoziție.

SQLite este foarte bine testat înainte de eliberarea fiecărei versiuni și are reputația de a fi foarte stabil. Majoritatea codului sursă SQLite este devotat doar testării și verificării. O suită automată de verificare rulează milioane și milioane de cazuri de test ce implica sute de milioane de declarații SQL individuale și arhivează 100% din ramurile de testare. SQLite răspunde grațios la eșuarea alocării de memorie și erorilor de citire și scriere. Tranzacțiile sunt ACID (Atomicitate, Consistență, Izolare, Durabilitate) chiar dacă sunt întrerupte de căderi de sistem sau pene de curent. Toate acestea sunt verificate de teste automate folosind sisteme ce simulează problemele de sistem. Desigur, cu toate că sunt testate extensiv, încă sunt bug-uri, dar, spre deosebire de proiecte similare, în special competitori comerciali, SQLite este deschis și sincer în legătură cu bug-urile și oferă liste de bug-uri și cronologii la minut la rapoartele de bug-uri și schimbările de cod.

Proiectul SQLite este suportat de o echipă internațională de programatori care lucrează full-time la acesta. Dezvoltatorii continuă să extindă capabilitățile bazei de date SQLite și să îi crească stabilitatea și performanța, în timp ce păstrează compatibilitatea cu specificațiile de interfață publicate, sintaxa SQL și formatul fișierului bazei de date. []

Windows Phone

Windows Phone este un sistem de operare pentru telefoanele mobile smart (smartphone) și dispozitive mobile care servesc ca succesor al sistemului de operare mobil inițial dezvoltat de Microsoft, Windows Mobile. Spre deosebire de Windows Mobile ,Windows Phone 8 și versiunile ulterioare sunt dezvoltate cu piața de consumatori în minte mai mult decât cea de afaceri.

Visual Studio Community 2013

Aplicația pe care am ales să o dezvolt este făcută în C#, utilizând .NET Framework și este dezvoltată pentru platforma de sistem de operare mobil Windows Phone 8.1, cu bază de date SQLite locală. Pentru a începe dezvoltarea proiectului, a fost nevoie să achiziționez o licență de dezvoltator Microsoft de pe site-ul companiei.

Proiectul este dezvoltat în mediul de dezvoltare integrat („Integrated Development Environment” (IDE)) Microsoft Visual Studio Community 2013. Acesta este utilizat în dezvoltarea programelor pentru platforma Microsoft Windows, dar și site-uri web, aplicații web și servicii web. Visual studio utilizează platforme precum Windows API, Windows Forms, Windows Presentation Foundation, Windows Store și Microsoft Silverlight. Visual Studio poate produce atât cod nativ, cât și cod gestionat.

Visual Studio include un editor de cod ce suportă IntelliSense (componenta utilizată la completarea automată a codului) și restructurarea codului existent, schimbând factorizarea fără a schimba comportamentul extern. Debugger-ul integrat funcționează atât ca debugger de cod sursă, dar și ca debugger la nivel de mașină. Alte unelte incluse includ un designer de interfață, designer web, designer de clase și designer de scheme de baze de date. Acceptă plug-in-uri care îmbunătățesc funcționalitatea la aproape fiecare nivel, inclusiv adăugarea suportului de sisteme control de sursă și adăugarea unor seturi de unelte pentru alte aspecte ale ciclului de dezvoltare.

Visual studio suportă diferite limbaje de programare și permite editorului de cod și debugger-ului să suporte, într-o oarecare măsură, aproape orice limbaj de programare, cu condiția ca serviciile specifice limbajului să existe. Limbajele suportate implicit în Visual Studio sunt C, C++, C++/CLI (prin Visual C++), VB.NET (prin Visual Basic .NET), C# (prin Visual C#), și F# (începând cu versiunea 2010 de Visual Studio). Suportul pentru alte limbaje de programare precum M, Python, și Ruby, printre altele, este disponibil prin servicii de limbaj instalate separat. Acesta suportă de asemenea și XML/XSLT, HTML/XHTML, JavaScript și CSS: Java (și J#) nu mai sunt suportate de Visual Studio.

Microsoft oferă ediții „Community” de Visual Studio fără costuri. Versiunile comerciale de Visual Studio, împreună cu versiuni selecte anterioare sunt disponibile gratuit pentru studenți prin programul Microsoft DreamSpark.

Aplicația

Am realizat aplicația din acest proiect cu scopul de a crea o unealtă de gestionare a unei biblioteci video salvată local ce necesită puține resurse de sistem. Astfel, am utilizat tehnologiile C# cu .NET Framework și SQLite pentru a da viață acestei aplicații.

Pentru a începe lucrul la aplicație, deschid Microsoft Visual Studio Community 2013 și creez un proiect nou din meniul File > New Project și am selectat din Templates > Visual C# > Store Apps > Windows Phone Apps > Hub App (Windows Phone).

După ce este creat proiectul, adaug următoarele pachete NuGet: sqlite-net (pentru gestionarea bazei de date SQLite) și Windows Phone Toolkit (utilizat la diverse meniuri și animații).

NuGet este managerul de pachete pentru platforma Microsoft de dezvoltare, inclusiv .NET. Acesta este dezvoltat în mod activ de către .NET Foundation. Uneltele NuGet client oferă abilitatea de a produce și consuma pachete. Galeria NuGet este un repository central de pachete utilizat de toți autorii și consumatorii de pachete și este rulat live la adresa http://www.nuget.org. []

Pagina App

După deschiderea aplicației șterg următoarele pagini create automat de către Visual Studio: HubPage.xaml, HubPage.xaml.cs, ItemPage.xaml, ItemPage.xaml.cs, SectionPage.xaml, SectionPage.xaml.cs. Fac o pagină nouă de tip Basic Page cu numele de Index.xaml.

Codul de pe pagina App este primul care rulează la deschiderea aplicației, de aceea aici se pot scrie instrucțiuni de pornire. Pentru a schimba pagina de pornire, înlocuiesc din pagina App.xaml.cs înlocuiesc prima pagină afișată (nu rulată) la deschiderea aplicației în următoarele linii de cod:

Fiecare pagină are două fișiere interconectate, .xaml și .cs, interconectate. Fișierul xaml conține codul utilizat pentru a compune interfața aplicației și a lega elemente de diverse funcții din sursa .cs și este tradus în cod mașină la rulare, iar sursa .cs poate da valori elementelor declarate în fișierul .xaml atașat acesteia.

if (rootFrame.Content == null) // Verifică dacă este gol conținutul frame-ului inițial.

{

// Înlocuiește navigarea turnichet pentru pornire.

if (rootFrame.ContentTransitions != null)

{

this.transitions = new TransitionCollection();

foreach (var c in rootFrame.ContentTransitions)

{

this.transitions.Add(c);

}

}

rootFrame.ContentTransitions = null;

rootFrame.Navigated += this.RootFrame_FirstNavigated;

/* Atunci când stiva de navigare nu este restaurată, navighează la prima pagină, se face configurarea paginii noi prin parsarea informației necesare ca parametru de navigare. */

// parameter.

if (!rootFrame.Navigate(typeof(Index), e.Arguments)) /* Am înlocuit HubApp cu Index pentru a deschide pagina Index.xaml la pornirea aplicației. */

{

throw new Exception("Crearea paginii inițiale a eșuat."); /* Afișarea erorii dacă nu se poate deschide pagina inițială. */

}

}

Fac declarația claselor Movie și TvShow, cu câmpurile necesare, după care, în funcția ce este rulată la deschiderea aplicației, declar, setez locația, creez și mă conectez la bazele de date:

public class Movie // Clasa film

{

[PrimaryKey] // Cheia primară

public string MovieTitle { get; set; } /* Șirul de caractere ce reprezintă titlul filmului */

public string Notification { get; set; } /* Șirul de caractere ce reprezintă notificarea */

}

public class TvShow

{

[PrimaryKey]

public string TvShowTitle { get; set; }/* Șirul de caractere ce reprezintă titlul filmului */

public string Notification { get; set; } /* Șirul de caractere ce reprezintă notificarea */

} /* … */

protected override async void OnLaunched(LaunchActivatedEventArgs e)

{

/* … */

var dbpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "movies.db");

/* Setează locația bazei de date */

using (var db = new SQLite.SQLiteConnection(dbpath))

db.CreateTable<Movie>(); /* Utilizând dbpath, locatia bazei de date, crează tabelul „Movies” folosind conexiunea db */

var dbpath2 = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "tvshows.db");

using (var db2 = new SQLite.SQLiteConnection(dbpath2))

db2.CreateTable<TvShow>(); /* … */

}

Pagina Index

Index este prima pagină afișată la deschiderea aplicației. În aceasta afișez categoriile „Seriale TV” și „Filme” ca butoane, iar la atingerea unuia din ele se deschide baza de date legată de butoane. În AppBar, meniul din josul paginii, plasez butoanele „Adaugă” și „Șterge” pentru a putea adăuga intrări în baza de date și pentru a șterge o anumită intrare.

Interfață

Panoul de titlu

Panou de titlu utilizează StackPanel, o modalitate de a așeza elemente child in mod consecutiv pe ecran, orientate vertical sau orizontal. StackPanel declară rândul utilizat din grila principală a interfeței paginii pentru textul de titlu și numele paginii curente. Comanda <StackPanel Grid.Row="0" Margin="19,0,0,0"> declară un StackPanel ce utilizează rândul 0 din grila de așezare.

Atributul Margin cu o valoare mai mare decât 0 aplică spațiu în afara lățimii și înălțimii reale a obiectului. Marginile sunt aditive pentru obiecte de același tip dintr-un layout. Spre exemplu, două obiecte adiacente vertical sau orizontal cu o margine de 30 pe muchea dintre acestea vor avea o distanță de 60 de pixeli între ele; în cazul nostru, elementele din StackPanel au o margine de 19 pixeli spre muchea stângă a ecranului. Dimensiuni negative sunt permise pentru margini, dar ar trebui utilizate cu precauție deoarece pot fi interpretate diferit de către diferite implementări de clase de layout. Marginile negative, în mod tipic, mută conținutul obiectului în direcția respectivă. Valorile non-integrale sunt permise, dar ar trebui evitate. []

Câmpul de titlu ia șirul de caractere utilizat pentru câmpul text din fișierul Strings/en-US/Resources.resw prin atributul x:Uid. Orice valoare ar primi câmpul text, aceasta este suprascrisă din tabelul Resources.resw.

<TextBlock x:Uid="AppName" Text="VIDEO LIBRARY MANAGER" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>

Câmpurile AppName.Text și Index.Text din tabelul Resources arată în felul următor:

Figura 4 : Tabelul Resources.resw

Stilul de text al titlului este preluat dintr-o resursă statică de teme pentru Windows Phone, TitleTextBlockStyle, ce se apelează prin ThemeResource.

Mai jos este declarația titlului paginii curentă, deosebindu-se de cel al aplicației prin câmpul x:Uid și resursa de stil utilizată. CharacterSpacing setează spațierea după resursa statica PivotHeaderItemCharacterSpacing, dedicată textului de titlu.

<TextBlock x:Uid="Index" Text="INDEX" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>

Butoane

Pentru butoanele „Seriale TV” și „Filme” am introdus un ListView într-un StackPanel pentru a le așeza consecutiv. În mod normal, un item de date este afișat în ListView ca reprezentarea șirului de caractere la care este legat obiectul de date, iar ListView poate conține o colecție de elemente de orice tip. Am ales să populez lista cu două câmpuri TextBlock: unul pentru Seriale TV, iar celălalt pentru Filme. TextBlock este un control care afișează un text ce poate fi doar citit de către utilizator, cu conținut modificabil din codul sursă.

<!– Seriale –>

<TextBlock Text="Seriale TV" Style="{ThemeResource ListViewItemTextBlockStyle}" Tapped="TvShowLibrary_Click" Padding="0,0,0,20" />

<!– Filme –>

<TextBlock Text="Filme" Style="{ThemeResource ListViewItemTextBlockStyle}" Tapped="MovieLibrary_Click" Padding="0,0,0,20" />

Evenimentele Tapped sunt activate la atingerea câmpului de text afișat pe ecran. Fiecare TextBlock are acțiunea proprie. Spre exemplu, TvShowLibrary_Click este definit în modul următor:

private void TvShowLibrary_Click(object sender, TappedRoutedEventArgs e)

{

Frame.Navigate(typeof(TvShowLibrary));

}

Frame.Navigate(typeof(TvShowLibrary)) deschide pagina TvShowLibrary. În mod similar este definit și butonul MovieLibrary_Click, ce deschide pagina MovieLibrary.

Bara de comenzi

O bară de comenzi este un element de interfață ce pune la dispoziție utilizatorului diverse comenzi, navigație și unelte pentru aplicație. Bara de comenzi poate apărea în partea de sus sau de jos a paginii, sau în ambele locuri în același timp. Aceasta este ascunsă în mod implicit și este afișată sau micșorată programatic. []

Declarația la AppBar se face prin <Page.BottomAppBar> și comenzile se pot adăuga prin <CommandBar>. În cazul nostru, CommandBar are atributele Background="{ThemeResource PhoneAccentBrush}" ce setează culoarea în funcție de culoarea de accent a telefonului și modul de afișare a barei de comenzi în starea inactivă este declarată prin ClosedDisplayMode="Compact", modul compact afișând doar comenzile principale ale acesteia. Pentru a accesa comenzile secundare, utilizatorul va fi nevoit sa atingă cele trei puncte din partea din dreapta sus a barei de comenzi sau să tragă de aceasta în sus.

Comenzi principale

Comenzile principale se declară în câmpul <CommandBar.PrimaryCommands> și sunt sub forma unor butoane. Butoanele din AppBar difera de butoanele standard în câteva moduri:

Aspectul implicit este sub formă de cerc în loc de dreptunghi.

Poți utiliza proprietățile Label și Icon pentru a seta conținutul în loc de propiretatea Content. Proprietatea Content este ignorată dacă proprietatea Icon este setată.

Butonul are proprietatea IsCompact pentru a îi controla dimensiunea.

AppBarButton are două dimensiuni: normală și compactă. Implicit, acesta este afișat cu etichetă și padding complet. Atunci când proprietatea IsCompact este stată ca true, eticheta text este ascunsă și padding-ul din jurul butonului este redus.

Proprietățile Label și Icon pot fi folosite pentru a defini conținutul butoanelor din AppBar. Setarea Label-ului ca un șir de caractere va specifica textul de sub buton. Acesta este implicit afișat și este ascuns atunci când butonul este într-o stare compactă, așa că este necesară și o pictogramă reprezentativă. Pentru a defini iconița butonului se setează proprietatea Icon la un element derivat din clasa IconElement. Sunt 4 tipuri de elemente disponibile pentru a afișa pictograme.

FontIcon – pictograma este bazată pe un glyph din familia de fonturi specificată.

BitmapIcon – pictograma este bazată pe un fișier botmap cu Uri-ul specificat.

PathIcon – pictograma este bazată pe o locație dată.

SymbolIcon – pictograma este bazată pe un glyph din fontul Segoe UI Symbol lustat din enumerațiile Symbol. []

În câmpul de comenzi principale am declarat un singur buton de adăugare ce deschide un meniu din care utilizatorul poate alege ce să adauge în baza de date: un Serial TV sau un Film.

<CommandBar.PrimaryCommands>

<AppBarButton Label="Adaugă" Icon="Add">

<AppBarButton.Flyout>

<MenuFlyout Placement="Top" >

<MenuFlyoutItem Text="Serial TV" Click="NewTvShow_Click" />

<MenuFlyoutItem Text="Film" Click="NewMovie_Click" />

</MenuFlyout>

</AppBarButton.Flyout>

</AppBarButton>

</CommandBar.PrimaryCommands>

Meniu Flyout

Pentru a deschide meniul Flyout, am utilizat clasa <AppBarButton.Flyout> ce suprapune un element de interfață peste ecranul curent la atingerea butonului „+”, iar în aceasta am adăugat două iteme de tip MenuFlyoutItem. La atingerea elementelor se poate naviga la paginile NewTvShow, respectiv NewMovie.

Un control Flyout poate fi utilizat pentru a colecta informații, pentru a afișa informații adiționale, pentru avertismente sau confirmări. Spre deosebire de un dialog, un Flyout nu creează o fereastră separată și nu blochează alte interacțiuni ale utilizatorului. Am introdus un MenuFlyout în Flyout pentru a afișa butoanele „Serial TV” și „Film”.

Comenzile secundare se declară în câmpul <CommandBar.SecondaryCommands>. Singura comandă pe care am adăugat-o este cea care deschide meniul cu informații despre aplicație, iar aceasta este declarată în felul următor:

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

Pagina Serial Nou

Pagina Serial Nou este folosită la introducerea serialelor TV în baza de date, cu posibilitatea de a adăuga notificări săptămânale acestora – pagina sursă este denumită NewTvShow. Pentru a salva datele introduse de utilizator, am creat o listă în care se pot adăuga intrări ce sunt apoi salvate în baza de date.

Interfață

Pagina din stânga este cea de introducere a unui serial TV nou fără notificare. Pentru a prelua numele serialului TV, am creat un câmp TextBox ce preia datele introduse de la tastatură.

Câmpul de titlu

<TextBox x:Name="TvShowName" x:Uid="TvShowName" PlaceholderText="Nume serial" InputScope= "AlphanumericFullWidth" />

Câmpul x:Name="TvShowName" permite accesarea programatică datelor din TextBox pentru a putea fi citite și adăugate în baza de date, InputScope= "AlphanumericFullWidth" declară scopul introducerii datelor și deschide tastatura dedicată acelui scop la atingerea câmpului.

Modalități de avertizare

PlaceholderText="Nume serial” este textul afișat pe câmpul de text înainte să fie introdus numele serialului TV și dispare la atingerea câmpului sau introducerea datelor.

Ca modalitate de avertizare permanentă pentru tentativa de a introduce o intrare goală în baza de date, am declarat câmpul <TextBlock x:Name="NoInput" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" /> ce afișează mesajul "Câmpul nu poate fi gol!" dacă utilizatorul atinge butonul de confirmare fără să completeze numele serialului TV.

O altă modalitate de a avertiza utilizatorul este un MessageDialog ce afișează un mesaj în partea de sus a ecranului ce notifică utilizatorul de faptul că nu a introdus numele filmului. Codul sursă pentru a afișa mesajul este

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol.");

await msgbox.ShowAsync();

și rezultatul arată ca ultima imagine de pe pagina anterioară.

De asemenea. utilizatorul poate adăuga notificări săptămânale pentru fiecare serial TV din baza de date, cu posibilitatea de a fi repetat pentru un număr definit de săptămâni. Pentru a putea face asta, este necesar să tragă de comutatorul „Notificare” la dreapta, după care vor fi afișate elementele de interfață utilizate la salvarea notificărilor.

Elementele interfeței din Figura 7 sunt create folosind comenzile de mai jos:

<ToggleSwitch x:Name="HasNotification" x:Uid="HasNotification" OffContent="Nu" OnContent="Da" Header="Notificare" IsOn="False" Toggled="HasNotification_Toggled" />

<!– Declararea comutatorului de notificare cu modalitățile de accesare programatică și înlocuirea șirului de caractere global, parametrii de afișare pentru stările de oprit și pornit, titlul comutatorului, setarea stării implicite IsOn ca fals, iar la comutare se rulează funcția HasNotification_Toggled –>

<TimePicker Opacity="0" Header="Alege ora" x:Name="MyTimePicker" />

<!– Declararea modului de alegere a orei pentru notificare cu opacitate zero (complet transparent), a titlului și a modalității de accesare programatică. –>

<DatePicker Opacity="0" Header="Alege data" x:Name="MyDatePicker" />

<!– Declararea modului de alegere a datei pentru notificare cu opacitate zero (complet transparent), a titlului și a modalității de accesare programatică. –>

<TextBox Opacity="0" x:Name="NumberOfRepetitions" Header="Introdu numărul de săptămâni" PlaceholderText="pentru care se repetă notificarea" InputScope="Number" />

<!– Declararea modului de introducere a numărului de notificări cu opacitate zero (complet transparent), a modalității de accesare programatică, a titlului, a textului cu rol îndrumător și de deschidere a tastaturii numerice la atingere. –>

Elementele transparente apar la activarea comutatorului prin opțiunea Toggled=”HasNotification_Toggled”. Funcția este descrisă mai jos.

private void HasNotification_Toggled(object sender, RoutedEventArgs e)

{

if (HasNotification.IsOn == true) // Dacă este activat comutatorul

{

MyTimePicker.Opacity = 1; // opacitatea devine 1

MyDatePicker.Opacity = 1; //la fiecare element

NumberOfRepetitions.Opacity = 1; // de mai jos.

}

else

{

MyTimePicker.Opacity = 0; // Altfel, dacă nu este atins

MyDatePicker.Opacity = 0; // sau este dezactivat comutatorul,

NumberOfRepetitions.Opacity = 0; // opacitatea rămâne sau devine 0.

}

}

Butoanele din AppBar

Butoanele primare din AppBar sunt Accept și Anulare, iar cele secundare sunt Despre și Înapoi. Butonul Accept introduce noul serial TV în baza de date, iar Anulare se întoarce la ecranul precedent.

<CommandBar.PrimaryCommands>

<!– Declararea butoanelor primare din bara de jos –>

<AppBarButton Icon="Accept" Label="Accept" Click="NewTvShow_AddToDb" />

<!– Declararea butonului de acceptare, descris în partea de funcționalitate –>

<AppBarButton x:Uid="Cancel" Label="Anulare" Click="Back_Click" Icon="Cancel" />

<!– Declararea butonului de anulare, descries în partea de funcționalitate –>

</CommandBar.PrimaryCommands>

<!– Închiderea tag-ului de comenzi primare –>

<CommandBar.SecondaryCommands>

<!– Declararea butoanelor secundare –>

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii About_Click, ce deschide pagina AboutPage –>

<AppBarButton x:Uid="Back" Label="înapoi" Click="Back_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii Back_Click, ce deschide pagina anterioară –>

</CommandBar.SecondaryCommands>

<!– Închiderea tag-ului de comenzi secundare –>

Funcționalitate

Butoane

Butonul „Accept” apelează funcția NewTvShow_AddToDb (descrisă mai jos), iar butonul „Anulare” apelează funcția Back_Click ce conține instrucțiunile if(this.Frame.CanGoBack) Frame.GoBack(), ce afișează ecranul precedent. Butonul „Despre” deschide pagina AboutPage, iar butonul „Înapoi” apelează aceeași funcție ca butonul „Anulare”.

Baza de date

Locația bazei de date a serialelor tv este dată de șirul static global de caractere „dbpath2”, declarat în felul următor: static string dbpath2 = Path.Combine(Windows.Storage. ApplicationData.Current.LocalFolder.Path, "tvshows.db");

Funcția de notificare a numărului de repetiții a notificării serialului tv

În rândurile următoare declar o funcție ce, dacă este apelată cu șir de caractere ca parametru, afișează acel șir de caractere ca notificare. Metoda de notificare, se apelează prin ShowToastNotification("[șir de caractere ce va fi afișat în notificare]"). Folosesc această funcție pentru a afișa pe ecran, sub formă de notificare, numărul de săptămâni pentru care se va repeta notificarea.

private void ShowToastNotification(String message)

{

ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText01;

XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);

// Se setează textul

XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");

toastTextElements[0].AppendChild(toastXml.CreateTextNode(message));

// Se setează imaginea

// Imaginile trebuie să fie mai mici de 200 KB în dimensiune și mai mici de 1014 x 1024 pixeli.

XmlNodeList toastImageAttributes = toastXml.GetElementsByTagName("image");

((XmlElement)toastImageAttributes[0]).SetAttribute("src", "ms-appx:///Images/logo-80px-80px.png");

((XmlElement)toastImageAttributes[0]).SetAttribute("alt", "logo");

// durata notificării

IXmlNode toastNode = toastXml.SelectSingleNode("/toast");

((XmlElement)toastNode).SetAttribute("duration", "short");

// navigarea notificării

var toastNavigationUriString = "#/MainPage.xaml?param1=12345";

var toastElement = ((XmlElement)toastXml.SelectSingleNode("/toast"));

toastElement.SetAttribute("launch", toastNavigationUriString);

// Crearea notificării bazată pe XML-ul specificat.

ToastNotification toast = new ToastNotification(toastXml);

// Trimiterea notificării toast.

ToastNotificationManager.CreateToastNotifier().Show(toast);

}

Clasa TvShow

public class TvShow // Clasa serial TV

{

[PrimaryKey] // Cheia primară

public string TvShowTitle { get; set; } /* Șirul de caractere ce reprezintă titlul serialului TV */

public string Notification { get; set; } /* Șirul de caractere ce reprezintă notificarea */

}

Butonul NewTvShow_AddToDb

private async void NewTvShow_AddToDb(object sender, RoutedEventArgs e)

{

using (var db2 = new SQLite.SQLiteConnection(dbpath2))

{

db2.Table<TvShow>(); // Assignează tabelului db2 lista cu seriale TV.

string notificationValue = null; /* Șirul de caractere adăugat în baza de date în câmpul Notificare. */

if((TvShowName.Text).Length > 0) /* Lungimea șirului de caractere introdus trebuie să fie mai mare decât 0. */

{

if (HasNotification != null) /* Verifică dacă starea comutatorului de notificare nu este nulă și efectuează instrucțiunile de mai jos. */

{

if (HasNotification.IsOn == true) /* Dacă comutatorul este activ, atunci efectuează instrucțiunile de mai jos. */

{

DateTime _selectedTime = (MyDatePicker.Date).Date.Add((MyTimePicker.Time)); /* Preia ziua și ora din modalitățile de introducere a orei și a datei în variabila _selectedTime. /

ToastTemplateType toastTemplate = ToastTemplateType.ToastText02; // Declarația șablonului de notificare

var toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate); /* Declarația XML-ului de notificare. */

toastXml.DocumentElement.SetAttribute("duration", "long"); /* Setează durata notificării ca fiind lungă. */

var textLines = toastXml.GetElementsByTagName("text"); /* Preia elementele după text. */

textLines[0].InnerText = "Serial TV"; /* Linia 1 din notificare va fi „Serial TV”. */

textLines[1].InnerText = TvShowName.Text; /* Linia 2 din notificare va fi numele serialului TV introdus de către utilizator. */

ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier(); /* Crearea notificării. */

int _numberOfRepetitions = 0; /* Declararea variabilei ce servește ca număr de repetiții. */

_numberOfRepetitions = Int32.Parse(NumberOfRepetitions.Text.ToString()); /* Preluarea numărului de repetiții din câmpul de introducere declarat pentru acest scop. */

ShowToastNotification(TvShowName.Text.ToString() + " se va repeta de " + _numberOfRepetitions.ToString() + " ori."); /* Confirmă numărul de repetiții pentru noua notificare. */

for (int i = 0; i < _numberOfRepetitions; i++) /* Incrementarea repetițiilor. */

{

ScheduledToastNotification scheduledToast = new ScheduledToastNotification(toastXml, _selectedTime); /* Declararea noii înregistrări pentru notificare cu timpul dat și termenii preluați din interfață. */

toastNotifier.AddToSchedule(scheduledToast); /* Adăugarea notificării la notificările plănuite. */

_selectedTime = _selectedTime.AddDays(7); /* Adăugarea a 7 zile la data selectată pentru a repeta notificarea cu o săptămână mai tarziu la fiecare incrementare a lui i. */

}

string _selectedDate = string.Format("{0:dd/MM/yyyy}", MyDatePicker.Date); /* Salvarea zilei selectate în string-ul _selectedDate. */

string _selectedNotificationTime = MyTimePicker.Time.ToString(); /* Salvarea orei selectate în string-ul _selectedNotificationTime. */

notificationValue = "Data " + _selectedDate + ", ora " + _selectedNotificationTime + "."; /* Salvarea datei și a orei în variabila NotificationValue pentru a fi înregistrată în baza de date. */

}

else

notificationValue = "Fără notificare."; /* Dacă nu este activat comutatorul de notificare, în câmpul Notification din baza de date va fi salvat textul „Fără notificare”. */

}

db2.RunInTransaction(() => // Accesarea bazei de date.

{

db2.Insert(new TvShow() { TvShowTitle = TvShowName.Text.ToString(), Notification = notificationValue }); /* Inserarea titlului serialului TV și a notificării acestuia în baza de date. */

});

Frame.Navigate(typeof(TvShowLibrary)); /* Navigarea la pagina Seriale Tv.

}

else /* Dacă nu este introdus nimic în câmpul de nume serial TV

{

NoInput.Text = "Câmpul nu poate fi gol!"; /* Atribuirea valorii „Câmpul nu poate fi gol!” câmpului de atenționare. */

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol."); /* Afișarea avertismentului pe ecran, pentru care utilizatorul va trebui să atingă butonul de închidere. */

await msgbox.ShowAsync(); // Așteptarea deschiderii avertismentului.

}

}

}

Redirecționare forțată

Pentru a forța direcționarea la pagina de seriale TV la atingerea butonului hardware „Înapoi”, i-am suprascris funcționalitatea în codul sursă al paginii NewTvShow. Pentru început, am adăugat librăria Windows.Phone.UI.Input în antetul paginii prin cuvântul cheie „using”, în modul următor: „using Windows.Phone.UI.Input;”. În continuare, am declarat funcția de suprascriere a acțiunii butonului hardware „Înapoi”:

private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)

{

Frame.Navigate(typeof(TvShowLibrary)); /* La apăsarea butonului „Înapoi” se va naviga la pagina TvShowLibrary. */

}

Pentru a finaliza, am asignat un nou buton de back în pagina curentă în funcția compilată la navigarea pe pagina NewTvShow:

protected override void OnNavigatedTo(NavigationEventArgs e)

{

this.navigationHelper.OnNavigatedTo(e); /* Cheamă NavigationHelper la încărcare. */

HardwareButtons.BackPressed += HardwareButtons_BackPressed; /* Declararea butonului „Înapoi” ca HardwareButtons_BackPressed, pentru a putea fi utilizat la suprascrierea funcționalității butonului. */

}

Pagina Seriale TV

În pagina Seriale TV sunt afișate titlurile și notificările acestora din baza de date tvshows.db – pagina din sursă este denumită TvShowLibrary. Pentru a afișa intrările din baza de date, am folosit un <ListView> în care am legat câmpurile de text ce sunt afișate pe ecran de elementele din baza de date pentru afișarea dinamică.

Interfață

Pentru a crea pagina din stânga, am creat în pe rândul 1 din grila de afișare un ScrolViewer pentru a permite mutarea listei pentru a afișa mai multe elemente pe ecran, în ScrollViewer am pus un ListView (ce afișează datele din interiorul lui), pe care îl umplu cu o comandă de afișare a datelor din baza de date. În ListView am pus un ListView.ItemTemplate pentru stilizarea afișării, cu un DataTemplate ce afișează datele din căsuțele de text într-un StackPanel.

Comenzile de afișare sunt descrise mai jos, fiecare linie explicată imediat dedesubt, pentru claritate.

<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">

<!– Declarația rândului 1 de afișare, cu marginile de 19 pixeli în părți și 9.5 pixeli sus –>

<ScrollViewer> <!– Pentru a putea fi scrollabilă pagina, am declarat un scrollviewer –>

<ListView x:Name="TvShows" ItemClick="Item_Click" IsItemClickEnabled="True" >

<!– Declarația listei ce va fi populată cu intrări din baza de date folosind identificatorul unic x:Name –>

<ListView.ItemTemplate>

<!– Declarația template-ului de iteme utilziat în listă –>

<DataTemplate>

<!– Declarația template-ului de date –>

<StackPanel>

<!– StackPanel utilizat la așezarea elementelor din interfață –>

<TextBlock Style="{ThemeResource ListViewItemTextBlockStyle}" Text="{Binding TvShowTitle}" TextWrapping="WrapWholeWords" />

<!– Blocul de text ce poate fi accesat programatic prin TvShowTitle, cu conținutul afișat pe rândul următor dacă se umple primul rând (prin TextWrapping), stilizat ca element de listă –>

<TextBlock FontSize="16" Text="{Binding Notification}" Padding="0,0,0,16" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" TextWrapping="WrapWholeWords" />

<!– Blocul de text ce poate fi accesat programatic prin Notification, stilizat ca subtitlu de item din listă –>

</StackPanel>

</DataTemplate>

</ListView.ItemTemplate>

</ListView>

</ScrollViewer>

</Grid>

<!– Închiderea tag-urilor –>

Bara de comenzi are 4 butoane principale: Refresh (pentru reîncărcarea elementelor afișate), Film Nou (pentru a accesa pagina NewTvShow), Șterge (pentru a accesa pagina DeleteTvShow) și sortare pentru a deschide panoul de sortare a serialelor TV după anumite categorii. Butoanele secundare includ ștergerea tuturor elementelor din listă, accesarea paginii cu informații despre aplicație și revenirea la meniul anterior.

Butonul „Șterge toate intrările”

<AppBarButton Label="Șterge toate intrările" >

<!– Crearea butonului și a textului afișat pe ecran –>

<Button.Flyout>

<!– Deschiderea unui meniu de tip flyout la atingerea butonului –>

<Flyout x:Name="ConfirmDelete" >

<!– Denumirea programatică a meniului flyout –>

<StackPanel>

<!– Declararea panoului în care este afișată confirmarea –>

<TextBlock Text="Confirmi golirea completă a listei?" Margin="12, 12, 12, 0" Style="{ThemeResource BodyTextBlockStyle}" />

<!– Textul de confirmare a ștergerii complete a listei de filme –>

<Button Content="Confirm" Click="DeleteList" Margin="12, 12, 0, 0" />

<!– Butonul de confirmare a ștergerii –>

</StackPanel>

</Flyout>

</Button.Flyout>

</AppBarButton>

<!– Închiderea tag-urilor –>

Butonul „Despre”

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii About_Click, ce deschide pagina AboutPage –>

Acțiunea efectuată la atingerea butonului „Despre”.

private void About_Click(object sender, RoutedEventArgs e) // Declararea evenimentului.

{

Frame.Navigate(typeof(AboutPage)); // Navigarea la pagina AboutPage.

}

Butonul „Înapoi”

<AppBarButton x:Name="Back" x:Uid="Back" Label="înapoi" Click="Back_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii Back_Click, ce deschide pagina anterioară –>

Acțiunea efectuată la atingerea butonului „Înapoi”.

private void Back_Click(object sender, RoutedEventArgs e) // Declarația funcției.

{

if (Frame.CanGoBack) // Verifică stiva de frame-uri (meniuri sau ecrane) anterioare și răspunde boolean cu adevărat dacă se poate întoarce la ultimul frame.

{

Frame.GoBack(); // Întoarcerea la ultimul frame.

}

}

Butonul „Refresh”

Butonul „Refresh” reîncarcă și afișează elementele din baza de date pe pagina activă.

<AppBarButton Label="Refresh" Icon="Refresh" Click="Refresh_List" />

<!– Declararea butonului cu iconița predefinită „Refresh” și acțiunea pe click declarată mai jos –>

public void Refresh_List(object sender, RoutedEventArgs e) // Declarația funcției

{

sortingBy = "ByNotification"; /* Salvarea în string-ul sortingBy valoarea „ByNotification” */

ChangeSortingType(sortingBy); /* Apelarea funcției de sortare cu parametrul declarant mai sus */

}

Butonul „Film Nou”

<AppBarButton x:Name="NewTvShow" x:Uid=" NewTvShow " Label="Serial nou" Click="NewTvShow_Click" Icon="Add" />

<!– Declararea butonului cu pictograma predefinită „Add” și la atingerea butonului se deschide pagina NewTvShow: Frame.Navigate(typeof(NewTvShow));–>

Butonul „Șterge”

<AppBarButton Label="Șterge" Icon="Delete" Click="DeleteTvShow_Click" />

<!– Declararea butonului cu pictograma predefinită „Delete” și la atingerea butonului se deschide pagina DeleteTvShow: Frame.Navigate(typeof(DeleteTvShow));–>

Butonul „Sortare”

<AppBarButton Label="Sortare" Icon="Sort">

<!– Realizarea butonului Sortare cu pictograma predefinită „Sort” –>

<Button.Flyout>

<!– Deschiderea unui meniu de tip flyout la atingerea butonului –>

<Flyout x:Name="SortByFlyout" >

<!– Denumirea programatică a meniului flyout –>

<StackPanel>

<!– Declararea panoului în care este afișată confirmarea –>

<TextBlock Text="Sortare" Margin="12, 12, 0, 0" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />

<!– Titlul listei de sortare –>

<MenuFlyoutItem Text="De la A la Z" Tapped="Alphabetic_Sort" FontSize="24" Margin="12, 12, 0, 12" />

<!– Sortare alfabetică –>

<MenuFlyoutItem Text="De la Z la A" Tapped="ReversedAlphabeticSort" FontSize="24" Margin="12, 0, 0, 12" />

<!– Sortare alfabetică inversată –>

<MenuFlyoutItem Text="După notificări" Tapped="WithNotificationFirst" FontSize="24" Margin="12, 0, 0, 12" />

<!– Sortare după notificări –>

<MenuFlyoutItem Text="În ordinea introducerii" Tapped="OrderedByDate" FontSize="24" Margin="12, 0, 0, 20" />

<!– Sortare în ordinea introducerii datelor –>

</StackPanel>

</Flyout>

</Button.Flyout>

</AppBarButton>

<!– Închiderea tag-urilor –>

Funcționalitate

Clasa TvShow

Cu ajutorul clasei TvShow sunt create câmpurile din baza de date SQLite. Cheia primară este utilizată la efectuarea acțiunilor din baza de date: creare și ștergere a intrărilor din aceasta.

public class TvShow

{

[PrimaryKey]

public string TvShowTitle { get; set; }

public string Notification { get; set; }

}

Variabila globală a bazei de date

Locația bazei de date a serialelor tv este dată de șirul static global de caractere „dbpath2”, declarat în felul următor: static string dbpath2 = Path.Combine(Windows.Storage. ApplicationData.Current.LocalFolder.Path, "tvshows.db"); Acesta poate fi accesat de oriunde din pagină.

Butonul „Șterge toate intrările”

public void DeleteList(object sender, RoutedEventArgs e)

{

using (var db = new SQLite.SQLiteConnection(dbpath2)) /* Utilzând variabila db ca interfață SQLite pentru adresa dbpath2 */

db.RunInTransaction(() => // începe tranzacția.

{

// Golește baza de date

db.DeleteAll<TvShow>();

// Încarcă elementele din pagină

ChangeSortingType(sortingBy); // sortingBy este o variabilă globală

});

ConfirmDelete.Hide(); // Ascunderea meniului de confirmare

}

Schimbarea criteriului de sortare

public string sortingBy = "ByNotification"; // Variabila globală utilizată la sortare

private void ChangeSortingType(String typeOfSort) // Funcția de sortare

{

sortingBy = typeOfSort; /* Se asignează variabilei globale sortingBy șirul de caractere typeOfSort, primit ca parametru */

// Sortare alfabetica

if (sortingBy == "Alphabetical") /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „Alphabetical”, sortează intrările alfabetic și afișează-le */

using (var db = new SQLite.SQLiteConnection(dbpath2)) /* Folosind variabila db ca interfață, se conectează la locația bazei de date dbpath2. */

{

var SortByAttribute = db.Table<TvShow>().OrderBy(TvShow => TvShow.TvShowTitle).ToList(); /* Declarația unei variabile SortByAttribute ce primește tabelul TvShow ordonat în funcție de titlu */

TvShows.ItemsSource = SortByAttribute;

}

// Sortare invers alfabetica

if (sortingBy == "RevAlphabetical") /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „RevAlphabetical”, sortează intrările invers alfabetic și afișează-le */

using (var db = new SQLite.SQLiteConnection(dbpath2))

{

var SortByAttribute = db.Table<TvShow>().OrderByDescending(TvShow => TvShow.TvShowTitle).ToList();

TvShows.ItemsSource = SortByAttribute;

}

// Sortare alfabetic dupa notificare

if (sortingBy == "ByNotification")

using (var db = new SQLite.SQLiteConnection(dbpath2))

{

var SortByAttribute = db.Table<TvShow>().OrderBy(TvShow => TvShow.Notification).ToList(); /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „ByNotification”, sortează intrările alfabetic după notificare și afișează-le */

TvShows.ItemsSource = SortByAttribute;

}

// Sortare invers alfabetic dupa notificare

if (sortingBy == "RevByNotification")

using (var db = new SQLite.SQLiteConnection(dbpath2))

{

var SortByAttribute = db.Table<TvShow>().OrderByDescending(TvShow => TvShow.Notification).ToList(); /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „RevByNotification”, sortează intrările invers alfabetic după notificare și afișează-le */

TvShows.ItemsSource = SortByAttribute;

}

// Sortare in ordinea introducerii in baza de date

if (sortingBy == "ByDate")

{

using (var db = new SQLite.SQLiteConnection(dbpath2))

TvShows.ItemsSource = db.Table<TvShow>();/* Dacă șirul de caractere primit de către funcția ChangeSortingType este „ByDate”, afișează intrările în ordinea în care au fost introduce în baza de date */

}

}

Sortarea din meniul flyout

private void Alphabetic_Sort(object sender, TappedRoutedEventArgs e) /* Butonul de sortare alfabetică */

{

sortingBy = "Alphabetical"; /* Variabila globală sortingBy primește valoarea „Alphabetical” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void ReversedAlphabeticSort(object sender, TappedRoutedEventArgs e) /* Butonul de sortare invers alfabetică */

{

sortingBy = "RevAlphabetical"; /* Variabila globală sortingBy primește valoarea „RevAlphabetical” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void WithNotificationFirst(object sender, TappedRoutedEventArgs e) /* Butonul de sortare alfabetică după notificare */

{

sortingBy = "ByNotification"; /* Variabila globală sortingBy primește valoarea „ByNotification” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void NoNotificationFirst(object sender, TappedRoutedEventArgs e) /* Butonul de sortare invers alfabetică după notificare */

{

sortingBy = "RevByNotification"; /* Variabila globală sortingBy primește valoarea „RevByNotification” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void OrderedByDate(object sender, TappedRoutedEventArgs e) /* Butonul de sortare după data de intrare */

{

sortingBy = "ByDate"; /* Variabila globală sortingBy primește valoarea „ByDate” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

Pagina de ștergere a serialelor TV

Pentru a trece peste limitările elementului xaml ListView, care permite doar afișarea datelor fără posibilitatea de a interacționa cu acestea, este nevoie ca implementarea funcției de ștergere să fie separată și bazată pe datele introduse de către utilizator. Mai jos demonstrez implementarea paginii de ștergere și a funcției de căutare și ștergere a rândului din baza de date ce conține textul introdus de către utilizator în câmpul de titlu.

Interfața

Pagina „Șterge” are ca sursă fișierul DeleteTvShow și conține un singur câmp de căutare. Dacă utilizatorul atinge cutia de text, atunci se va deschide tastatura și i se va permite să introducă numele serialului TV pe care dorește să îl șteargă din baza de date.

Câmpul de căutare

Câmpul de căutare este declarat ca TextBox.

<TextBox Header="Caută" PlaceholderText= "Nume serial TV" x:Name="SearchBoxTerm" />

Atributul Header plasează textul primit ca titlu pentru a indica utilizatorului că acesta este un câmp de căutare, PlaceholderText indică obiectul căutat, în cazul nostru este numele serialului TV și conținutul textbox-ului se poate citi programatic cu ajutorul termenului SearchBoxTerm.

Butoanele din AppBar

În AppBar am adăugat un buton de ștergere a serialului TV, un buton de anulare, și un buton ce deschide pagina cu informații despre aplicație. În rândurile de mai jos am descris comenzile utilizate la crearea acestor elemente.

<Page.BottomAppBar>

<!– Declarația bării de jos a paginii –>

<CommandBar Background="{ThemeResource PhoneAccentBrush}" >

<!– Crearea bării de comandă și selectarea automată a culorii bării de jos în funcție de culoarea de accent a telefonului –>

<CommandBar.SecondaryCommands>

<!– Containerul pentru comenzile secundare –>

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Butonul ce deschide pagina AboutPage –>

</CommandBar.SecondaryCommands>

<!– Încheierea tag-urilor containerului de comenzi secundare –>

<CommandBar.PrimaryCommands>

<!– Containerul pentru comenzi principale –>

<AppBarButton Label="Șterge" Click="Delete_Click" Icon="Delete" />

<!– Butonul de confirmare a ștergerii serialului TV –>

<AppBarButton Label="Anulează" Icon="Cancel" Click="Cancel_Action" />

<!– Buton de anulare, ce se întoarce la ecranul precedent –>

</CommandBar.PrimaryCommands>

<!– Încheierea tag-urilor containerului de comenzi principale –>

</CommandBar>

<!– Închierea tagurilor de commandbar –>

</Page.BottomAppBar>

<!– Închiderea tag-urilor de bară de comenzi –>

Funcționalitate

Butonul „Șterge”

private async void Delete_Click(object sender, RoutedEventArgs e) /* Declararea funcției de ștergere este declarată asincron pentru a aștepta mesajul de avertizare pentru utilizator. */

{

string searchboxTerm = SearchBoxTerm.Text; /* Preia șirul de caractere din câmpul de căutare ca string */

if(searchboxTerm.Length < 1) /* Dacă dimensiunea termenului de căutare este mai mica decât 1 – adică nu a introdus niciun cuvânt */

{

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol."); /* Variabila msgbox de tip MessageDialog „Câmpul de text nu poate fi gol.” */

await msgbox.ShowAsync(); /* Așteaptă verificarea funcției if, iar dacă este adevărat se afișează mesajul */

}

else

{

var dbpath2 = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "tvshows.db");

/* Se atribuie adresa bazei de date variabilei dbpath2 */

using (var db2 = new SQLite.SQLiteConnection(dbpath2)) /* Utilizând variabila db2 ca interfață pentru dbpath2 */

db2.RunInTransaction(() => /* efectuează tranzacția */

{

db2.Delete<TvShow>(searchboxTerm); /* Șterge serialul TV din listă care conține termenul căutat de utilziator */

Frame.Navigate(typeof(TvShowLibrary)); /* Navighează la lista cu seriale TV. */

});

}

}

Butonul „Anulează”

private void Cancel_Action(object sentder, RoutedEventArgs e)

{

Frame.Navigate(typeof(TvShowLibrary)); /* La anularea acțiunii de ștergere se va naviga la lista cu seriale TV. */

}

Butonul „Despre”

private void About_Click(object sender, RoutedEventArgs e)

{

Frame.Navigate(typeof(AboutPage)); /* La atingerea butonului se va naviga la pagina AboutPage; aceasta conține informații despre aplicație. */

}

Pagina Film Nou

Pagina Film Nou este folosită la introducerea filmelor în baza de date, cu posibilitatea de a adăuga notificări pentru data în care acestea încep să ruleze în cinematografe– pagina sursă este denumită NewMovie. Pentru a salva datele introduse de utilizator, am creat o listă în care se pot adăuga intrări ce sunt apoi salvate în baza de date.

Interfață

Pagina din stânga este cea de introducere a unui film nou fără notificare. Pentru a prelua numele serialului TV, am creat un câmp TextBox ce preia datele introduse de la tastatură.

Câmpul de titlu

<TextBox x:Name="MovieName" x:Uid="MovieName" PlaceholderText="Nume film" InputScope= "AlphanumericFullWidth" />

Câmpul x:Name="MovieName" permite accesarea programatică datelor din TextBox pentru a putea fi citite și adăugate în baza de date, InputScope= "AlphanumericFullWidth" declară scopul introducerii datelor și deschide tastatura dedicată acelui scop la atingerea câmpului.

Modalități de avertizare

PlaceholderText="Nume film” este textul afișat pe câmpul de text înainte să fie introdus numele serialului TV și dispare la atingerea câmpului sau introducerea datelor.

Ca modalitate de avertizare permanentă pentru tentativa de a introduce o intrare goală în baza de date, am declarat câmpul <TextBlock x:Name="NoInput" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" /> ce afișează mesajul "Câmpul nu poate fi gol!" dacă utilizatorul atinge butonul de confirmare fără să completeze numele serialului TV.

O altă modalitate de a avertiza utilizatorul este un MessageDialog ce afișează un mesaj în partea de sus a ecranului ce notifică utilizatorul de faptul că nu a introdus numele filmului. Codul sursă pentru a afișa mesajul este

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol.");

await msgbox.ShowAsync();

și rezultatul arată ca ultima imagine de pe pagina anterioară.

De asemenea. utilizatorul poate adăuga notificări pentru fiecare film din baza de date, cu posibilitatea de a fi repetat pentru un număr definit de săptămâni. Pentru a putea face asta, este necesar să tragă de comutatorul „Notificare” la dreapta, după care vor fi afișate elementele de interfață utilizate la salvarea notificărilor.

Elementele interfeței din Figura 15 sunt create folosind comenzile de mai jos:

<ToggleSwitch x:Name="HasNotification" x:Uid="HasNotification" OffContent="Nu" OnContent="Da" Header="Notificare" IsOn="False" Toggled="HasNotification_Toggled" />

<!– Declararea comutatorului de notificare cu modalitățile de accesare programatică și înlocuirea șirului de caractere global, parametrii de afișare pentru stările de oprit și pornit, titlul comutatorului, setarea stării implicite IsOn ca fals, iar la comutare se rulează funcția HasNotification_Toggled –>

<TimePicker Opacity="0" Header="Alege ora" x:Name="MyTimePicker" />

<!– Declararea modului de alegere a orei pentru notificare cu opacitate zero (complet transparent), a titlului și a modalității de accesare programatică. –>

<DatePicker Opacity="0" Header="Alege data" x:Name="MyDatePicker" />

<!– Declararea modului de alegere a datei pentru notificare cu opacitate zero (complet transparent), a titlului și a modalității de accesare programatică. –>

Elementele transparente apar la activarea comutatorului prin opțiunea Toggled=”HasNotification_Toggled”. Funcția este descrisă mai jos.

private void HasNotification_Toggled(object sender, RoutedEventArgs e)

{

if (HasNotification.IsOn == true) // Dacă este activat comutatorul

{

MyTimePicker.Opacity = 1; // opacitatea devine 1

MyDatePicker.Opacity = 1; //la fiecare element

}

else

{

MyTimePicker.Opacity = 0; // Altfel, dacă nu este atins

MyDatePicker.Opacity = 0; // sau este dezactivat comutatorul,

}

}

Butoanele din AppBar

Butoanele primare din AppBar sunt Accept și Anulare, iar cele secundare sunt Despre și Înapoi. Butonul Accept introduce noul film în baza de date, iar Anulare se întoarce la ecranul precedent.

<CommandBar.PrimaryCommands>

<!– Declararea butoanelor primare din bara de jos –>

<AppBarButton Icon="Accept" Label="Accept" Click="NewMovie_AddToDb" />

<!– Declararea butonului de acceptare, descris în partea de funcționalitate –>

<AppBarButton x:Uid="Cancel" Label="Anulare" Click="Back_Click" Icon="Cancel" />

<!– Declararea butonului de anulare, descries în partea de funcționalitate –>

</CommandBar.PrimaryCommands>

<!– Închiderea tag-ului de comenzi primare –>

<CommandBar.SecondaryCommands>

<!– Declararea butoanelor secundare –>

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii About_Click, ce deschide pagina AboutPage –>

<AppBarButton x:Uid="Back" Label="înapoi" Click="Back_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii Back_Click, ce deschide pagina anterioară –>

</CommandBar.SecondaryCommands>

<!– Închiderea tag-ului de comenzi secundare –>

Funcționalitate

Butoane

Butonul „Accept” apelează funcția NewMovie_AddToDb (descrisă mai jos), iar butonul „Anulare” apelează funcția Back_Click ce conține instrucțiunile if(this.Frame.CanGoBack) Frame.GoBack(), ce afișează ecranul precedent. Butonul „Despre” deschide pagina AboutPage, iar butonul „Înapoi” apelează aceeași funcție ca butonul „Anulare”.

Baza de date

Locația bazei de date a serialelor tv este dată de șirul static global de caractere „dbpath”, declarat în felul următor: static string dbpath = Path.Combine(Windows.Storage. ApplicationData.Current.LocalFolder.Path, "movies.db");

Funcția de notificare a numărului de repetiții a notificării serialului tv

În rândurile următoare declar o funcție ce, dacă este apelată cu șir de caractere ca parametru, afișează acel șir de caractere ca notificare. Metoda de notificare, se apelează prin ShowToastNotification("[șir de caractere ce va fi afișat în notificare]"). Folosesc această funcție pentru a afișa pe ecran, sub formă de notificare, numărul de săptămâni pentru care se va repeta notificarea.

private void ShowToastNotification(String message)

{

ToastTemplateType toastTemplate = ToastTemplateType.ToastImageAndText01;

XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);

// Se setează textul

XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");

toastTextElements[0].AppendChild(toastXml.CreateTextNode(message));

// Se setează imaginea

// Imaginile trebuie să fie mai mici de 200 KB în dimensiune și mai mici de 1014 x 1024 pixeli.

XmlNodeList toastImageAttributes = toastXml.GetElementsByTagName("image");

((XmlElement)toastImageAttributes[0]).SetAttribute("src", "ms-appx:///Images/logo-80px-80px.png");

((XmlElement)toastImageAttributes[0]).SetAttribute("alt", "logo");

// durata notificării

IXmlNode toastNode = toastXml.SelectSingleNode("/toast");

((XmlElement)toastNode).SetAttribute("duration", "short");

// navigarea notificării

var toastNavigationUriString = "#/MainPage.xaml?param1=12345";

var toastElement = ((XmlElement)toastXml.SelectSingleNode("/toast"));

toastElement.SetAttribute("launch", toastNavigationUriString);

// Crearea notificării bazată pe XML-ul specificat.

ToastNotification toast = new ToastNotification(toastXml);

// Trimiterea notificării toast.

ToastNotificationManager.CreateToastNotifier().Show(toast);

}

Clasa Movie

public class Movie // Clasa serial TV

{

[PrimaryKey] // Cheia primară

public string MovieTitle { get; set; } /* Șirul de caractere ce reprezintă titlul filmului */

public string Notification { get; set; } /* Șirul de caractere ce reprezintă notificarea */

}

Butonul NewMovie_AddToDb

private async void NewMovie_AddToDb(object sender, RoutedEventArgs e)

{

using (var db = new SQLite.SQLiteConnection(dbpath))

{

db.Table<Movie>(); // Assignează tabelului db lista cu filme.

string notificationValue = null; /* Șirul de caractere adăugat în baza de date în câmpul Notificare. */

if((MovieName.Text).Length > 0) /* Lungimea șirului de caractere introdus trebuie să fie mai mare decât 0. */

{

if (HasNotification != null) /* Verifică dacă starea comutatorului de notificare nu este nulă și efectuează instrucțiunile de mai jos. */

{

if (HasNotification.IsOn == true) /* Dacă comutatorul este activ, atunci efectuează instrucțiunile de mai jos. */

{

DateTime _selectedTime = (MyDatePicker.Date).Date.Add((MyTimePicker.Time)); /* Preia ziua și ora din modalitățile de introducere a orei și a datei în variabila _selectedTime. /

ToastTemplateType toastTemplate = ToastTemplateType.ToastText02; // Declarația șablonului de notificare

var toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate); /* Declarația XML-ului de notificare. */

toastXml.DocumentElement.SetAttribute("duration", "long"); /* Setează durata notificării ca fiind lungă. */

var textLines = toastXml.GetElementsByTagName("text"); /* Preia elementele după text. */

textLines[0].InnerText = "Film"; /* Linia 1 din notificare va fi „Film”. */

textLines[1].InnerText = MovieName.Text; /* Linia 2 din notificare va fi numele filmului introdus de către utilizator. */

ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier(); /* Crearea notificării. */

string _selectedDate = string.Format("{0:dd/MM/yyyy}", MyDatePicker.Date); /* Salvarea zilei selectate în string-ul _selectedDate. */

string _selectedNotificationTime = MyTimePicker.Time.ToString(); /* Salvarea orei selectate în string-ul _selectedNotificationTime. */

notificationValue = "Data " + _selectedDate + ", ora " + _selectedNotificationTime + "."; /* Salvarea datei și a orei în variabila NotificationValue pentru a fi înregistrată în baza de date. */

}

else

notificationValue = "Fără notificare."; /* Dacă nu este activat comutatorul de notificare, în câmpul Notification din baza de date va fi salvat textul „Fără notificare”. */

}

db.RunInTransaction(() => // Accesarea bazei de date.

{

db.Insert(new Movie() { MovieTitle = MovieTitle.Text.ToString(), Notification = notificationValue }); /* Inserarea titlului serialului TV și a notificării acestuia în baza de date. */

});

Frame.Navigate(typeof(MovieLibrary)); /* Navigarea la pagina Seriale Tv.

}

else /* Dacă nu este introdus nimic în câmpul de nume serial TV

{

NoInput.Text = "Câmpul nu poate fi gol!"; /* Atribuirea valorii „Câmpul nu poate fi gol!” câmpului de atenționare. */

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol."); /* Afișarea avertismentului pe ecran, pentru care utilizatorul va trebui să atingă butonul de închidere. */

await msgbox.ShowAsync(); // Așteptarea deschiderii avertismentului.

}

}

}

Redirecționare forțată

Pentru a forța direcționarea la pagina de filme la atingerea butonului hardware „Înapoi”, i-am suprascris funcționalitatea în codul sursă al paginii NewMovie. Pentru început, am adăugat librăria Windows.Phone.UI.Input în antetul paginii prin cuvântul cheie „using”, în modul următor: „using Windows.Phone.UI.Input;”. În continuare, am declarat funcția de suprascriere a acțiunii butonului hardware „Înapoi”:

private void HardwareButtons_BackPressed(object sender, BackPressedEventArgs e)

{

Frame.Navigate(typeof(MovieLibrary)); /* La apăsarea butonului „Înapoi” se va naviga la pagina MovieLibrary. */

}

Pentru a finaliza, am asignat un nou buton de back în pagina curentă în funcția compilată la navigarea pe pagina NewMovie:

protected override void OnNavigatedTo(NavigationEventArgs e)

{

this.navigationHelper.OnNavigatedTo(e); /* Cheamă NavigationHelper la încărcare. */

HardwareButtons.BackPressed += HardwareButtons_BackPressed; /* Declararea butonului „Înapoi” ca HardwareButtons_BackPressed, pentru a putea fi utilizat la suprascrierea funcționalității butonului. */

}

Pagina Filme

În pagina Filme sunt afișate titlurile și notificările acestora din baza de date movies.db – pagina din sursă este denumită MovieLibrary. Pentru a afișa intrările din baza de date, am folosit un <ListView> în care am legat câmpurile de text ce sunt afișate pe ecran de elementele din baza de date pentru afișarea dinamică.

Interfață

Pentru a crea pagina din stânga, am creat în pe rândul 1 din grila de afișare un ScrolViewer pentru a permite mutarea listei pentru a afișa mai multe elemente pe ecran, în ScrollViewer am pus un ListView (ce afișează datele din interiorul lui), pe care îl umplu cu o comandă de afișare a datelor din baza de date. În ListView am pus un ListView.ItemTemplate pentru stilizarea afișării, cu un DataTemplate ce afișează datele din căsuțele de text într-un StackPanel.

Comenzile de afișare sunt descrise mai jos, fiecare linie explicată imediat dedesubt, pentru claritate.

<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">

<!– Declarația rândului 1 de afișare, cu marginile de 19 pixeli în părți și 9.5 pixeli sus –>

<ScrollViewer> <!– Pentru a putea fi scrollabilă pagina, am declarat un scrollviewer –>

<ListView x:Name="TvShows" ItemClick="Item_Click" IsItemClickEnabled="True" >

<!– Declarația listei ce va fi populată cu intrări din baza de date folosind identificatorul unic x:Name –>

<ListView.ItemTemplate>

<!– Declarația template-ului de iteme utilziat în listă –>

<DataTemplate>

<!– Declarația template-ului de date –>

<StackPanel>

<!– StackPanel utilizat la așezarea elementelor din interfață –>

<TextBlock Style="{ThemeResource ListViewItemTextBlockStyle}" Text="{Binding MovieTitle}" TextWrapping="WrapWholeWords" />

<!– Blocul de text ce poate fi accesat programatic prin TvShowTitle, cu conținutul afișat pe rândul următor dacă se umple primul rând (prin TextWrapping), stilizat ca element de listă –>

<TextBlock FontSize="16" Text="{Binding Notification}" Padding="0,0,0,16" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" TextWrapping="WrapWholeWords" />

<!– Blocul de text ce poate fi accesat programatic prin Notification, stilizat ca subtitlu de item din listă –>

</StackPanel>

</DataTemplate>

</ListView.ItemTemplate>

</ListView>

</ScrollViewer>

</Grid>

<!– Închiderea tag-urilor –>

Bara de comenzi are 4 butoane principale: Refresh (pentru reîncărcarea elementelor afișate), Film Nou (pentru a accesa pagina NewMovie), Șterge (pentru a accesa pagina DeleteMovie) și sortare pentru a deschide panoul de sortare a filmelor după anumite categorii. Butoanele secundare includ ștergerea tuturor elementelor din listă, accesarea paginii cu informații despre aplicație și revenirea la meniul anterior.

Butonul „Șterge toate intrările”

<AppBarButton Label="Șterge toate intrările" >

<!– Crearea butonului și a textului afișat pe ecran –>

<Button.Flyout>

<!– Deschiderea unui meniu de tip flyout la atingerea butonului –>

<Flyout x:Name="ConfirmDelete" >

<!– Denumirea programatică a meniului flyout –>

<StackPanel>

<!– Declararea panoului în care este afișată confirmarea –>

<TextBlock Text="Confirmi golirea completă a listei?" Margin="12, 12, 12, 0" Style="{ThemeResource BodyTextBlockStyle}" />

<!– Textul de confirmare a ștergerii complete a listei de filme –>

<Button Content="Confirm" Click="DeleteList" Margin="12, 12, 0, 0" />

<!– Butonul de confirmare a ștergerii –>

</StackPanel>

</Flyout>

</Button.Flyout>

</AppBarButton>

<!– Închiderea tag-urilor –>

Butonul „Despre”

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii About_Click, ce deschide pagina AboutPage –>

Acțiunea efectuată la atingerea butonului „Despre”.

private void About_Click(object sender, RoutedEventArgs e) // Declararea evenimentului.

{

Frame.Navigate(typeof(AboutPage)); // Navigarea la pagina AboutPage.

}

Butonul „Înapoi”

<AppBarButton x:Name="Back" x:Uid="Back" Label="înapoi" Click="Back_Click" />

<!– Declararea numelui accesibil programatic, identificatorului unic din șirurile de caractere globale, a etichetei ce va fi suprascrise de x:Uid și a acțiunii Back_Click, ce deschide pagina anterioară –>

Acțiunea efectuată la atingerea butonului „Înapoi”.

private void Back_Click(object sender, RoutedEventArgs e) // Declarația funcției.

{

if (Frame.CanGoBack) // Verifică stiva de frame-uri (meniuri sau ecrane) anterioare și răspunde boolean cu adevărat dacă se poate întoarce la ultimul frame.

{

Frame.GoBack(); // Întoarcerea la ultimul frame.

}

}

Butonul „Refresh”

Butonul „Refresh” reîncarcă și afișează elementele din baza de date pe pagina activă.

<AppBarButton Label="Refresh" Icon="Refresh" Click="Refresh_List" />

<!– Declararea butonului cu iconița predefinită „Refresh” și acțiunea pe click declarată mai jos –>

public void Refresh_List(object sender, RoutedEventArgs e) // Declarația funcției

{

sortingBy = "ByName"; /* Salvarea în string-ul sortingBy valoarea „ByName” */

ChangeSortingType(sortingBy); /* Apelarea funcției de sortare cu parametrul declarant mai sus */

}

Butonul „Film Nou”

<AppBarButton x:Name="NewMovie" x:Uid=" NewMovie " Label="Film nou" Click="NewMovie_Click" Icon="Add" />

<!– Declararea butonului cu pictograma predefinită „Add” și la atingerea butonului se deschide pagina NewMovie: Frame.Navigate(typeof(NewMovie));–>

Butonul „Șterge”

<AppBarButton Label="Șterge" Icon="Delete" Click="DeleteMovie_Click" />

<!– Declararea butonului cu pictograma predefinită „Delete” și la atingerea butonului se deschide pagina DeleteMovie: Frame.Navigate(typeof(DeleteMovie));–>

Butonul „Sortare”

<AppBarButton Label="Sortare" Icon="Sort">

<!– Realizarea butonului Sortare cu pictograma predefinită „Sort” –>

<Button.Flyout>

<!– Deschiderea unui meniu de tip flyout la atingerea butonului –>

<Flyout x:Name="SortByFlyout" >

<!– Denumirea programatică a meniului flyout –>

<StackPanel>

<!– Declararea panoului în care este afișată confirmarea –>

<TextBlock Text="Sortare" Margin="12, 12, 0, 0" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />

<!– Titlul listei de sortare –>

<MenuFlyoutItem Text="De la A la Z" Tapped="Alphabetic_Sort" FontSize="24" Margin="12, 12, 0, 12" />

<!– Sortare alfabetică –>

<MenuFlyoutItem Text="De la Z la A" Tapped="ReversedAlphabeticSort" FontSize="24" Margin="12, 0, 0, 12" />

<!– Sortare alfabetică inversată –>

<MenuFlyoutItem Text="După notificări" Tapped="WithNotificationFirst" FontSize="24" Margin="12, 0, 0, 12" />

<!– Sortare după notificări –>

<MenuFlyoutItem Text="În ordinea introducerii" Tapped="OrderedByDate" FontSize="24" Margin="12, 0, 0, 20" />

<!– Sortare în ordinea introducerii datelor –>

</StackPanel>

</Flyout>

</Button.Flyout>

</AppBarButton>

<!– Închiderea tag-urilor –>

Funcționalitate

Clasa Movie

Cu ajutorul clasei TvShow sunt create câmpurile din baza de date SQLite. Cheia primară este utilizată la efectuarea acțiunilor din baza de date: creare și ștergere a intrărilor din aceasta.

public class Movie

{

[PrimaryKey]

public string MovieTitle { get; set; }

public string Notification { get; set; }

}

Variabila globală a bazei de date

Locația bazei de date a serialelor tv este dată de șirul static global de caractere „dbpath2”, declarat în felul următor: static string dbpath = Path.Combine(Windows.Storage. ApplicationData.Current.LocalFolder.Path, "movies.db"); Acesta poate fi accesat de oriunde din pagină.

Butonul „Șterge toate intrările”

public void DeleteList(object sender, RoutedEventArgs e)

{

using (var db = new SQLite.SQLiteConnection(dbpath)) /* Utilzând variabila db ca interfață SQLite pentru adresa dbpath */

db.RunInTransaction(() => // începe tranzacția.

{

// Golește baza de date

db.DeleteAll<Movie>();

// Încarcă elementele din pagină

ChangeSortingType(sortingBy); // sortingBy este o variabilă globală

});

ConfirmDelete.Hide(); // Ascunderea meniului de confirmare

}

Schimbarea criteriului de sortare

public string sortingBy = "ByName"; // Variabila globală utilizată la sortare

private void ChangeSortingType(String typeOfSort) // Funcția de sortare

{

sortingBy = typeOfSort; /* Se asignează variabilei globale sortingBy șirul de caractere typeOfSort, primit ca parametru */

// Sortare alfabetica

if (sortingBy == "Alphabetical") /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „Alphabetical”, sortează intrările alfabetic și afișează-le */

using (var db = new SQLite.SQLiteConnection(dbpath)) /* Folosind variabila db ca interfață, se conectează la locația bazei de date dbpath2. */

{

var SortByAttribute = db.Table<Movie>().OrderBy(Movie => Movie.MovieTitle).ToList(); /* Declarația unei variabile SortByAttribute ce primește tabelul TvShow ordonat în funcție de titlu */

Movies.ItemsSource = SortByAttribute;

}

// Sortare invers alfabetica

if (sortingBy == "RevAlphabetical") /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „RevAlphabetical”, sortează intrările invers alfabetic și afișează-le */

using (var db = new SQLite.SQLiteConnection(dbpath))

{

var SortByAttribute = db.Table<Movie>().OrderByDescending(Movie => Movie.MovieTitle).ToList();

Movies.ItemsSource = SortByAttribute;

}

// Sortare alfabetic dupa notificare

if (sortingBy == "ByNotification")

using (var db = new SQLite.SQLiteConnection(dbpath))

{

var SortByAttribute = db.Table< Movie >().OrderBy(Movie => Movie.Notification).ToList(); /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „ByNotification”, sortează intrările alfabetic după notificare și afișează-le */

Movies.ItemsSource = SortByAttribute;

}

// Sortare invers alfabetic dupa notificare

if (sortingBy == "RevByNotification")

using (var db = new SQLite.SQLiteConnection(dbpath))

{

var SortByAttribute = db.Table< Movie >().OrderByDescending(Movie => Movie.Notification).ToList(); /* Dacă șirul de caractere primit de către funcția ChangeSortingType este „RevByNotification”, sortează intrările invers alfabetic după notificare și afișează-le */

Movies.ItemsSource = SortByAttribute;

}

// Sortare in ordinea introducerii in baza de date

if (sortingBy == "ByDate")

{

using (var db = new SQLite.SQLiteConnection(dbpath))

Movies.ItemsSource = db.Table<Movie>();/* Dacă șirul de caractere primit de către funcția ChangeSortingType este „ByDate”, afișează intrările în ordinea în care au fost introduce în baza de date */

}

}

Sortarea din meniul flyout

private void Alphabetic_Sort(object sender, TappedRoutedEventArgs e) /* Butonul de sortare alfabetică */

{

sortingBy = "Alphabetical"; /* Variabila globală sortingBy primește valoarea „Alphabetical” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void ReversedAlphabeticSort(object sender, TappedRoutedEventArgs e) /* Butonul de sortare invers alfabetică */

{

sortingBy = "RevAlphabetical"; /* Variabila globală sortingBy primește valoarea „RevAlphabetical” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void WithNotificationFirst(object sender, TappedRoutedEventArgs e) /* Butonul de sortare alfabetică după notificare */

{

sortingBy = "ByNotification"; /* Variabila globală sortingBy primește valoarea „ByNotification” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void NoNotificationFirst(object sender, TappedRoutedEventArgs e) /* Butonul de sortare invers alfabetică după notificare */

{

sortingBy = "RevByNotification"; /* Variabila globală sortingBy primește valoarea „RevByNotification” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

private void OrderedByDate(object sender, TappedRoutedEventArgs e) /* Butonul de sortare după data de intrare */

{

sortingBy = "ByDate"; /* Variabila globală sortingBy primește valoarea „ByDate” */

ChangeSortingType(sortingBy); /* Chemarea funcției ChangeSortingType cu șirul de caractere din sortingBy */

SortByFlyout.Hide(); /* Închiderea meniului flyout apelat programmatic cu x:Name=”SortByFlyout” */

}

Pagina de ștergere a filmelor

Pentru a trece peste limitările elementului xaml ListView, care permite doar afișarea datelor fără posibilitatea de a interacționa cu acestea, este nevoie ca implementarea funcției de ștergere să fie separată și bazată pe datele introduse de către utilizator. Mai jos demonstrez implementarea paginii de ștergere și a funcției de căutare și ștergere a rândului din baza de date ce conține textul introdus de către utilizator în câmpul de titlu.

Interfața

Pagina „Șterge” are ca sursă fișierul DeleteMovie și conține un singur câmp de căutare. Dacă utilizatorul atinge cutia de text, atunci se va deschide tastatura și i se va permite să introducă numele filmului pe care dorește să îl șteargă din baza de date.

Câmpul de căutare

Câmpul de căutare este declarat ca TextBox.

<TextBox Header="Caută" PlaceholderText= "Nume film" x:Name="SearchBoxTerm" />

Atributul Header plasează textul primit ca titlu pentru a indica utilizatorului că acesta este un câmp de căutare, PlaceholderText indică obiectul căutat, în cazul nostru este numele filmului și conținutul textbox-ului se poate citi programatic cu ajutorul termenului SearchBoxTerm.

Butoanele din AppBar

În AppBar am adăugat un buton de ștergere a filmului, un buton de anulare, și un buton ce deschide pagina cu informații despre aplicație. În rândurile de mai jos am descris comenzile utilizate la crearea acestor elemente.

<Page.BottomAppBar>

<!– Declarația bării de jos a paginii –>

<CommandBar Background="{ThemeResource PhoneAccentBrush}" >

<!– Crearea bării de comandă și selectarea automată a culorii bării de jos în funcție de culoarea de accent a telefonului –>

<CommandBar.SecondaryCommands>

<!– Containerul pentru comenzile secundare –>

<AppBarButton x:Name="About" x:Uid="About" Label="despre" Click="About_Click" />

<!– Butonul ce deschide pagina AboutPage –>

</CommandBar.SecondaryCommands>

<!– Încheierea tag-urilor containerului de comenzi secundare –>

<CommandBar.PrimaryCommands>

<!– Containerul pentru comenzi principale –>

<AppBarButton Label="Șterge" Click="Delete_Click" Icon="Delete" />

<!– Butonul de confirmare a ștergerii filmului –>

<AppBarButton Label="Anulează" Icon="Cancel" Click="Cancel_Action" />

<!– Buton de anulare, ce se întoarce la ecranul precedent –>

</CommandBar.PrimaryCommands>

<!– Încheierea tag-urilor containerului de comenzi principale –>

</CommandBar>

<!– Închierea tagurilor de commandbar –>

</Page.BottomAppBar>

<!– Închiderea tag-urilor de bară de comenzi –>

Funcționalitate

Butonul „Șterge”

private async void Delete_Click(object sender, RoutedEventArgs e) /* Declararea funcției de ștergere este declarată asincron pentru a aștepta mesajul de avertizare pentru utilizator. */

{

string searchboxTerm = SearchBoxTerm.Text; /* Preia șirul de caractere din câmpul de căutare ca string */

if(searchboxTerm.Length < 1) /* Dacă dimensiunea termenului de căutare este mai mica decât 1 – adică nu a introdus niciun cuvânt */

{

MessageDialog msgbox = new MessageDialog("Câmpul de text nu poate fi gol."); /* Variabila msgbox de tip MessageDialog „Câmpul de text nu poate fi gol.” */

await msgbox.ShowAsync(); /* Așteaptă verificarea funcției if, iar dacă este adevărat se afișează mesajul */

}

else

{

var dbpath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "movies.db");

/* Se atribuie adresa bazei de date variabilei dbpath */

using (var db = new SQLite.SQLiteConnection(dbpath)) /* Utilizând variabila db ca interfață pentru dbpath */

db2.RunInTransaction(() => /* efectuează tranzacția */

{

d2.Delete<Movie>(searchboxTerm); /* Șterge serialul TV din listă care conține termenul căutat de utilziator */

Frame.Navigate(typeof(MovieLibrary)); /* Navighează la lista cu filme. */

});

}

}

Butonul „Anulează”

private void Cancel_Action(object sentder, RoutedEventArgs e)

{

Frame.Navigate(typeof(TvShowLibrary)); /* La anularea acțiunii de ștergere se va naviga la lista cu seriale TV. */

}

Butonul „Despre”

private void About_Click(object sender, RoutedEventArgs e)

{

Frame.Navigate(typeof(AboutPage)); /* La atingerea butonului se va naviga la pagina AboutPage; aceasta conține informații despre aplicație. */

}

Concluzii

Anexe

Similar Posts